1 /*****************************************************************************
2 * update.m: MacOS X Check-For-Update window
3 *****************************************************************************
4 * Copyright (C) 2005 the VideoLAN team
7 * Authors: Felix K
\9fhne <fkuehne@users.sf.net>
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.
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.
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 *****************************************************************************/
25 /*****************************************************************************
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 *****************************************************************************/
33 /*****************************************************************************
35 *****************************************************************************/
43 #import "vlc_stream.h"
46 #define UPDATE_VLC_OS "macosx"
49 #define UPDATE_VLC_ARCH "i386"
51 #define UPDATE_VLC_ARCH "ppc"
54 #define UPDATE_VLC_STATUS_URL "http://update.videolan.org/vlc/status"
55 #define UPDATE_VLC_MIRRORS_URL "http://update.videolan.org/mirrors"
57 #define UPDATE_VLC_DOWNLOAD_BUFFER_SIZE 2048
59 /*****************************************************************************
60 * VLCExtended implementation
61 *****************************************************************************/
63 @implementation VLCUpdate
65 static VLCUpdate *_o_sharedInstance = nil;
67 + (VLCUpdate *)sharedInstance
69 return _o_sharedInstance ? _o_sharedInstance : [[self alloc] init];
74 if (_o_sharedInstance) {
77 _o_sharedInstance = [super init];
80 return _o_sharedInstance;
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: @""];
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...")];
113 - (void)showUpdateWindow
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];
120 /* alloc some dictionaries first */
121 o_mirrors = [[NSMutableArray alloc] init];
122 o_files = [[NSMutableDictionary alloc] init];
124 [o_bar_checking startAnimation:nil];
126 [o_bar_checking stopAnimation:nil];
129 - (IBAction)cancel:(id)sender
131 /* cancel the download and close the sheet */
134 - (IBAction)download:(id)sender
136 /* open the sheet and start the download */
139 - (IBAction)okay:(id)sender
141 /* just close the window */
142 [o_update_window close];
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. */
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;
159 xml_reader_t *p_xml_reader = NULL;
163 intf_thread_t * p_intf = VLCIntf;
165 if( UPDATE_VLC_ARCH == "i386" )
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
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."));
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];
188 //struct update_mirror_t tmp_mirror;
190 p_xml = xml_Create( p_intf );
193 msg_Err( p_intf, "Failed to open XML parser" );
194 // FIXME: display error message in dialog
198 p_stream = stream_UrlNew( p_intf, UPDATE_VLC_STATUS_URL );
201 msg_Err( p_intf, "Failed to open %s for reading",
202 UPDATE_VLC_STATUS_URL );
203 // FIXME: display error message in dialog
207 p_xml_reader = xml_ReaderCreate( p_xml, p_stream );
211 msg_Err( p_intf, "Failed to open %s for parsing",
212 UPDATE_VLC_STATUS_URL );
213 // FIXME: display error message in dialog
218 while( xml_ReaderRead( p_xml_reader ) == 1 )
220 switch( xml_ReaderNodeType( p_xml_reader ) )
224 // TODO: print message
227 case XML_READER_STARTELEM:
228 psz_eltname = xml_ReaderName( p_xml_reader );
231 // TODO: print message
234 msg_Dbg( p_intf, "element name: %s", psz_eltname );
235 while( xml_ReaderNextAttr( p_xml_reader ) == VLC_SUCCESS )
237 psz_name = xml_ReaderName( p_xml_reader );
238 psz_value = xml_ReaderValue( p_xml_reader );
239 if( !psz_name || !psz_value )
241 // TODO: print message
245 msg_Dbg( p_intf, " attribute %s = %s",
246 psz_name, psz_value );
248 if( !strcmp( psz_name, "name" )
249 && ( !strcmp( psz_value, "macosx" )
250 || !strcmp( psz_value, "*" ) )
251 && !strcmp( psz_eltname, "os" ) )
255 if( b_os && !strcmp( psz_name, "name" )
256 && ( !strcmp( psz_value, UPDATE_VLC_ARCH )
257 || !strcmp( psz_value, "*" ) )
258 && !strcmp( psz_eltname, "arch" ) )
265 if( strcmp( psz_eltname, "version" ) == 0 )
267 [temp_version setObject: [NSString \
268 stringWithUTF8String: psz_value] forKey: \
269 [NSString stringWithUTF8String: psz_name]];
271 if( !strcmp( psz_eltname, "file" ) )
273 [temp_file setObject: [NSString \
274 stringWithUTF8String: psz_value] forKey: \
275 [NSString stringWithUTF8String: psz_name]];
281 if( ( b_os && b_arch && strcmp( psz_eltname, "arch" ) ) )
283 /*if( !strcmp( psz_eltname, "version" ) )
285 it = m_versions.begin();
286 while( it != m_versions.end() )
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 )
298 if( it == m_versions.end() )
300 m_versions.push_back( tmp_version );
301 it = m_versions.begin();
302 while( it != m_versions.end() )
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 )
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( "" );
321 if( !strcmp( psz_eltname, "file" ) )
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( "" );
331 if(! [temp_version objectForKey: @"extra"] == @"0")
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"]]];
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"]]];
354 case XML_READER_ENDELEM:
355 psz_eltname = xml_ReaderName( p_xml_reader );
358 // TODO: print message
361 msg_Dbg( p_intf, "element end: %s", psz_eltname );
362 if( !strcmp( psz_eltname, "os" ) )
364 if( !strcmp( psz_eltname, "arch" ) )
367 if( !strcmp( psz_eltname, "file") )
369 if( [temp_file objectForKey: @"type"] == @"info" )
371 /* this is the announce file, store it correctly */
372 [o_files setObject: temp_file forKey: @"announce"];
374 else if( [temp_file objectForKey: @"type"] == @"binary" )
376 /* that's our binary */
377 [o_files setObject: temp_file forKey: @"binary"];
379 else if( [temp_file objectForKey: @"type"] == @"source" )
381 /* that's the source. not needed atm, but store it
382 * anyway to make possible enhancement of this dialogue
384 [o_files setObject: temp_file forKey: @"source"];
387 /* clean the temp-dict */
388 [temp_file removeAllObjects];
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 );
404 if( p_xml_reader && p_xml ) xml_ReaderDelete( p_xml, p_xml_reader );
405 if( p_stream ) stream_Delete( p_stream );
407 p_stream = stream_UrlNew( p_intf, UPDATE_VLC_MIRRORS_URL );
410 msg_Err( p_intf, "Failed to open %s for reading",
411 UPDATE_VLC_MIRRORS_URL );
412 // FIXME: display error message in dialog
416 p_xml_reader = xml_ReaderCreate( p_xml, p_stream );
420 msg_Err( p_intf, "Failed to open %s for parsing",
421 UPDATE_VLC_MIRRORS_URL );
422 // FIXME: display error message in dialog
427 while( xml_ReaderRead( p_xml_reader ) == 1 )
429 switch( xml_ReaderNodeType( p_xml_reader ) )
433 // TODO: print message
436 case XML_READER_STARTELEM:
437 psz_eltname = xml_ReaderName( p_xml_reader );
440 // TODO: print message
443 msg_Dbg( p_intf, "element name: %s", psz_eltname );
444 while( xml_ReaderNextAttr( p_xml_reader ) == VLC_SUCCESS )
446 psz_name = xml_ReaderName( p_xml_reader );
447 psz_value = xml_ReaderValue( p_xml_reader );
448 if( !psz_name || !psz_value )
450 // TODO: print message
454 msg_Dbg( p_intf, " attribute %s = %s",
455 psz_name, psz_value );
457 if( !strcmp( psz_eltname, "mirror" ) )
459 [temp_mirror setObject: [NSString stringWithUTF8String: psz_name] forKey: [NSString stringWithUTF8String: psz_value]];
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 );*/
466 if( !strcmp( psz_eltname, "url" ) )
468 [temp_mirror setObject: [NSString stringWithUTF8String: psz_name] forKey: [NSString stringWithUTF8String: psz_value]];
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 );*/
479 /*if( !strcmp( psz_eltname, "url" ) )
481 m_mirrors.push_back( tmp_mirror );
482 tmp_mirror.type = wxT( "" );
483 tmp_mirror.base_url = wxT( "" );
488 case XML_READER_ENDELEM:
489 psz_eltname = xml_ReaderName( p_xml_reader );
492 // TODO: print message
495 msg_Dbg( p_intf, "element end: %s", psz_eltname );
496 /*if( !strcmp( psz_eltname, "mirror" ) )
498 tmp_mirror.name = wxT( "" );
499 tmp_mirror.location = wxT( "" );
502 /* store our mirror correctly */
503 [o_mirrors addObject: temp_mirror];
504 [temp_mirror removeAllObjects];
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 );
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 );