]> git.sesse.net Git - vlc/blob - modules/gui/wxwidgets/updatevlc.cpp
contrib/makefile: add libmpcdec (Musepack) to win contribs
[vlc] / modules / gui / wxwidgets / updatevlc.cpp
1 /*****************************************************************************
2  * updatevlc.cpp : Check for VLC updates dialog
3  *****************************************************************************
4  * Copyright (C) 2000-2004 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Antoine Cellerier <dionoea@videolan.org>
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  * Preamble
26  *****************************************************************************/
27 #include <vlc/vlc.h>
28 #include <vlc/intf.h>
29
30 #include <wx/progdlg.h>
31
32 #include "wxwidgets.h"
33
34 #include "vlc_block.h"
35 #include "vlc_stream.h"
36 #include "vlc_xml.h"
37
38 /* define UPDATE_VLC_OS and UPDATE_VLC_ARCH */
39 /* todo : move this somewhere else (isn't wx specific) */
40
41 #ifdef WIN32
42 #   define UPDATE_VLC_OS "windows"
43 #   define UPDATE_VLC_ARCH "i386"
44 #else
45 #ifdef SYS_DARWIN
46 #   define UPDATE_VLC_OS "macosx"
47 #   define UPDATE_VLC_ARCH "ppc"
48 #else
49 #   define UPDATE_VLC_OS "*"
50 #   define UPDATE_VLC_ARCH "*"
51 #endif
52 #endif
53
54 /* arch == "*" and os == "*" concern non OS or arch specific stuff */
55
56 #define UPDATE_VLC_STATUS_URL "http://update.videolan.org/vlc/status"
57 #define UPDATE_VLC_MIRRORS_URL "http://update.videolan.org/mirrors"
58
59 #define UPDATE_VLC_DOWNLOAD_BUFFER_SIZE 2048
60
61 class UpdatesTreeItem : public wxTreeItemData
62 {
63     public:
64         UpdatesTreeItem( wxString _url ):wxTreeItemData()
65         {
66             url = _url;
67         }
68         wxString url;
69 };
70
71 /*****************************************************************************
72  * Event Table.
73  *****************************************************************************/
74
75 /* IDs for the controls and the menu commands */
76 enum
77 {
78     Close_Event,
79     CheckForUpdate_Event,
80     MirrorChoice_Event,
81     UpdatesTreeActivate_Event
82 };
83
84 BEGIN_EVENT_TABLE(UpdateVLC, wxFrame)
85     /* Button events */
86     EVT_BUTTON(wxID_OK, UpdateVLC::OnButtonClose)
87     EVT_BUTTON(CheckForUpdate_Event, UpdateVLC::OnCheckForUpdate)
88
89     /* Choice events */
90     EVT_CHOICE(MirrorChoice_Event, UpdateVLC::OnMirrorChoice)
91
92     /* Tree events */
93     EVT_TREE_ITEM_ACTIVATED(UpdatesTreeActivate_Event, UpdateVLC::OnUpdatesTreeActivate)
94
95     /* Hide the window when the user closes the window */
96     EVT_CLOSE(UpdateVLC::OnClose)
97
98 END_EVENT_TABLE()
99
100 /*****************************************************************************
101  * Constructor.
102  *****************************************************************************/
103 UpdateVLC::UpdateVLC( intf_thread_t *_p_intf, wxWindow *p_parent ):
104     wxFrame( p_parent, -1, wxU(_("Check for updates ...")), wxDefaultPosition,
105              wxDefaultSize, wxDEFAULT_FRAME_STYLE )
106 {
107     /* Initializations */
108     p_intf = _p_intf;
109     release_type = wxT( "testing" );
110     SetIcon( *p_intf->p_sys->p_icon );
111     SetAutoLayout( TRUE );
112
113     /* Create a panel to put everything in */
114     wxPanel *panel = new wxPanel( this, -1 );
115     panel->SetAutoLayout( TRUE );
116
117     updates_tree =
118         new wxTreeCtrl( panel, UpdatesTreeActivate_Event, wxDefaultPosition,
119                         wxSize( 400, 200 ),
120                         wxTR_HAS_BUTTONS | wxTR_HIDE_ROOT | wxSUNKEN_BORDER );
121     updates_tree->AddRoot( wxU(_("root" )), -1, -1, NULL );
122
123     /* Place everything in sizers */
124     wxBoxSizer *main_sizer = new wxBoxSizer( wxVERTICAL );
125     wxBoxSizer *panel_sizer = new wxBoxSizer( wxVERTICAL );
126     wxBoxSizer *subpanel_sizer = new wxBoxSizer( wxHORIZONTAL );
127     panel_sizer->Add( updates_tree, 1, wxGROW | wxALL, 5 );
128     wxButton *update_button =
129         new wxButton( panel, CheckForUpdate_Event,
130                       wxU(_("Check for updates now !")) );
131     subpanel_sizer->Add( update_button, 0, wxALL, 5 );
132 //wxChoice constructor prototype changes with 2.5
133 #if wxCHECK_VERSION(2,5,0)
134     wxArrayString *choices_array = new wxArrayString();
135     choices_array->Add( wxT("") );
136     mirrors_choice =
137         new wxChoice( panel, MirrorChoice_Event, wxDefaultPosition,
138                       wxSize( 200, -1 ), *choices_array );
139 #else
140     wxString choices_array = wxT("");
141     mirrors_choice =
142         new wxChoice( panel, -1, wxDefaultPosition,
143                       wxSize( 200, -1 ),1, *choices_array );
144 #endif
145     subpanel_sizer->Add( mirrors_choice, 0, wxALL, 5 );
146     subpanel_sizer->Layout();
147     panel_sizer->Add( subpanel_sizer, 0, wxALL , 0 );
148     panel_sizer->Layout();
149     panel->SetSizerAndFit( panel_sizer );
150     main_sizer->Add( panel, 1, wxALL | wxGROW, 0 );
151     main_sizer->Layout();
152     SetSizerAndFit( main_sizer );
153
154     UpdateMirrorsChoice();
155     UpdateUpdatesTree();
156 }
157
158
159 UpdateVLC::~UpdateVLC()
160 {
161 }
162
163 /* this function gets all the info from the xml files hosted on
164 http://update.videolan.org/ and stores it in appropriate lists */
165 void UpdateVLC::GetData()
166 {
167     stream_t *p_stream = NULL;
168     char *psz_eltname = NULL;
169     char *psz_name = NULL;
170     char *psz_value = NULL;
171     char *psz_eltvalue = NULL;
172     xml_t *p_xml = NULL;
173     xml_reader_t *p_xml_reader = NULL;
174     bool b_os = false;
175     bool b_arch = false;
176
177     struct update_file_t tmp_file;
178     struct update_version_t tmp_version;
179     std::list<update_version_t>::iterator it;
180     std::list<update_file_t>::iterator it_files;
181
182     struct update_mirror_t tmp_mirror;
183
184     p_xml = xml_Create( p_intf );
185     if( !p_xml )
186     {
187         msg_Err( p_intf, "Failed to open XML parser" );
188         // FIXME : display error message in dialog
189         return;
190     }
191
192     p_stream = stream_UrlNew( p_intf, UPDATE_VLC_STATUS_URL );
193     if( !p_stream )
194     {
195         msg_Err( p_intf, "Failed to open %s for reading",
196                  UPDATE_VLC_STATUS_URL );
197         // FIXME : display error message in dialog
198         return;
199     }
200
201     p_xml_reader = xml_ReaderCreate( p_xml, p_stream );
202
203     if( !p_xml_reader )
204     {
205         msg_Err( p_intf, "Failed to open %s for parsing",
206                  UPDATE_VLC_STATUS_URL );
207         // FIXME : display error message in dialog
208         return;
209     }
210
211     /* empty tree */
212     m_versions.clear();
213
214     /* build tree */
215     while( xml_ReaderRead( p_xml_reader ) == 1 )
216     {
217         switch( xml_ReaderNodeType( p_xml_reader ) )
218         {
219             // Error
220             case -1:
221                 // TODO : print message
222                 return;
223
224             case XML_READER_STARTELEM:
225                 psz_eltname = xml_ReaderName( p_xml_reader );
226                 if( !psz_eltname )
227                 {
228                     // TODO : print message
229                     return;
230                 }
231                 msg_Dbg( p_intf, "element name : %s", psz_eltname );
232                 while( xml_ReaderNextAttr( p_xml_reader ) == VLC_SUCCESS )
233                 {
234                     psz_name = xml_ReaderName( p_xml_reader );
235                     psz_value = xml_ReaderValue( p_xml_reader );
236                     if( !psz_name || !psz_value )
237                     {
238                         // TODO : print message
239                         free( psz_eltname );
240                         return;
241                     }
242                     msg_Dbg( p_intf, "  attribute %s = %s",
243                              psz_name, psz_value );
244                     if( b_os && b_arch )
245                     {
246                         if( strcmp( psz_eltname, "version" ) == 0 )
247                         {
248                             if( !strcmp( psz_name, "type" ) )
249                                 tmp_version.type = wxU( psz_value );
250                             if( !strcmp( psz_name, "major" ) )
251                                 tmp_version.major = wxU( psz_value );
252                             if( !strcmp( psz_name, "minor" ) )
253                                 tmp_version.minor = wxU( psz_value );
254                             if( !strcmp( psz_name, "revision" ) )
255                                 tmp_version.revision = wxU( psz_value );
256                             if( !strcmp( psz_name, "extra" ) )
257                                 tmp_version.extra = wxU( psz_value );
258                         }
259                         if( !strcmp( psz_eltname, "file" ) )
260                         {
261                             if( !strcmp( psz_name, "type" ) )
262                                 tmp_file.type = wxU( psz_value );
263                             if( !strcmp( psz_name, "md5" ) )
264                                 tmp_file.md5 = wxU( psz_value );
265                             if( !strcmp( psz_name, "size" ) )
266                                 tmp_file.size = wxU( psz_value );
267                             if( !strcmp( psz_name, "url" ) )
268                                 tmp_file.url = wxU( psz_value );
269                         }
270                     }
271                     if( !strcmp( psz_name, "name" )
272                         && ( !strcmp( psz_value, UPDATE_VLC_OS )
273                            || !strcmp( psz_value, "*" ) )
274                         && !strcmp( psz_eltname, "os" ) )
275                     {
276                         b_os = true;
277                     }
278                     if( b_os && !strcmp( psz_name, "name" )
279                         && ( !strcmp( psz_value, UPDATE_VLC_ARCH )
280                            || !strcmp( psz_value, "*" ) )
281                         && !strcmp( psz_eltname, "arch" ) )
282                     {
283                         b_arch = true;
284                     }
285                     free( psz_name );
286                     free( psz_value );
287                 }
288                 if( ( b_os && b_arch && strcmp( psz_eltname, "arch" ) ) )
289                 {
290                     if( !strcmp( psz_eltname, "version" ) )
291                     {
292                         it = m_versions.begin();
293                         while( it != m_versions.end() )
294                         {
295                             if( it->type == tmp_version.type
296                                 && it->major == tmp_version.major
297                                 && it->minor == tmp_version.minor
298                                 && it->revision == tmp_version.revision
299                                 && it->extra == tmp_version.extra )
300                             {
301                                 break;
302                             }
303                             it++;
304                         }
305                         if( it == m_versions.end() )
306                         {
307                             m_versions.push_back( tmp_version );
308                             it = m_versions.begin();
309                             while( it != m_versions.end() )
310                             {
311                                 if( it->type == tmp_version.type
312                                     && it->major == tmp_version.major
313                                     && it->minor == tmp_version.minor
314                                     && it->revision == tmp_version.revision
315                                     && it->extra == tmp_version.extra )
316                                 {
317                                     break;
318                                 }
319                                 it++;
320                             }
321                         }
322                         tmp_version.type = wxT( "" );
323                         tmp_version.major = wxT( "" );
324                         tmp_version.minor = wxT( "" );
325                         tmp_version.revision = wxT( "" );
326                         tmp_version.extra = wxT( "" );
327                     }
328                     if( !strcmp( psz_eltname, "file" ) )
329                     {
330                         it->m_files.push_back( tmp_file );
331                         tmp_file.type = wxT( "" );
332                         tmp_file.md5 = wxT( "" );
333                         tmp_file.size = wxT( "" );
334                         tmp_file.url = wxT( "" );
335                         tmp_file.description = wxT( "" );
336                     }
337                 }
338                 free( psz_eltname );
339                 break;
340
341             case XML_READER_ENDELEM:
342                 psz_eltname = xml_ReaderName( p_xml_reader );
343                 if( !psz_eltname )
344                 {
345                     // TODO : print message
346                     return;
347                 }
348                 msg_Dbg( p_intf, "element end : %s", psz_eltname );
349                 if( !strcmp( psz_eltname, "os" ) )
350                     b_os = false;
351                 if( !strcmp( psz_eltname, "arch" ) )
352                     b_arch = false;
353                 free( psz_eltname );
354                 break;
355
356             case XML_READER_TEXT:
357                 psz_eltvalue = xml_ReaderValue( p_xml_reader );
358                 msg_Dbg( p_intf, "  text : %s", psz_eltvalue );
359                 /* This doesn't look safe ... but it works */
360                 if( !m_versions.empty() )
361                     if( !it->m_files.empty() )
362                         it->m_files.back().description = wxU( psz_eltvalue );
363                 free( psz_eltvalue );
364                 break;
365         }
366     }
367
368     if( p_xml_reader && p_xml ) xml_ReaderDelete( p_xml, p_xml_reader );
369     if( p_stream ) stream_Delete( p_stream );
370
371     p_stream = stream_UrlNew( p_intf, UPDATE_VLC_MIRRORS_URL );
372     if( !p_stream )
373     {
374         msg_Err( p_intf, "Failed to open %s for reading",
375                  UPDATE_VLC_MIRRORS_URL );
376         // FIXME : display error message in dialog
377         return;
378     }
379
380     p_xml_reader = xml_ReaderCreate( p_xml, p_stream );
381
382     if( !p_xml_reader )
383     {
384         msg_Err( p_intf, "Failed to open %s for parsing",
385                  UPDATE_VLC_MIRRORS_URL );
386         // FIXME : display error message in dialog
387         return;
388     }
389     /* empty list */
390     m_mirrors.clear();
391
392     /* build list */
393     while( xml_ReaderRead( p_xml_reader ) == 1 )
394     {
395         switch( xml_ReaderNodeType( p_xml_reader ) )
396         {
397             // Error
398             case -1:
399                 // TODO : print message
400                 return;
401
402             case XML_READER_STARTELEM:
403                 psz_eltname = xml_ReaderName( p_xml_reader );
404                 if( !psz_eltname )
405                 {
406                     // TODO : print message
407                     return;
408                 }
409                 msg_Dbg( p_intf, "element name : %s", psz_eltname );
410                 while( xml_ReaderNextAttr( p_xml_reader ) == VLC_SUCCESS )
411                 {
412                     psz_name = xml_ReaderName( p_xml_reader );
413                     psz_value = xml_ReaderValue( p_xml_reader );
414                     if( !psz_name || !psz_value )
415                     {
416                         // TODO : print message
417                         free( psz_eltname );
418                         return;
419                     }
420                     msg_Dbg( p_intf, "  attribute %s = %s",
421                              psz_name, psz_value );
422                     if( !strcmp( psz_eltname, "mirror" ) )
423                     {
424                         if( !strcmp( psz_name, "name" ) )
425                             tmp_mirror.name = wxU( psz_value );
426                         if( !strcmp( psz_name, "location" ) )
427                             tmp_mirror.location = wxU( psz_value );
428                     }
429                     if( !strcmp( psz_eltname, "url" ) )
430                     {
431                         if( !strcmp( psz_name, "type" ) )
432                             tmp_mirror.type = wxU( psz_value );
433                         if( !strcmp( psz_name, "base" ) )
434                             tmp_mirror.base_url = wxU( psz_value );
435                     }
436                     free( psz_name );
437                     free( psz_value );
438                 }
439                 if( !strcmp( psz_eltname, "url" ) )
440                 {
441                     m_mirrors.push_back( tmp_mirror );
442                     tmp_mirror.type = wxT( "" );
443                     tmp_mirror.base_url = wxT( "" );
444                 }
445                 free( psz_eltname );
446                 break;
447
448             case XML_READER_ENDELEM:
449                 psz_eltname = xml_ReaderName( p_xml_reader );
450                 if( !psz_eltname )
451                 {
452                     // TODO : print message
453                     return;
454                 }
455                 msg_Dbg( p_intf, "element end : %s", psz_eltname );
456                 if( !strcmp( psz_eltname, "mirror" ) )
457                 {
458                     tmp_mirror.name = wxT( "" );
459                     tmp_mirror.location = wxT( "" );
460                 }
461                 free( psz_eltname );
462                 break;
463
464             case XML_READER_TEXT:
465                 psz_eltvalue = xml_ReaderValue( p_xml_reader );
466                 msg_Dbg( p_intf, "  text : %s", psz_eltvalue );
467                 free( psz_eltvalue );
468                 break;
469         }
470     }
471
472
473     if( p_xml_reader && p_xml ) xml_ReaderDelete( p_xml, p_xml_reader );
474     if( p_stream ) stream_Delete( p_stream );
475     if( p_xml ) xml_Delete( p_xml );
476 }
477
478 void UpdateVLC::UpdateUpdatesTree()
479 {
480     wxTreeItemId parent;
481     std::list<update_version_t>::iterator it;
482     std::list<update_file_t>::iterator it_files;
483     std::list<update_mirror_t>::iterator it_mirrors;
484
485     int selection = mirrors_choice->GetSelection();
486     wxString base_url = wxT( "" );
487
488     if( selection-- )
489     {
490         it_mirrors = m_mirrors.begin();
491         while( it_mirrors != m_mirrors.end() && selection )
492         {
493             it_mirrors++;
494             selection--;
495         }
496         if( it_mirrors != m_mirrors.end() ) base_url = it_mirrors->base_url;
497     }
498
499     /* empty tree */
500     updates_tree->DeleteAllItems();
501
502     /* build tree */
503     parent=updates_tree->AddRoot( wxU(_("root" )), -1, -1, NULL );
504     updates_tree->AppendItem( parent,
505                              wxT( "Current version : VLC media player "PACKAGE_VERSION_MAJOR"."PACKAGE_VERSION_MINOR"."PACKAGE_VERSION_REVISION"-"PACKAGE_VERSION_EXTRA ),
506                              -1, -1, new UpdatesTreeItem( wxT( "" ) ));
507     it = m_versions.begin();
508     while( it != m_versions.end() )
509     {
510         if( it->type != release_type )
511         {
512             it++;
513             continue;
514         }
515
516         if( release_type != wxT( "stable" ) && it->type == wxT( "stable" ) )
517         {
518             it++;
519             continue;
520         }
521
522         if( release_type != wxT( "stable" ) && release_type != wxT( "testing" )
523             && it->type == wxT( "testing" ) )
524         {
525             it++;
526             continue;
527         }
528
529         if( release_type != wxT( "stable" ) && release_type != wxT( "testing" )
530             && release_type != wxT( "nightly" ) )
531         {
532             it++;
533             continue;
534         }
535
536         if( atoi((const char *)it->major.mb_str()) <
537             atoi(PACKAGE_VERSION_MAJOR)
538          || ( atoi((const char *)it->major.mb_str()) ==
539               atoi(PACKAGE_VERSION_MAJOR)
540          && ( atoi((const char *)it->minor.mb_str()) <
541                atoi(PACKAGE_VERSION_MINOR)
542          || ( atoi((const char *)it->minor.mb_str()) ==
543               atoi(PACKAGE_VERSION_MINOR)
544          && ( atoi((const char *)it->revision.mb_str()) <
545                atoi(PACKAGE_VERSION_REVISION)
546          || ( atoi((const char *)it->revision.mb_str()) ==
547               atoi(PACKAGE_VERSION_REVISION) ) ) ) ) ) )
548         {
549             /* version is older or equal tu current version.
550             FIXME : how do we handle the extra version number ? */
551             it++;
552             continue;
553         }
554         wxTreeItemId cat = updates_tree->AppendItem( parent,
555                          wxT("New Version : VLC media player ")
556                          + it->major + wxT(".")
557                          + it->minor + wxT(".") + it->revision + wxT("-")
558                          + it->extra + wxT(" (") + it->type + wxT(")"),
559                          -1, -1, new UpdatesTreeItem( wxT( "" ) ));
560         it_files = it->m_files.begin();
561         while( it_files != it->m_files.end() )
562         {
563             wxString url = (it_files->url[0]=='/' ? base_url : wxT( "" ) )
564                            + it_files->url;
565             wxTreeItemId file =
566                 updates_tree->AppendItem( cat, it_files->description,
567                    -1, -1, new UpdatesTreeItem( url ) );
568             updates_tree->AppendItem( file,
569                 wxU(_("type : ")) + it_files->type,
570                 -1, -1, new UpdatesTreeItem( url ));
571             updates_tree->AppendItem( file, wxU(_("URL : ")) + url,
572                                       -1, -1, new UpdatesTreeItem( url ));
573             if( it_files->size != wxT( "" ) )
574                 updates_tree->AppendItem( file,
575                     wxU(_("file size : ")) + it_files->size,
576                     -1, -1, new UpdatesTreeItem( url ));
577             if( it_files->md5 != wxT( "" ) )
578                 updates_tree->AppendItem( file,
579                     wxU(_("file md5 hash : ")) + it_files->md5,
580                     -1, -1, new UpdatesTreeItem( url ));
581             it_files ++;
582         }
583         it ++;
584         updates_tree->Expand( cat );
585         updates_tree->Expand( parent );
586     }
587 }
588
589 void UpdateVLC::UpdateMirrorsChoice()
590 {
591     std::list<update_mirror_t>::iterator it_mirrors;
592
593     mirrors_choice->Clear();
594     mirrors_choice->Append( wxU(_("Choose a mirror")) );
595     it_mirrors = m_mirrors.begin();
596     while( it_mirrors != m_mirrors.end() )
597     {
598         mirrors_choice->Append( it_mirrors->name + wxT(" (")
599                                 + it_mirrors->location + wxT(") [")
600                                 + it_mirrors->type + wxT("]") );
601         it_mirrors++;
602     }
603     mirrors_choice->SetSelection( 0 );
604 }
605
606 /*void UpdateVLC::UpdateUpdateVLC()
607 {
608     UpdateUpdatesTree();
609     UpdateMirrorsChoice();
610 }*/
611
612 void UpdateVLC::OnButtonClose( wxCommandEvent& event )
613 {
614     wxCloseEvent cevent;
615     OnClose(cevent);
616 }
617
618 void UpdateVLC::OnClose( wxCloseEvent& WXUNUSED(event) )
619 {
620     Hide();
621 }
622
623 void UpdateVLC::OnCheckForUpdate( wxCommandEvent& event )
624 {
625     GetData();
626     UpdateMirrorsChoice();
627     UpdateUpdatesTree();
628 }
629
630 void UpdateVLC::OnMirrorChoice( wxCommandEvent& event )
631 {
632     UpdateUpdatesTree();
633 }
634
635 void UpdateVLC::OnUpdatesTreeActivate( wxTreeEvent& event )
636 {
637     wxString url =
638       ((UpdatesTreeItem *)(updates_tree->GetItemData(event.GetItem())))->url;
639     if( url != wxT( "" ) ? url[0] != '/' : false )
640     {
641         wxFileDialog *filedialog =
642             new wxFileDialog( updates_tree, wxU(_("Save file ...")),
643                               wxT(""), url.AfterLast( '/' ), wxT("*.*"),
644                               wxSAVE | wxOVERWRITE_PROMPT );
645         if( filedialog->ShowModal() == wxID_OK )
646         {
647             DownloadFile( url, filedialog->GetPath() );
648         }
649     }
650 }
651
652 void UpdateVLC::DownloadFile( wxString url, wxString dst )
653 {
654     char *psz_local = ToLocale( dst.mb_str() );
655     msg_Dbg( p_intf, "Downloading %s to %s",
656              (const char *)url.mb_str(), psz_local );
657
658     stream_t *p_stream = NULL;
659     p_stream = stream_UrlNew( p_intf, (const char *)url.mb_str() );
660     if( !p_stream )
661     {
662         msg_Err( p_intf, "Failed to open %s for reading", (const char *)url.mb_str() );
663         // FIXME : display error message in dialog
664         return;
665     }
666
667     FILE *p_file = NULL;
668     p_file = fopen( psz_local, "w" );
669     if( !p_file )
670     {
671         msg_Err( p_intf, "Failed to open %s for writing", psz_local );
672         // FIXME : display error message in dialog
673         return;
674     }
675     LocaleFree( psz_local );
676
677     int i_progress = 0;
678     wxProgressDialog *progressdialog =
679         new wxProgressDialog( wxU(_("Downloading...")),
680         wxU(wxT("Src: ") +url + wxT("\nDst: ") +dst ),
681         (int)(stream_Size(p_stream)/UPDATE_VLC_DOWNLOAD_BUFFER_SIZE), NULL,
682         wxPD_ELAPSED_TIME | wxPD_REMAINING_TIME | wxPD_AUTO_HIDE
683         | wxPD_CAN_ABORT );
684
685     void *buffer = (void *)malloc( UPDATE_VLC_DOWNLOAD_BUFFER_SIZE );
686     while( stream_Read( p_stream, buffer, UPDATE_VLC_DOWNLOAD_BUFFER_SIZE ) )
687     {
688         fwrite( buffer, UPDATE_VLC_DOWNLOAD_BUFFER_SIZE, 1, p_file);
689         if( !progressdialog->Update(++i_progress) )
690         {
691             free( buffer );
692             fclose( p_file );
693             if( p_stream ) stream_Delete( p_stream );
694             progressdialog->Destroy();
695             msg_Warn( p_intf, "User aborted download" );
696             return;
697         }
698     }
699     progressdialog->Destroy();
700     msg_Dbg( p_intf, "Download finished" );
701     free( buffer );
702     fclose( p_file );
703     if( p_stream ) stream_Delete( p_stream );
704 }