1 /*****************************************************************************
2 * updatevlc.cpp : VLC Update checker
3 *****************************************************************************
4 * Copyright (C) 2000-2004 the VideoLAN team
7 * Authors: Antoine Cellerier <dionoea@videolan.org>
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 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
27 #include "updatevlc.hpp"
28 #include <wx/progdlg.h>
29 #include <wx/treectrl.h>
31 #include "vlc_block.h"
32 #include "vlc_stream.h"
35 /* define UPDATE_VLC_OS and UPDATE_VLC_ARCH */
36 /* todo : move this somewhere else (isn't wx specific) */
39 # define UPDATE_VLC_OS "windows"
40 # define UPDATE_VLC_ARCH "i386"
43 # define UPDATE_VLC_OS "macosx"
44 # define UPDATE_VLC_ARCH "ppc"
46 # define UPDATE_VLC_OS "*"
47 # define UPDATE_VLC_ARCH "*"
51 /* arch == "*" and os == "*" concern non OS or arch specific stuff */
53 #define UPDATE_VLC_STATUS_URL "http://update.videolan.org/vlc/status"
54 #define UPDATE_VLC_MIRRORS_URL "http://update.videolan.org/mirrors"
56 #define UPDATE_VLC_DOWNLOAD_BUFFER_SIZE 2048
58 class UpdatesTreeItem : public wxTreeItemData
61 UpdatesTreeItem( wxString _url ):wxTreeItemData()
68 /*****************************************************************************
70 *****************************************************************************/
72 /* IDs for the controls and the menu commands */
78 UpdatesTreeActivate_Event
81 BEGIN_EVENT_TABLE(UpdateVLC, wxFrame)
83 EVT_BUTTON(wxID_OK, UpdateVLC::OnButtonClose)
84 EVT_BUTTON(CheckForUpdate_Event, UpdateVLC::OnCheckForUpdate)
87 EVT_CHOICE(MirrorChoice_Event, UpdateVLC::OnMirrorChoice)
90 EVT_TREE_ITEM_ACTIVATED(UpdatesTreeActivate_Event, UpdateVLC::OnUpdatesTreeActivate)
92 /* Hide the window when the user closes the window */
93 EVT_CLOSE(UpdateVLC::OnClose)
97 /*****************************************************************************
99 *****************************************************************************/
100 UpdateVLC::UpdateVLC( intf_thread_t *_p_intf, wxWindow *p_parent ):
101 wxFrame( p_parent, -1, wxU(_("Check for updates ...")), wxDefaultPosition,
102 wxDefaultSize, wxDEFAULT_FRAME_STYLE )
104 /* Initializations */
106 release_type = wxT( "testing" );
107 SetIcon( *p_intf->p_sys->p_icon );
108 SetAutoLayout( TRUE );
110 /* Create a panel to put everything in */
111 wxPanel *panel = new wxPanel( this, -1 );
112 panel->SetAutoLayout( TRUE );
115 new wxTreeCtrl( panel, UpdatesTreeActivate_Event, wxDefaultPosition,
117 wxTR_HAS_BUTTONS | wxTR_HIDE_ROOT | wxSUNKEN_BORDER );
118 updates_tree->AddRoot( wxU(_("root" )), -1, -1, NULL );
120 /* Place everything in sizers */
121 wxBoxSizer *main_sizer = new wxBoxSizer( wxVERTICAL );
122 wxBoxSizer *panel_sizer = new wxBoxSizer( wxVERTICAL );
123 wxBoxSizer *subpanel_sizer = new wxBoxSizer( wxHORIZONTAL );
124 panel_sizer->Add( updates_tree, 1, wxGROW | wxALL, 5 );
125 wxButton *update_button =
126 new wxButton( panel, CheckForUpdate_Event,
127 wxU(_("Check for updates now !")) );
128 subpanel_sizer->Add( update_button, 0, wxALL, 5 );
129 //wxChoice constructor prototype changes with 2.5
130 #if wxCHECK_VERSION(2,5,0)
131 wxArrayString *choices_array = new wxArrayString();
132 choices_array->Add( wxT("") );
134 new wxChoice( panel, MirrorChoice_Event, wxDefaultPosition,
135 wxSize( 200, -1 ), *choices_array );
137 wxString choices_array = wxT("");
139 new wxChoice( panel, -1, wxDefaultPosition,
140 wxSize( 200, -1 ),1, *choices_array );
142 subpanel_sizer->Add( mirrors_choice, 0, wxALL, 5 );
143 subpanel_sizer->Layout();
144 panel_sizer->Add( subpanel_sizer, 0, wxALL , 0 );
145 panel_sizer->Layout();
146 panel->SetSizerAndFit( panel_sizer );
147 main_sizer->Add( panel, 1, wxALL | wxGROW, 0 );
148 main_sizer->Layout();
149 SetSizerAndFit( main_sizer );
151 UpdateMirrorsChoice();
156 UpdateVLC::~UpdateVLC()
158 fprintf( stderr, "Fooing\n");
161 /* this function gets all the info from the xml files hosted on
162 http://update.videolan.org/ and stores it in appropriate lists */
163 void UpdateVLC::GetData()
165 stream_t *p_stream = NULL;
166 char *psz_eltname = NULL;
167 char *psz_name = NULL;
168 char *psz_value = NULL;
169 char *psz_eltvalue = NULL;
171 xml_reader_t *p_xml_reader = NULL;
175 struct update_file_t tmp_file;
176 struct update_version_t tmp_version;
177 std::list<update_version_t>::iterator it;
178 std::list<update_file_t>::iterator it_files;
180 struct update_mirror_t tmp_mirror;
182 p_xml = xml_Create( p_intf );
185 msg_Err( p_intf, "Failed to open XML parser" );
186 // FIXME : display error message in dialog
190 p_stream = stream_UrlNew( p_intf, UPDATE_VLC_STATUS_URL );
193 msg_Err( p_intf, "Failed to open %s for reading",
194 UPDATE_VLC_STATUS_URL );
195 // FIXME : display error message in dialog
199 p_xml_reader = xml_ReaderCreate( p_xml, p_stream );
203 msg_Err( p_intf, "Failed to open %s for parsing",
204 UPDATE_VLC_STATUS_URL );
205 // FIXME : display error message in dialog
213 while( xml_ReaderRead( p_xml_reader ) == 1 )
215 switch( xml_ReaderNodeType( p_xml_reader ) )
219 // TODO : print message
222 case XML_READER_STARTELEM:
223 psz_eltname = xml_ReaderName( p_xml_reader );
226 // TODO : print message
229 msg_Dbg( p_intf, "element name : %s", psz_eltname );
230 while( xml_ReaderNextAttr( p_xml_reader ) == VLC_SUCCESS )
232 psz_name = xml_ReaderName( p_xml_reader );
233 psz_value = xml_ReaderValue( p_xml_reader );
234 if( !psz_name || !psz_value )
236 // TODO : print message
240 msg_Dbg( p_intf, " attribute %s = %s",
241 psz_name, psz_value );
244 if( strcmp( psz_eltname, "version" ) == 0 )
246 if( !strcmp( psz_name, "type" ) )
247 tmp_version.type = wxU( psz_value );
248 if( !strcmp( psz_name, "major" ) )
249 tmp_version.major = wxU( psz_value );
250 if( !strcmp( psz_name, "minor" ) )
251 tmp_version.minor = wxU( psz_value );
252 if( !strcmp( psz_name, "revision" ) )
253 tmp_version.revision = wxU( psz_value );
254 if( !strcmp( psz_name, "extra" ) )
255 tmp_version.extra = wxU( psz_value );
257 if( !strcmp( psz_eltname, "file" ) )
259 if( !strcmp( psz_name, "type" ) )
260 tmp_file.type = wxU( psz_value );
261 if( !strcmp( psz_name, "md5" ) )
262 tmp_file.md5 = wxU( psz_value );
263 if( !strcmp( psz_name, "size" ) )
264 tmp_file.size = wxU( psz_value );
265 if( !strcmp( psz_name, "url" ) )
266 tmp_file.url = wxU( psz_value );
269 if( !strcmp( psz_name, "name" )
270 && ( !strcmp( psz_value, UPDATE_VLC_OS )
271 || !strcmp( psz_value, "*" ) )
272 && !strcmp( psz_eltname, "os" ) )
276 if( b_os && !strcmp( psz_name, "name" )
277 && ( !strcmp( psz_value, UPDATE_VLC_ARCH )
278 || !strcmp( psz_value, "*" ) )
279 && !strcmp( psz_eltname, "arch" ) )
286 if( ( b_os && b_arch && strcmp( psz_eltname, "arch" ) ) )
288 if( !strcmp( psz_eltname, "version" ) )
290 it = m_versions.begin();
291 while( it != m_versions.end() )
293 if( it->type == tmp_version.type
294 && it->major == tmp_version.major
295 && it->minor == tmp_version.minor
296 && it->revision == tmp_version.revision
297 && it->extra == tmp_version.extra )
303 if( it == m_versions.end() )
305 m_versions.push_back( tmp_version );
306 it = m_versions.begin();
307 while( it != m_versions.end() )
309 if( it->type == tmp_version.type
310 && it->major == tmp_version.major
311 && it->minor == tmp_version.minor
312 && it->revision == tmp_version.revision
313 && it->extra == tmp_version.extra )
320 tmp_version.type = wxT( "" );
321 tmp_version.major = wxT( "" );
322 tmp_version.minor = wxT( "" );
323 tmp_version.revision = wxT( "" );
324 tmp_version.extra = wxT( "" );
326 if( !strcmp( psz_eltname, "file" ) )
328 it->m_files.push_back( tmp_file );
329 tmp_file.type = wxT( "" );
330 tmp_file.md5 = wxT( "" );
331 tmp_file.size = wxT( "" );
332 tmp_file.url = wxT( "" );
333 tmp_file.description = wxT( "" );
339 case XML_READER_ENDELEM:
340 psz_eltname = xml_ReaderName( p_xml_reader );
343 // TODO : print message
346 msg_Dbg( p_intf, "element end : %s", psz_eltname );
347 if( !strcmp( psz_eltname, "os" ) )
349 if( !strcmp( psz_eltname, "arch" ) )
354 case XML_READER_TEXT:
355 psz_eltvalue = xml_ReaderValue( p_xml_reader );
356 msg_Dbg( p_intf, " text : %s", psz_eltvalue );
357 /* This doesn't look safe ... but it works */
358 if( !m_versions.empty() )
359 if( !it->m_files.empty() )
360 it->m_files.back().description = wxU( psz_eltvalue );
361 free( psz_eltvalue );
366 if( p_xml_reader && p_xml ) xml_ReaderDelete( p_xml, p_xml_reader );
367 if( p_stream ) stream_Delete( p_stream );
369 p_stream = stream_UrlNew( p_intf, UPDATE_VLC_MIRRORS_URL );
372 msg_Err( p_intf, "Failed to open %s for reading",
373 UPDATE_VLC_MIRRORS_URL );
374 // FIXME : display error message in dialog
378 p_xml_reader = xml_ReaderCreate( p_xml, p_stream );
382 msg_Err( p_intf, "Failed to open %s for parsing",
383 UPDATE_VLC_MIRRORS_URL );
384 // FIXME : display error message in dialog
391 while( xml_ReaderRead( p_xml_reader ) == 1 )
393 switch( xml_ReaderNodeType( p_xml_reader ) )
397 // TODO : print message
400 case XML_READER_STARTELEM:
401 psz_eltname = xml_ReaderName( p_xml_reader );
404 // TODO : print message
407 msg_Dbg( p_intf, "element name : %s", psz_eltname );
408 while( xml_ReaderNextAttr( p_xml_reader ) == VLC_SUCCESS )
410 psz_name = xml_ReaderName( p_xml_reader );
411 psz_value = xml_ReaderValue( p_xml_reader );
412 if( !psz_name || !psz_value )
414 // TODO : print message
418 msg_Dbg( p_intf, " attribute %s = %s",
419 psz_name, psz_value );
420 if( !strcmp( psz_eltname, "mirror" ) )
422 if( !strcmp( psz_name, "name" ) )
423 tmp_mirror.name = wxU( psz_value );
424 if( !strcmp( psz_name, "location" ) )
425 tmp_mirror.location = wxU( psz_value );
427 if( !strcmp( psz_eltname, "url" ) )
429 if( !strcmp( psz_name, "type" ) )
430 tmp_mirror.type = wxU( psz_value );
431 if( !strcmp( psz_name, "base" ) )
432 tmp_mirror.base_url = wxU( psz_value );
437 if( !strcmp( psz_eltname, "url" ) )
439 m_mirrors.push_back( tmp_mirror );
440 tmp_mirror.type = wxT( "" );
441 tmp_mirror.base_url = wxT( "" );
446 case XML_READER_ENDELEM:
447 psz_eltname = xml_ReaderName( p_xml_reader );
450 // TODO : print message
453 msg_Dbg( p_intf, "element end : %s", psz_eltname );
454 if( !strcmp( psz_eltname, "mirror" ) )
456 tmp_mirror.name = wxT( "" );
457 tmp_mirror.location = wxT( "" );
462 case XML_READER_TEXT:
463 psz_eltvalue = xml_ReaderValue( p_xml_reader );
464 msg_Dbg( p_intf, " text : %s", psz_eltvalue );
465 free( psz_eltvalue );
471 if( p_xml_reader && p_xml ) xml_ReaderDelete( p_xml, p_xml_reader );
472 if( p_stream ) stream_Delete( p_stream );
473 if( p_xml ) xml_Delete( p_xml );
476 void UpdateVLC::UpdateUpdatesTree()
479 std::list<update_version_t>::iterator it;
480 std::list<update_file_t>::iterator it_files;
481 std::list<update_mirror_t>::iterator it_mirrors;
483 int selection = mirrors_choice->GetSelection();
484 wxString base_url = wxT( "" );
488 it_mirrors = m_mirrors.begin();
489 while( it_mirrors != m_mirrors.end() && selection )
494 if( it_mirrors != m_mirrors.end() ) base_url = it_mirrors->base_url;
498 updates_tree->DeleteAllItems();
501 parent=updates_tree->AddRoot( wxU(_("root" )), -1, -1, NULL );
502 updates_tree->AppendItem( parent,
503 wxT( "Current version : VLC media player "PACKAGE_VERSION_MAJOR"."PACKAGE_VERSION_MINOR"."PACKAGE_VERSION_REVISION"-"PACKAGE_VERSION_EXTRA ),
504 -1, -1, new UpdatesTreeItem( wxT( "" ) ));
505 it = m_versions.begin();
506 while( it != m_versions.end() )
508 if( it->type != release_type )
514 if( release_type != wxT( "stable" ) && it->type == wxT( "stable" ) )
520 if( release_type != wxT( "stable" ) && release_type != wxT( "testing" )
521 && it->type == wxT( "testing" ) )
527 if( release_type != wxT( "stable" ) && release_type != wxT( "testing" )
528 && release_type != wxT( "nightly" ) )
534 if( atoi((const char *)it->major.mb_str()) <
535 atoi(PACKAGE_VERSION_MAJOR)
536 || ( atoi((const char *)it->major.mb_str()) ==
537 atoi(PACKAGE_VERSION_MAJOR)
538 && ( atoi((const char *)it->minor.mb_str()) <
539 atoi(PACKAGE_VERSION_MINOR)
540 || ( atoi((const char *)it->minor.mb_str()) ==
541 atoi(PACKAGE_VERSION_MINOR)
542 && ( atoi((const char *)it->revision.mb_str()) <
543 atoi(PACKAGE_VERSION_REVISION)
544 || ( atoi((const char *)it->revision.mb_str()) ==
545 atoi(PACKAGE_VERSION_REVISION) ) ) ) ) ) )
547 /* version is older or equal tu current version.
548 FIXME : how do we handle the extra version number ? */
552 wxTreeItemId cat = updates_tree->AppendItem( parent,
553 wxT("New Version : VLC media player ")
554 + it->major + wxT(".")
555 + it->minor + wxT(".") + it->revision + wxT("-")
556 + it->extra + wxT(" (") + it->type + wxT(")"),
557 -1, -1, new UpdatesTreeItem( wxT( "" ) ));
558 it_files = it->m_files.begin();
559 while( it_files != it->m_files.end() )
561 wxString url = (it_files->url[0]=='/' ? base_url : wxT( "" ) )
564 updates_tree->AppendItem( cat, it_files->description,
565 -1, -1, new UpdatesTreeItem( url ) );
566 updates_tree->AppendItem( file,
567 wxU(_("type : ")) + it_files->type,
568 -1, -1, new UpdatesTreeItem( url ));
569 updates_tree->AppendItem( file, wxU(_("URL : ")) + url,
570 -1, -1, new UpdatesTreeItem( url ));
571 if( it_files->size != wxT( "" ) )
572 updates_tree->AppendItem( file,
573 wxU(_("file size : ")) + it_files->size,
574 -1, -1, new UpdatesTreeItem( url ));
575 if( it_files->md5 != wxT( "" ) )
576 updates_tree->AppendItem( file,
577 wxU(_("file md5 hash : ")) + it_files->md5,
578 -1, -1, new UpdatesTreeItem( url ));
582 updates_tree->Expand( cat );
583 updates_tree->Expand( parent );
587 void UpdateVLC::UpdateMirrorsChoice()
589 std::list<update_mirror_t>::iterator it_mirrors;
591 mirrors_choice->Clear();
592 mirrors_choice->Append( wxU(_("Choose a mirror")) );
593 it_mirrors = m_mirrors.begin();
594 while( it_mirrors != m_mirrors.end() )
596 mirrors_choice->Append( it_mirrors->name + wxT(" (")
597 + it_mirrors->location + wxT(") [")
598 + it_mirrors->type + wxT("]") );
601 mirrors_choice->SetSelection( 0 );
604 /*void UpdateVLC::UpdateUpdateVLC()
607 UpdateMirrorsChoice();
610 void UpdateVLC::OnButtonClose( wxCommandEvent& event )
616 void UpdateVLC::OnClose( wxCloseEvent& WXUNUSED(event) )
621 void UpdateVLC::OnCheckForUpdate( wxCommandEvent& event )
624 UpdateMirrorsChoice();
628 void UpdateVLC::OnMirrorChoice( wxCommandEvent& event )
633 void UpdateVLC::OnUpdatesTreeActivate( wxTreeEvent& event )
636 ((UpdatesTreeItem *)(updates_tree->GetItemData(event.GetItem())))->url;
637 if( url != wxT( "" ) ? url[0] != '/' : false )
639 wxFileDialog *filedialog =
640 new wxFileDialog( updates_tree, wxU(_("Save file ...")),
641 wxT(""), url.AfterLast( '/' ), wxT("*.*"),
642 wxSAVE | wxOVERWRITE_PROMPT );
643 if( filedialog->ShowModal() == wxID_OK )
645 DownloadFile( url, filedialog->GetPath() );
650 void UpdateVLC::DownloadFile( wxString url, wxString dst )
652 char *psz_local = ToLocale( dst.mb_str() );
653 msg_Dbg( p_intf, "Downloading %s to %s",
654 (const char *)url.mb_str(), psz_local );
656 stream_t *p_stream = NULL;
657 p_stream = stream_UrlNew( p_intf, (const char *)url.mb_str() );
660 msg_Err( p_intf, "Failed to open %s for reading", (const char *)url.mb_str() );
661 // FIXME : display error message in dialog
666 p_file = fopen( psz_local, "w" );
669 msg_Err( p_intf, "Failed to open %s for writing", psz_local );
670 // FIXME : display error message in dialog
673 LocaleFree( psz_local );
676 wxProgressDialog *progressdialog =
677 new wxProgressDialog( wxU(_("Downloading...")),
678 wxU(wxT("Src: ") +url + wxT("\nDst: ") +dst ),
679 (int)(stream_Size(p_stream)/UPDATE_VLC_DOWNLOAD_BUFFER_SIZE), NULL,
680 wxPD_ELAPSED_TIME | wxPD_REMAINING_TIME | wxPD_AUTO_HIDE
683 void *buffer = (void *)malloc( UPDATE_VLC_DOWNLOAD_BUFFER_SIZE );
684 while( stream_Read( p_stream, buffer, UPDATE_VLC_DOWNLOAD_BUFFER_SIZE ) )
686 fwrite( buffer, UPDATE_VLC_DOWNLOAD_BUFFER_SIZE, 1, p_file);
687 if( !progressdialog->Update(++i_progress) )
691 if( p_stream ) stream_Delete( p_stream );
692 progressdialog->Destroy();
693 msg_Warn( p_intf, "User aborted download" );
697 progressdialog->Destroy();
698 msg_Dbg( p_intf, "Download finished" );
701 if( p_stream ) stream_Delete( p_stream );