1
//---------------------------------------------------------------------------------------
2
// LenMus Phonascus: The teacher of music
3
// Copyright (c) 2002-2012 LenMus project
5
// This program is free software; you can redistribute it and/or modify it under the
6
// terms of the GNU General Public License as published by the Free Software Foundation,
7
// either version 3 of the License, or (at your option) any later version.
9
// This program is distributed in the hope that it will be useful, but WITHOUT ANY
10
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
11
// PARTICULAR PURPOSE. See the GNU General Public License for more details.
13
// You should have received a copy of the GNU General Public License along with this
14
// program. If not, see <http://www.gnu.org/licenses/>.
16
// For any comment, suggestion or feature request, please contact the manager of
17
// the project at cecilios@users.sourceforge.net
19
//---------------------------------------------------------------------------------------
22
#include "lenmus_updater.h"
24
#include "lenmus_msg_box.h"
25
#include "lenmus_updater_dlg.h"
26
#include "lenmus_paths.h"
29
#include <wx/dialup.h>
30
#include <wx/wfstream.h>
31
#include <wx/protocol/http.h>
32
#include <wx/mstream.h> //to use files in memory
34
#include <wx/datetime.h> //to get and save the date of last successful check
35
#include <wx/mimetype.h>
36
#include <wx/filename.h>
41
//=======================================================================================
42
// Updater implementation
43
//=======================================================================================
44
Updater::Updater(ApplicationScope& appScope)
45
: m_appScope(appScope)
49
//---------------------------------------------------------------------------------------
54
//---------------------------------------------------------------------------------------
55
void Updater::LoadUserPreferences()
57
//load settings form user congiguration data or default values
58
wxConfigBase* pPrefs = m_appScope.get_preferences();
59
pPrefs->Read(_T("/Internet/CheckForUpdates"), &m_fCheckForUpdates, true );
63
//---------------------------------------------------------------------------------------
64
void Updater::SaveUserPreferences()
66
//save settings in user congiguration data
67
wxConfigBase* pPrefs = m_appScope.get_preferences();
68
pPrefs->Write(_T("/Internet/CheckForUpdates"), m_fCheckForUpdates );
72
//---------------------------------------------------------------------------------------
73
//true if errors in conection or update information download
74
bool Updater::DoCheck(wxString sPlatform, bool fSilent)
76
m_sPlatform = sPlatform;
80
//for developing and testing do not connect to internet (it implies firewall
81
//rules modification each time I recompile) unless explicitly selected 'Release
82
//behaviour' in Debug menu.
83
if (m_appScope.is_release_behaviour())
85
//Release behaviour. Access to internet
87
//verify if internet is available
88
if (!CheckInternetConnection())
92
wxString sEmpty = _T("");
93
wxString sMsg = sEmpty +
94
_("You are not connected to internet!") + _T("\n\n") +
95
_("To check for updates LenMus needs internet connection.") + _T("\n") +
96
_("Please, connect to internet and then retry.");
97
ErrorBox oEB(sMsg, _T("Close this error window"));
103
//wxString sUrl = _T("http://localhost/sw/UpdateData.xml");
104
#if (LENMUS_PLATFORM_UNIX == 1)
105
wxString sUrl = _T("http://www.lenmus.org/sw/UpdateData.xml");
107
wxString sUrl = _T("http://www.lenmus.org/sw/UpdateData-linux.xml");
110
//-----------------------------------
111
////Old code using wxHTTP
113
// // ensure we can build a wxURL object from the given URL
115
// wxASSERT( oURL.GetError() == wxURL_NOERR);
117
// //Setup user-agent string to be identified not as a bot but as a browser
118
// wxProtocol& oProt = oURL.GetProtocol();
119
// wxHTTP* pHTTP = (wxHTTP*)&oProt;
120
// pHTTP->SetHeader(_T("User-Agent"), _T("LenMus Phonascus updater"));
121
// oProt.SetTimeout(10); // 90 sec
123
// //create the input stream by establishing http connection
124
// wxInputStream* pInput = oURL.GetInputStream();
126
//-----------------------------------
127
//// New code using wxHttpEngine
129
// wxHTTPBuilder oHttp;
130
// oHttp.InitContentTypes(); // Initialise the content types on the page
132
// //get proxy options
133
// ProxySettings* pSettings = GetProxySettings();
135
// if (pSettings->fUseProxy) {
136
// oHttp.HttpProxy(pSettings->sProxyHostname, pSettings->nProxyPort );
137
// if (pSettings->fRequiresAuth)
138
// oHttp.HttpProxyAuth( pSettings->sProxyUsername, pSettings->sProxyPassword);
141
// //Setup user-agent string to be identified not as a bot but as a browser
142
// oHttp.SetHeader(_T("User-Agent"), _T("LenMus Phonascus updater"));
143
// oHttp.SetTimeout(10); // 10 sec
145
// wxInputStream* pInput = oHttp.GetInputStream( sUrl );
147
//-----------------------------------
148
// New code using wxHTTP
150
// ensure we can build a wxURL object from the given URL
152
wxASSERT( oURL.GetError() == wxURL_NOERR);
154
//Setup user-agent string to be identified not as a bot but as a browser
155
wxProtocol& oProt = oURL.GetProtocol();
156
wxHTTP* pHTTP = (wxHTTP*)&oProt;
157
pHTTP->SetHeader(_T("User-Agent"), _T("LenMus_updater"));
158
oProt.SetTimeout(10); // 10 secs.
161
ProxySettings* pSettings = m_appScope.get_proxy_settings();
163
// If a proxy is used, set it
164
if (pSettings->fUseProxy)
166
pHTTP->SetProxyMode(true);
167
// user:pass@host:port
168
wxString sProxyUrl = _T("http://");
169
if (pSettings->fRequiresAuth)
171
sProxyUrl += pSettings->sProxyUsername + _T(":") +
172
pSettings->sProxyPassword + _T("@");
174
sProxyUrl += pSettings->sProxyHostname +
175
wxString::Format( _T(":%d"), pSettings->nProxyPort );
176
oURL.SetProxy( sProxyUrl );
179
//create the input stream by establishing http connection
180
wxInputStream* pInput = oURL.GetInputStream();
183
//-----------------------------------
184
if (!pInput || !pInput->IsOk())
188
//wxLogMessage( oHttp.GetLastError() );
189
wxString sEmpty = _T("");
190
wxString sMsg = sEmpty + _("Error checking for updates") + _T("\n\n") +
191
_("A connection with the server could not be established. \
192
Check that you are connected to the internet and that no firewalls are blocking \
193
this program; then try again. If problems persist, the server \
194
may be down. Please, try again later.");
195
ErrorBox oEB(sMsg, _T("Close this error window"));
200
//download updates data file and analyze it
201
if (!oDoc.Load(*pInput))
203
wxLogMessage(_T("[Updater::DoCheck] Problem: Error loading XML file "));
211
//Debug behaviour. Instead of accesing Internet use local files
212
wxFileName oFN(m_appScope.get_paths()->GetRootPath(), _T("TestUpdateData.xml"));
213
wxString sFilename = oFN.GetFullPath();
214
if (!oDoc.Load(sFilename) )
216
wxLogMessage(_T("[Updater::DoCheck] Problem: Error loading XML file "));
221
//Verify type of document. Must be <UpdateData>
222
wxXmlNode *pRoot = oDoc.GetRoot();
223
if (pRoot->GetName() != _T("UpdateData"))
225
wxLogMessage(_T("[Updater::DoCheck] Error. <%s> files are not supported"), pRoot->GetName().c_str() );
229
//analyze document and extract information for this platform
230
ParseDocument(pRoot);
232
m_fNeedsUpdate = (m_sVersion != _T("") &&
233
m_sVersion != m_appScope.get_version_string());
235
return false; //no errors
238
//---------------------------------------------------------------------------------------
239
bool Updater::CheckInternetConnection()
241
bool fConnected = false; //assume not connected
244
wxDialUpManager* pManager = wxDialUpManager::Create();
245
if (pManager->IsOk()) {
246
fConnected = pManager->IsOnline();
253
//---------------------------------------------------------------------------------------
254
void Updater::ParseDocument(wxXmlNode* pNode)
258
m_sDescription = _T("");
259
m_sPackage = _T("No package!");
261
//start parsing. Loop to find <platform> tag for this platform
262
wxLogMessage(_T("[Updater::ParseDocument] Trace: Starting the parser"));
263
pNode = GetFirstChild(pNode);
264
wxXmlNode* pElement = pNode;
267
if (pElement->GetName() != _T("platform")) {
268
wxLogMessage(_T("[Updater::ParseDocument] Error: Expected tag <platform> but found <%s>"),
269
pElement->GetName().c_str() );
273
//if this platform found analyze it and finish
274
if (GetAttribute(pElement, _T("name"), _T("")) == m_sPlatform) {
275
wxLogMessage(_T("[Updater::ParseDocument] Trace: Analyzing data for <platform name='%s'>"),
276
m_sPlatform.c_str() );
279
pNode = GetFirstChild(pNode);
283
if (pElement->GetName() == _T("version")) {
284
m_sVersion = GetText(pElement);
286
else if (pElement->GetName() == _T("package")) {
287
m_sPackage = GetText(pElement);
289
else if (pElement->GetName() == _T("description")) {
290
m_sDescription = GetText(pElement);
292
else if (pElement->GetName() == _T("download_url")) {
293
m_sUrl = GetText(pElement);
296
wxLogMessage(_T("[Updater::ParseDocument] Error: Expected tag <version> or <description> but found <%s>"),
297
pElement->GetName().c_str() );
301
pNode = GetNextSibling(pNode);
306
//it is not this platform. Continue with next <platform> tag
309
// Find next next <platform> tag
310
pNode = GetNextSibling(pNode);
317
//---------------------------------------------------------------------------------------
318
void Updater::check_for_updates(wxFrame* pParent, bool fSilent)
320
if (!m_fCheckForUpdates) return;
324
m_fNeedsUpdate = false;
325
::wxBeginBusyCursor();
327
//Inform user and ask permision to proceed
329
UpdaterDlgStart dlgStart(m_pParent);
330
if (dlgStart.ShowModal() == wxID_CANCEL) {
332
return; //updater canceled
336
//conect to server and get information about updates
337
#if (LENMUS_PLATFORM_WIN32 == 1)
338
if (DoCheck(_T("Win32"), fSilent)) {
340
if (DoCheck(_T("Linux"), fSilent)) {
343
return; //Error. Not posible to do check
346
//inform about results and remove busy cursor
347
if (!m_fNeedsUpdate) {
348
//no updates available
350
if (!fSilent) wxMessageBox(_T("No updates available."));
353
//update available. Create and show informative dialog
354
UpdaterDlgInfo dlg(m_pParent, this);
355
dlg.AddPackage(GetPackage(), GetDescription());
360
//save the date of last successful check
361
wxString sLastCheckDate = (wxDateTime::Now()).Format(_T("%x"));
362
wxConfigBase* pPrefs = m_appScope.get_preferences();
363
pPrefs->Write(_T("/Options/CheckForUpdates/LastCheck"), sLastCheckDate);
367
//---------------------------------------------------------------------------------------
368
bool Updater::DownloadFiles()
370
::wxLaunchDefaultBrowser(m_sUrl);
374
//---------------------------------------------------------------------------------------
375
wxString Updater::GetText(wxXmlNode* pElement)
377
// Receives node of type ELEMENT and returns its text content
378
wxASSERT(pElement->GetType() == wxXML_ELEMENT_NODE);
380
wxXmlNode* pNode = pElement->GetChildren();
381
wxString sName = pElement->GetName();
382
wxString sValue = _T("");
384
if (pNode->GetType() == wxXML_TEXT_NODE) {
385
sValue = pNode->GetContent();
390
//---------------------------------------------------------------------------------------
391
wxString Updater::GetAttribute(wxXmlNode* pNode, wxString sName, wxString sDefault)
393
wxXmlProperty* pAttrib = pNode->GetProperties();
395
if (pAttrib->GetName() == sName)
396
return pAttrib->GetValue();
397
pAttrib = pAttrib->GetNext();
403
//---------------------------------------------------------------------------------------
404
wxXmlNode* Updater::GetNextSibling(wxXmlNode* pNode)
406
// Return next sibling element or NULL if no more
407
pNode = pNode->GetNext();
408
while (pNode && pNode->GetType() != wxXML_ELEMENT_NODE)
409
pNode = pNode->GetNext();
413
//---------------------------------------------------------------------------------------
414
wxXmlNode* Updater::GetFirstChild(wxXmlNode* pNode)
416
// Return first child element or NULL if no more
417
pNode = pNode->GetChildren();
418
while (pNode && pNode->GetType() != wxXML_ELEMENT_NODE)
419
pNode = pNode->GetNext();