]> git.sesse.net Git - vlc/blob - modules/gui/wxwidgets/dialogs/updatevlc.cpp
* Got rid of SYS_DARWIN everywhere.
[vlc] / modules / gui / wxwidgets / dialogs / updatevlc.cpp
1 /*****************************************************************************
2  * updatevlc.cpp : VLC Update checker
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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include "updatevlc.hpp"
28 #include <wx/progdlg.h>
29 #include <wx/treectrl.h>
30
31 #include "vlc_block.h"
32 #include "vlc_stream.h"
33 #include "vlc_xml.h"
34
35 /* define UPDATE_VLC_OS and UPDATE_VLC_ARCH */
36 /* todo : move this somewhere else (isn't wx specific) */
37
38 #ifdef WIN32
39 #   define UPDATE_VLC_OS "windows"
40 #   define UPDATE_VLC_ARCH "i386"
41 #else
42 #ifdef __APPLE__
43 #   define UPDATE_VLC_OS "macosx"
44 #   define UPDATE_VLC_ARCH "ppc"
45 #else
46 #   define UPDATE_VLC_OS "*"
47 #   define UPDATE_VLC_ARCH "*"
48 #endif
49 #endif
50
51 /* arch == "*" and os == "*" concern non OS or arch specific stuff */
52
53 #define UPDATE_VLC_STATUS_URL "http://update.videolan.org/vlc/status"
54 #define UPDATE_VLC_MIRRORS_URL "http://update.videolan.org/mirrors"
55
56 #define UPDATE_VLC_DOWNLOAD_BUFFER_SIZE 2048
57
58 class UpdatesTreeItem : public wxTreeItemData
59 {
60     public:
61         UpdatesTreeItem( wxString _url ):wxTreeItemData()
62         {
63             url = _url;
64         }
65         wxString url;
66 };
67
68 /*****************************************************************************
69  * Event Table.
70  *****************************************************************************/
71
72 /* IDs for the controls and the menu commands */
73 enum
74 {
75     Close_Event,
76     CheckForUpdate_Event,
77     MirrorChoice_Event,
78     UpdatesTreeActivate_Event
79 };
80
81 BEGIN_EVENT_TABLE(UpdateVLC, wxFrame)
82     /* Button events */
83     EVT_BUTTON(wxID_OK, UpdateVLC::OnButtonClose)
84     EVT_BUTTON(CheckForUpdate_Event, UpdateVLC::OnCheckForUpdate)
85
86     /* Choice events */
87     EVT_CHOICE(MirrorChoice_Event, UpdateVLC::OnMirrorChoice)
88
89     /* Tree events */
90     EVT_TREE_ITEM_ACTIVATED(UpdatesTreeActivate_Event, UpdateVLC::OnUpdatesTreeActivate)
91
92     /* Hide the window when the user closes the window */
93     EVT_CLOSE(UpdateVLC::OnClose)
94
95 END_EVENT_TABLE()
96
97 /*****************************************************************************
98  * Constructor.
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 )
103 {
104     /* Initializations */
105     p_intf = _p_intf;
106     release_type = wxT( "testing" );
107     SetIcon( *p_intf->p_sys->p_icon );
108     SetAutoLayout( TRUE );
109
110     /* Create a panel to put everything in */
111     wxPanel *panel = new wxPanel( this, -1 );
112     panel->SetAutoLayout( TRUE );
113
114     updates_tree =
115         new wxTreeCtrl( panel, UpdatesTreeActivate_Event, wxDefaultPosition,
116                         wxSize( 400, 200 ),
117                         wxTR_HAS_BUTTONS | wxTR_HIDE_ROOT | wxSUNKEN_BORDER );
118     updates_tree->AddRoot( wxU(_("root" )), -1, -1, NULL );
119
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("") );
133     mirrors_choice =
134         new wxChoice( panel, MirrorChoice_Event, wxDefaultPosition,
135                       wxSize( 200, -1 ), *choices_array );
136 #else
137     wxString choices_array = wxT("");
138     mirrors_choice =
139         new wxChoice( panel, -1, wxDefaultPosition,
140                       wxSize( 200, -1 ),1, *choices_array );
141 #endif
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 );
150
151     UpdateMirrorsChoice();
152     UpdateUpdatesTree();
153 }
154
155
156 UpdateVLC::~UpdateVLC()
157 {
158     fprintf( stderr, "Fooing\n");
159 }
160
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()
164 {
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;
170     xml_t *p_xml = NULL;
171     xml_reader_t *p_xml_reader = NULL;
172     bool b_os = false;
173     bool b_arch = false;
174
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;
179
180     struct update_mirror_t tmp_mirror;
181
182     p_xml = xml_Create( p_intf );
183     if( !p_xml )
184     {
185         msg_Err( p_intf, "Failed to open XML parser" );
186         // FIXME : display error message in dialog
187         return;
188     }
189
190     p_stream = stream_UrlNew( p_intf, UPDATE_VLC_STATUS_URL );
191     if( !p_stream )
192     {
193         msg_Err( p_intf, "Failed to open %s for reading",
194                  UPDATE_VLC_STATUS_URL );
195         // FIXME : display error message in dialog
196         return;
197     }
198
199     p_xml_reader = xml_ReaderCreate( p_xml, p_stream );
200
201     if( !p_xml_reader )
202     {
203         msg_Err( p_intf, "Failed to open %s for parsing",
204                  UPDATE_VLC_STATUS_URL );
205         // FIXME : display error message in dialog
206         return;
207     }
208
209     /* empty tree */
210     m_versions.clear();
211
212     /* build tree */
213     while( xml_ReaderRead( p_xml_reader ) == 1 )
214     {
215         switch( xml_ReaderNodeType( p_xml_reader ) )
216         {
217             // Error
218             case -1:
219                 // TODO : print message
220                 return;
221
222             case XML_READER_STARTELEM:
223                 psz_eltname = xml_ReaderName( p_xml_reader );
224                 if( !psz_eltname )
225                 {
226                     // TODO : print message
227                     return;
228                 }
229                 msg_Dbg( p_intf, "element name : %s", psz_eltname );
230                 while( xml_ReaderNextAttr( p_xml_reader ) == VLC_SUCCESS )
231                 {
232                     psz_name = xml_ReaderName( p_xml_reader );
233                     psz_value = xml_ReaderValue( p_xml_reader );
234                     if( !psz_name || !psz_value )
235                     {
236                         // TODO : print message
237                         free( psz_eltname );
238                         return;
239                     }
240                     msg_Dbg( p_intf, "  attribute %s = %s",
241                              psz_name, psz_value );
242                     if( b_os && b_arch )
243                     {
244                         if( strcmp( psz_eltname, "version" ) == 0 )
245                         {
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 );
256                         }
257                         if( !strcmp( psz_eltname, "file" ) )
258                         {
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 );
267                         }
268                     }
269                     if( !strcmp( psz_name, "name" )
270                         && ( !strcmp( psz_value, UPDATE_VLC_OS )
271                            || !strcmp( psz_value, "*" ) )
272                         && !strcmp( psz_eltname, "os" ) )
273                     {
274                         b_os = true;
275                     }
276                     if( b_os && !strcmp( psz_name, "name" )
277                         && ( !strcmp( psz_value, UPDATE_VLC_ARCH )
278                            || !strcmp( psz_value, "*" ) )
279                         && !strcmp( psz_eltname, "arch" ) )
280                     {
281                         b_arch = true;
282                     }
283                     free( psz_name );
284                     free( psz_value );
285                 }
286                 if( ( b_os && b_arch && strcmp( psz_eltname, "arch" ) ) )
287                 {
288                     if( !strcmp( psz_eltname, "version" ) )
289                     {
290                         it = m_versions.begin();
291                         while( it != m_versions.end() )
292                         {
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 )
298                             {
299                                 break;
300                             }
301                             it++;
302                         }
303                         if( it == m_versions.end() )
304                         {
305                             m_versions.push_back( tmp_version );
306                             it = m_versions.begin();
307                             while( it != m_versions.end() )
308                             {
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 )
314                                 {
315                                     break;
316                                 }
317                                 it++;
318                             }
319                         }
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( "" );
325                     }
326                     if( !strcmp( psz_eltname, "file" ) )
327                     {
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( "" );
334                     }
335                 }
336                 free( psz_eltname );
337                 break;
338
339             case XML_READER_ENDELEM:
340                 psz_eltname = xml_ReaderName( p_xml_reader );
341                 if( !psz_eltname )
342                 {
343                     // TODO : print message
344                     return;
345                 }
346                 msg_Dbg( p_intf, "element end : %s", psz_eltname );
347                 if( !strcmp( psz_eltname, "os" ) )
348                     b_os = false;
349                 if( !strcmp( psz_eltname, "arch" ) )
350                     b_arch = false;
351                 free( psz_eltname );
352                 break;
353
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 );
362                 break;
363         }
364     }
365
366     if( p_xml_reader && p_xml ) xml_ReaderDelete( p_xml, p_xml_reader );
367     if( p_stream ) stream_Delete( p_stream );
368
369     p_stream = stream_UrlNew( p_intf, UPDATE_VLC_MIRRORS_URL );
370     if( !p_stream )
371     {
372         msg_Err( p_intf, "Failed to open %s for reading",
373                  UPDATE_VLC_MIRRORS_URL );
374         // FIXME : display error message in dialog
375         return;
376     }
377
378     p_xml_reader = xml_ReaderCreate( p_xml, p_stream );
379
380     if( !p_xml_reader )
381     {
382         msg_Err( p_intf, "Failed to open %s for parsing",
383                  UPDATE_VLC_MIRRORS_URL );
384         // FIXME : display error message in dialog
385         return;
386     }
387     /* empty list */
388     m_mirrors.clear();
389
390     /* build list */
391     while( xml_ReaderRead( p_xml_reader ) == 1 )
392     {
393         switch( xml_ReaderNodeType( p_xml_reader ) )
394         {
395             // Error
396             case -1:
397                 // TODO : print message
398                 return;
399
400             case XML_READER_STARTELEM:
401                 psz_eltname = xml_ReaderName( p_xml_reader );
402                 if( !psz_eltname )
403                 {
404                     // TODO : print message
405                     return;
406                 }
407                 msg_Dbg( p_intf, "element name : %s", psz_eltname );
408                 while( xml_ReaderNextAttr( p_xml_reader ) == VLC_SUCCESS )
409                 {
410                     psz_name = xml_ReaderName( p_xml_reader );
411                     psz_value = xml_ReaderValue( p_xml_reader );
412                     if( !psz_name || !psz_value )
413                     {
414                         // TODO : print message
415                         free( psz_eltname );
416                         return;
417                     }
418                     msg_Dbg( p_intf, "  attribute %s = %s",
419                              psz_name, psz_value );
420                     if( !strcmp( psz_eltname, "mirror" ) )
421                     {
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 );
426                     }
427                     if( !strcmp( psz_eltname, "url" ) )
428                     {
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 );
433                     }
434                     free( psz_name );
435                     free( psz_value );
436                 }
437                 if( !strcmp( psz_eltname, "url" ) )
438                 {
439                     m_mirrors.push_back( tmp_mirror );
440                     tmp_mirror.type = wxT( "" );
441                     tmp_mirror.base_url = wxT( "" );
442                 }
443                 free( psz_eltname );
444                 break;
445
446             case XML_READER_ENDELEM:
447                 psz_eltname = xml_ReaderName( p_xml_reader );
448                 if( !psz_eltname )
449                 {
450                     // TODO : print message
451                     return;
452                 }
453                 msg_Dbg( p_intf, "element end : %s", psz_eltname );
454                 if( !strcmp( psz_eltname, "mirror" ) )
455                 {
456                     tmp_mirror.name = wxT( "" );
457                     tmp_mirror.location = wxT( "" );
458                 }
459                 free( psz_eltname );
460                 break;
461
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 );
466                 break;
467         }
468     }
469
470
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 );
474 }
475
476 void UpdateVLC::UpdateUpdatesTree()
477 {
478     wxTreeItemId parent;
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;
482
483     int selection = mirrors_choice->GetSelection();
484     wxString base_url = wxT( "" );
485
486     if( selection-- )
487     {
488         it_mirrors = m_mirrors.begin();
489         while( it_mirrors != m_mirrors.end() && selection )
490         {
491             it_mirrors++;
492             selection--;
493         }
494         if( it_mirrors != m_mirrors.end() ) base_url = it_mirrors->base_url;
495     }
496
497     /* empty tree */
498     updates_tree->DeleteAllItems();
499
500     /* build tree */
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() )
507     {
508         if( it->type != release_type )
509         {
510             it++;
511             continue;
512         }
513
514         if( release_type != wxT( "stable" ) && it->type == wxT( "stable" ) )
515         {
516             it++;
517             continue;
518         }
519
520         if( release_type != wxT( "stable" ) && release_type != wxT( "testing" )
521             && it->type == wxT( "testing" ) )
522         {
523             it++;
524             continue;
525         }
526
527         if( release_type != wxT( "stable" ) && release_type != wxT( "testing" )
528             && release_type != wxT( "nightly" ) )
529         {
530             it++;
531             continue;
532         }
533
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) ) ) ) ) ) )
546         {
547             /* version is older or equal tu current version.
548             FIXME : how do we handle the extra version number ? */
549             it++;
550             continue;
551         }
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() )
560         {
561             wxString url = (it_files->url[0]=='/' ? base_url : wxT( "" ) )
562                            + it_files->url;
563             wxTreeItemId file =
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 ));
579             it_files ++;
580         }
581         it ++;
582         updates_tree->Expand( cat );
583         updates_tree->Expand( parent );
584     }
585 }
586
587 void UpdateVLC::UpdateMirrorsChoice()
588 {
589     std::list<update_mirror_t>::iterator it_mirrors;
590
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() )
595     {
596         mirrors_choice->Append( it_mirrors->name + wxT(" (")
597                                 + it_mirrors->location + wxT(") [")
598                                 + it_mirrors->type + wxT("]") );
599         it_mirrors++;
600     }
601     mirrors_choice->SetSelection( 0 );
602 }
603
604 /*void UpdateVLC::UpdateUpdateVLC()
605 {
606     UpdateUpdatesTree();
607     UpdateMirrorsChoice();
608 }*/
609
610 void UpdateVLC::OnButtonClose( wxCommandEvent& event )
611 {
612     wxCloseEvent cevent;
613     OnClose(cevent);
614 }
615
616 void UpdateVLC::OnClose( wxCloseEvent& WXUNUSED(event) )
617 {
618     Hide();
619 }
620
621 void UpdateVLC::OnCheckForUpdate( wxCommandEvent& event )
622 {
623     GetData();
624     UpdateMirrorsChoice();
625     UpdateUpdatesTree();
626 }
627
628 void UpdateVLC::OnMirrorChoice( wxCommandEvent& event )
629 {
630     UpdateUpdatesTree();
631 }
632
633 void UpdateVLC::OnUpdatesTreeActivate( wxTreeEvent& event )
634 {
635     wxString url =
636       ((UpdatesTreeItem *)(updates_tree->GetItemData(event.GetItem())))->url;
637     if( url != wxT( "" ) ? url[0] != '/' : false )
638     {
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 )
644         {
645             DownloadFile( url, filedialog->GetPath() );
646         }
647     }
648 }
649
650 void UpdateVLC::DownloadFile( wxString url, wxString dst )
651 {
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 );
655
656     stream_t *p_stream = NULL;
657     p_stream = stream_UrlNew( p_intf, (const char *)url.mb_str() );
658     if( !p_stream )
659     {
660         msg_Err( p_intf, "Failed to open %s for reading", (const char *)url.mb_str() );
661         // FIXME : display error message in dialog
662         return;
663     }
664
665     FILE *p_file = NULL;
666     p_file = fopen( psz_local, "w" );
667     if( !p_file )
668     {
669         msg_Err( p_intf, "Failed to open %s for writing", psz_local );
670         // FIXME : display error message in dialog
671         return;
672     }
673     LocaleFree( psz_local );
674
675     int i_progress = 0;
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
681         | wxPD_CAN_ABORT );
682
683     void *buffer = (void *)malloc( UPDATE_VLC_DOWNLOAD_BUFFER_SIZE );
684     while( stream_Read( p_stream, buffer, UPDATE_VLC_DOWNLOAD_BUFFER_SIZE ) )
685     {
686         fwrite( buffer, UPDATE_VLC_DOWNLOAD_BUFFER_SIZE, 1, p_file);
687         if( !progressdialog->Update(++i_progress) )
688         {
689             free( buffer );
690             fclose( p_file );
691             if( p_stream ) stream_Delete( p_stream );
692             progressdialog->Destroy();
693             msg_Warn( p_intf, "User aborted download" );
694             return;
695         }
696     }
697     progressdialog->Destroy();
698     msg_Dbg( p_intf, "Download finished" );
699     free( buffer );
700     fclose( p_file );
701     if( p_stream ) stream_Delete( p_stream );
702 }