]> git.sesse.net Git - vlc/blob - modules/gui/macosx/update.m
Implemented the retrieval of the versions, files and mirrors. Both the size and the...
[vlc] / modules / gui / macosx / update.m
1 /*****************************************************************************
2  * update.m: MacOS X Check-For-Update window
3  *****************************************************************************
4  * Copyright (C) 2005 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Felix K\9fhne <fkuehne@users.sf.net>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24
25 /*****************************************************************************
26  * Note: 
27  * the code used to bind with VLC's core and the download of files is heavily 
28  * based upon ../wxwidgets/updatevlc.cpp, written by Antoine Cellerier. 
29  * (he is a member of the VideoLAN team) 
30  *****************************************************************************/
31
32
33 /*****************************************************************************
34  * Preamble
35  *****************************************************************************/
36 #import "update.h"
37 #import "intf.h"
38
39 #import <vlc/vlc.h>
40 #import <vlc/intf.h>
41
42 #import "vlc_block.h"
43 #import "vlc_stream.h"
44 #import "vlc_xml.h"
45
46 #define UPDATE_VLC_OS "macosx"
47
48 #ifdef i386
49 #define UPDATE_VLC_ARCH "i386"
50 #else
51 #define UPDATE_VLC_ARCH "ppc"
52 #endif
53
54 #define UPDATE_VLC_STATUS_URL "http://update.videolan.org/vlc/status"
55 #define UPDATE_VLC_MIRRORS_URL "http://update.videolan.org/mirrors"
56
57 #define UPDATE_VLC_DOWNLOAD_BUFFER_SIZE 2048
58
59 /*****************************************************************************
60  * VLCExtended implementation
61  *****************************************************************************/
62
63 @implementation VLCUpdate
64
65 static VLCUpdate *_o_sharedInstance = nil;
66
67 + (VLCUpdate *)sharedInstance
68 {
69     return _o_sharedInstance ? _o_sharedInstance : [[self alloc] init];
70 }
71
72 - (id)init
73 {
74     if (_o_sharedInstance) {
75         [self dealloc];
76     } else {
77         _o_sharedInstance = [super init];
78     }
79
80     return _o_sharedInstance;
81 }
82
83 - (void)awakeFromNib
84 {
85     /* clean the interface */
86     [o_fld_userVersion setStringValue: [[[NSBundle mainBundle] infoDictionary] \
87         objectForKey:@"CFBundleVersion"]];
88     [o_fld_releaseNote setString: @""];
89     [o_fld_size setStringValue: @""];
90     [o_fld_currentVersion setStringValue: @""];
91     
92     [self initStrings];
93 }
94
95 - (void)initStrings
96 {
97     /* translate strings to the user's language */
98     [o_update_window setTitle: _NS("Check for update")];
99     [o_btn_cancel setTitle: _NS("Cancel")];
100     [o_btn_DownloadNow setTitle: _NS("Download now")];
101     [o_btn_okay setTitle: _NS("OK")];
102     [o_lbl_currentVersion setStringValue: [_NS("Current version") \
103         stringByAppendingString: @":"]];
104     [o_lbl_size setStringValue: [_NS("Size") \
105         stringByAppendingString: @":"]];
106     [o_lbl_userVersion setStringValue: [_NS("Your version") \
107         stringByAppendingString: @":"]];
108     [o_lbl_mirror setStringValue: [_NS("Mirror") \
109         stringByAppendingString: @":"]];
110     [o_lbl_checkForUpdate setStringValue: _NS("Checking for update...")];
111 }
112
113 - (void)showUpdateWindow
114 {
115     /* show the window and check for a potential update */
116     [o_update_window center];
117     [o_update_window displayIfNeeded];
118     [o_update_window makeKeyAndOrderFront:nil];
119     
120     /* alloc some dictionaries first */
121     o_mirrors = [[NSMutableArray alloc] init];
122     o_files = [[NSMutableDictionary alloc] init];
123     
124     [o_bar_checking startAnimation:nil];
125     [self getData];
126     [o_bar_checking stopAnimation:nil];
127 }
128
129 - (IBAction)cancel:(id)sender
130 {
131     /* cancel the download and close the sheet */
132 }
133
134 - (IBAction)download:(id)sender
135 {
136     /* open the sheet and start the download */
137 }
138
139 - (IBAction)okay:(id)sender
140 {
141     /* just close the window */
142     [o_update_window close];
143 }
144
145
146
147 - (void)getData
148 {
149     /* This function gets all the info from the xml files hosted on
150     http://update.videolan.org/ and stores it in appropriate lists.
151     It was taken from the WX-interface and ported from C++ to Obj-C. */
152
153     stream_t *p_stream = NULL;
154     char *psz_eltname = NULL;
155     char *psz_name = NULL;
156     char *psz_value = NULL;
157     char *psz_eltvalue = NULL;
158     xml_t *p_xml = NULL;
159     xml_reader_t *p_xml_reader = NULL;
160     bool b_os = false;
161     bool b_arch = false;
162     
163     intf_thread_t * p_intf = VLCIntf;
164
165     if( UPDATE_VLC_ARCH == "i386" )
166     {
167         /* since we don't provide any binaries for MacTel atm, doing the
168          * update-check is not necessary (this would fail in fact). That's why 
169          * we just provide a sheet telling the user about that and skip 
170          * the rest. */
171         /* FIXME: remove me, if a i386-binary is available */
172         NSBeginInformationalAlertSheet(_NS("Unsupported architecture"), \
173                     _NS("OK"), @"", @"", o_update_window, nil, nil, nil, nil, \
174                     _NS("Binary builds are only available for Mac OS X on " \
175                     "the PowerPC-platform. Official builds for Intel-Macs " \
176                     "are not available at this time. \n\n If you want to " \
177                     "help us here, feel free to contact us."));
178         return;
179     }
180     
181     NSMutableDictionary * temp_version;
182     temp_version = [[NSMutableDictionary alloc] init];
183     NSMutableDictionary * temp_file;
184     temp_file = [[NSMutableDictionary alloc] init];
185     NSMutableDictionary * temp_mirror;
186     temp_mirror = [[NSMutableDictionary alloc] init];
187
188     //struct update_mirror_t tmp_mirror;
189
190     p_xml = xml_Create( p_intf );
191     if( !p_xml )
192     {
193         msg_Err( p_intf, "Failed to open XML parser" );
194         // FIXME: display error message in dialog
195         return;
196     }
197
198     p_stream = stream_UrlNew( p_intf, UPDATE_VLC_STATUS_URL );
199     if( !p_stream )
200     {
201         msg_Err( p_intf, "Failed to open %s for reading",
202                  UPDATE_VLC_STATUS_URL );
203         // FIXME: display error message in dialog
204         return;
205     }
206
207     p_xml_reader = xml_ReaderCreate( p_xml, p_stream );
208
209     if( !p_xml_reader )
210     {
211         msg_Err( p_intf, "Failed to open %s for parsing",
212                  UPDATE_VLC_STATUS_URL );
213         // FIXME: display error message in dialog
214         return;
215     }
216
217     /* build tree */
218     while( xml_ReaderRead( p_xml_reader ) == 1 )
219     {
220         switch( xml_ReaderNodeType( p_xml_reader ) )
221         {
222             // Error
223             case -1:
224                 // TODO: print message
225                 return;
226
227             case XML_READER_STARTELEM:
228                 psz_eltname = xml_ReaderName( p_xml_reader );
229                 if( !psz_eltname )
230                 {
231                     // TODO: print message
232                     return;
233                 }
234                 msg_Dbg( p_intf, "element name: %s", psz_eltname );
235                 while( xml_ReaderNextAttr( p_xml_reader ) == VLC_SUCCESS )
236                 {
237                     psz_name = xml_ReaderName( p_xml_reader );
238                     psz_value = xml_ReaderValue( p_xml_reader );
239                     if( !psz_name || !psz_value )
240                     {
241                         // TODO: print message
242                         free( psz_eltname );
243                         return;
244                     }
245                     msg_Dbg( p_intf, "  attribute %s = %s",
246                              psz_name, psz_value );
247                     
248                     if( !strcmp( psz_name, "name" )
249                         && ( !strcmp( psz_value, "macosx" ) 
250                             || !strcmp( psz_value, "*" ) )
251                         && !strcmp( psz_eltname, "os" ) )
252                     {
253                         b_os = true;
254                     }
255                     if( b_os && !strcmp( psz_name, "name" )
256                         && ( !strcmp( psz_value, UPDATE_VLC_ARCH ) 
257                             || !strcmp( psz_value, "*" ) )
258                         && !strcmp( psz_eltname, "arch" ) )
259                     {
260                         b_arch = true;
261                     }
262                     
263                     if( b_os && b_arch )
264                     {
265                         if( strcmp( psz_eltname, "version" ) == 0 )
266                         {
267                             [temp_version setObject: [NSString \
268                                 stringWithUTF8String: psz_value] forKey: \
269                                 [NSString stringWithUTF8String: psz_name]];
270                         }
271                         if( !strcmp( psz_eltname, "file" ) )
272                         {
273                             [temp_file setObject: [NSString \
274                                 stringWithUTF8String: psz_value] forKey: \
275                                 [NSString stringWithUTF8String: psz_name]];
276                         }
277                     }
278                     free( psz_name );
279                     free( psz_value );
280                 }
281                 if( ( b_os && b_arch && strcmp( psz_eltname, "arch" ) ) )
282                 {
283                     /*if( !strcmp( psz_eltname, "version" ) )
284                     {
285                         it = m_versions.begin();
286                         while( it != m_versions.end() )
287                         {
288                             if( it->type == tmp_version.type
289                                 && it->major == tmp_version.major
290                                 && it->minor == tmp_version.minor
291                                 && it->revision == tmp_version.revision
292                                 && it->extra == tmp_version.extra )
293                             {
294                                 break;
295                             }
296                             it++;
297                         }
298                         if( it == m_versions.end() )
299                         {
300                             m_versions.push_back( tmp_version );
301                             it = m_versions.begin();
302                             while( it != m_versions.end() )
303                             {
304                                 if( it->type == tmp_version.type
305                                     && it->major == tmp_version.major
306                                     && it->minor == tmp_version.minor
307                                     && it->revision == tmp_version.revision
308                                     && it->extra == tmp_version.extra )
309                                 {
310                                     break;
311                                 }
312                                 it++;
313                             }
314                         }
315                         tmp_version.type = wxT( "" );
316                         tmp_version.major = wxT( "" );
317                         tmp_version.minor = wxT( "" );
318                         tmp_version.revision = wxT( "" );
319                         tmp_version.extra = wxT( "" );
320                     }
321                     if( !strcmp( psz_eltname, "file" ) )
322                     {
323                         it->m_files.push_back( tmp_file );
324                         tmp_file.type = wxT( "" );
325                         tmp_file.md5 = wxT( "" );
326                         tmp_file.size = wxT( "" );
327                         tmp_file.url = wxT( "" );
328                         tmp_file.description = wxT( "" );
329                     }*/
330                      
331                     if(! [temp_version objectForKey: @"extra"] == @"0")
332                     {
333                         [o_fld_currentVersion setStringValue: [NSString \
334                             stringWithFormat: @"%@.%@.%@-%@ (%@)", \
335                             [temp_version objectForKey: @"major"], \
336                             [temp_version objectForKey: @"minor"], \
337                             [temp_version objectForKey: @"revision"], \
338                             [temp_version objectForKey: @"extra"], \
339                             [temp_version objectForKey: @"type"]]];
340                     }
341                     else
342                     {
343                         [o_fld_currentVersion setStringValue: [NSString \
344                             stringWithFormat: @"%@.%@.%@ (%@)", \
345                             [temp_version objectForKey: @"major"], \
346                             [temp_version objectForKey: @"minor"], \
347                             [temp_version objectForKey: @"revision"], \
348                             [temp_version objectForKey: @"type"]]];
349                     }
350                 }
351                 free( psz_eltname );
352                 break;
353
354             case XML_READER_ENDELEM:
355                 psz_eltname = xml_ReaderName( p_xml_reader );
356                 if( !psz_eltname )
357                 {
358                     // TODO: print message
359                     return;
360                 }
361                 msg_Dbg( p_intf, "element end: %s", psz_eltname );
362                 if( !strcmp( psz_eltname, "os" ) )
363                     b_os = false;
364                 if( !strcmp( psz_eltname, "arch" ) )
365                     b_arch = false;
366                     
367                 if( !strcmp( psz_eltname, "file") )
368                 {
369                     if( [temp_file objectForKey: @"type"] == @"info" )
370                     {
371                         /* this is the announce file, store it correctly */
372                         [o_files setObject: temp_file forKey: @"announce"];
373                     }
374                     else if( [temp_file objectForKey: @"type"] == @"binary" )
375                     {
376                         /* that's our binary */
377                         [o_files setObject: temp_file forKey: @"binary"];
378                     }
379                     else if( [temp_file objectForKey: @"type"] == @"source" )
380                     {
381                         /* that's the source. not needed atm, but store it 
382                          * anyway to make possible enhancement of this dialogue
383                          * a bit easier */
384                         [o_files setObject: temp_file forKey: @"source"];
385                     }
386                     
387                     /* clean the temp-dict */
388                     [temp_file removeAllObjects];
389                 }
390                 free( psz_eltname );
391                 break;
392
393             case XML_READER_TEXT:
394                 /* you can check the content of a file here (e.g. \
395                  * "Installer-less binaries", "Disk-Image", etc.). That's not
396                  * needed on OSX atm, but print debug-info anyway. */
397                 psz_eltvalue = xml_ReaderValue( p_xml_reader );
398                 msg_Dbg( p_intf, "  text: %s", psz_eltvalue );
399                 free( psz_eltvalue );
400                 break;
401         }
402     }
403
404     if( p_xml_reader && p_xml ) xml_ReaderDelete( p_xml, p_xml_reader );
405     if( p_stream ) stream_Delete( p_stream );
406
407     p_stream = stream_UrlNew( p_intf, UPDATE_VLC_MIRRORS_URL );
408     if( !p_stream )
409     {
410         msg_Err( p_intf, "Failed to open %s for reading",
411                  UPDATE_VLC_MIRRORS_URL );
412         // FIXME: display error message in dialog
413         return;
414     }
415
416     p_xml_reader = xml_ReaderCreate( p_xml, p_stream );
417
418     if( !p_xml_reader )
419     {
420         msg_Err( p_intf, "Failed to open %s for parsing",
421                  UPDATE_VLC_MIRRORS_URL );
422         // FIXME: display error message in dialog
423         return;
424     }
425     
426     /* build list */
427     while( xml_ReaderRead( p_xml_reader ) == 1 )
428     {
429         switch( xml_ReaderNodeType( p_xml_reader ) )
430         {
431             // Error
432             case -1:
433                 // TODO: print message
434                 return;
435
436             case XML_READER_STARTELEM:
437                 psz_eltname = xml_ReaderName( p_xml_reader );
438                 if( !psz_eltname )
439                 {
440                     // TODO: print message
441                     return;
442                 }
443                 msg_Dbg( p_intf, "element name: %s", psz_eltname );
444                 while( xml_ReaderNextAttr( p_xml_reader ) == VLC_SUCCESS )
445                 {
446                     psz_name = xml_ReaderName( p_xml_reader );
447                     psz_value = xml_ReaderValue( p_xml_reader );
448                     if( !psz_name || !psz_value )
449                     {
450                         // TODO: print message
451                         free( psz_eltname );
452                         return;
453                     }
454                     msg_Dbg( p_intf, "  attribute %s = %s",
455                              psz_name, psz_value );
456                     
457                     if( !strcmp( psz_eltname, "mirror" ) )
458                     {
459                         [temp_mirror setObject: [NSString stringWithUTF8String: psz_name] forKey: [NSString stringWithUTF8String: psz_value]];
460                     
461                         /*if( !strcmp( psz_name, "name" ) )
462                             tmp_mirror.name = wxU( psz_value );
463                         if( !strcmp( psz_name, "location" ) )
464                             tmp_mirror.location = wxU( psz_value );*/
465                     }
466                     if( !strcmp( psz_eltname, "url" ) )
467                     {
468                         [temp_mirror setObject: [NSString stringWithUTF8String: psz_name] forKey: [NSString stringWithUTF8String: psz_value]];
469                         
470                         /*
471                         if( !strcmp( psz_name, "type" ) )
472                             tmp_mirror.type = wxU( psz_value );
473                         if( !strcmp( psz_name, "base" ) )
474                             tmp_mirror.base_url = wxU( psz_value );*/
475                     }
476                     free( psz_name );
477                     free( psz_value );
478                 }
479                 /*if( !strcmp( psz_eltname, "url" ) )
480                 {
481                     m_mirrors.push_back( tmp_mirror );
482                     tmp_mirror.type = wxT( "" );
483                     tmp_mirror.base_url = wxT( "" );
484                 }*/
485                 free( psz_eltname );
486                 break;
487
488             case XML_READER_ENDELEM:
489                 psz_eltname = xml_ReaderName( p_xml_reader );
490                 if( !psz_eltname )
491                 {
492                     // TODO: print message
493                     return;
494                 }
495                 msg_Dbg( p_intf, "element end: %s", psz_eltname );
496                 /*if( !strcmp( psz_eltname, "mirror" ) )
497                 {
498                     tmp_mirror.name = wxT( "" );
499                     tmp_mirror.location = wxT( "" );
500                 }*/
501                 
502                 /* store our mirror correctly */
503                 [o_mirrors addObject: temp_mirror];
504                 [temp_mirror removeAllObjects];
505                 
506                 free( psz_eltname );
507                 break;
508
509             case XML_READER_TEXT:
510                 psz_eltvalue = xml_ReaderValue( p_xml_reader );
511                 msg_Dbg( p_intf, "  text: %s", psz_eltvalue );
512                 free( psz_eltvalue );
513                 break;
514         }
515     }
516
517
518     if( p_xml_reader && p_xml ) xml_ReaderDelete( p_xml, p_xml_reader );
519     if( p_stream ) stream_Delete( p_stream );
520     if( p_xml ) xml_Delete( p_xml );
521 }
522
523 @end