source: eviacam/trunk/fuentes/src/checkupdates.cpp @ 567

Last change on this file since 567 was 567, checked in by mabarracus, 4 years ago

updated sources to version 2.0.3

File size: 8.1 KB
Line 
1/////////////////////////////////////////////////////////////////////////////
2// Name:        checkupdates.cpp
3// Purpose:     
4// Author:      Cesar Mauri Loba (cesar at crea-si dot com)
5// Copyright:   (C) 2012-14 Cesar Mauri Loba - CREA Software Systems
6//
7//  This program is free software: you can redistribute it and/or modify
8//  it under the terms of the GNU General Public License as published by
9//  the Free Software Foundation, either version 3 of the License, or
10//  (at your option) any later version.
11//
12//  This program is distributed in the hope that it will be useful,
13//  but WITHOUT ANY WARRANTY; without even the implied warranty of
14//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15//  GNU General Public License for more details.
16//
17//  You should have received a copy of the GNU General Public License
18//  along with this program.  If not, see <http://www.gnu.org/licenses/>.
19/////////////////////////////////////////////////////////////////////////////
20
21#include "checkupdates.h"
22#include "config.h"
23
24#include <wx/intl.h>
25#include <wx/protocol/http.h>
26#include <wx/thread.h>
27
28#define UPDATE_HOSTNAME "eviacam.crea-si.com"
29#ifdef NDEBUG           
30        #define MODE_DEBUG _T("&m=r")
31#else
32        #define MODE_DEBUG _T("&m=d")
33#endif
34
35#if defined(__WXGTK__)
36        #define UPDATE_FILE _T("/version.php?cv=") _T(VERSION) _T("&p=linux") MODE_DEBUG
37#else
38        #define UPDATE_FILE _T("/version.php?cv=") _T(VERSION) _T("&p=windows") MODE_DEBUG
39#endif
40
41
42
43// Compare two version strings
44// Return:
45// -1: s1< s2
46// 0: s1== s2
47// 1: s1> s2
48static
49int versionstrcmp(const char* s1, const char* s2)
50{
51        int compo_s1[4], compo_s2[4];
52
53        for (int i= 0; i< 4; i++) compo_s1[i]= compo_s2[i]= 0;
54
55        sscanf (s1, "%d.%d.%d.%d", &compo_s1[0], &compo_s1[1], &compo_s1[2], &compo_s1[3]);
56        sscanf (s2, "%d.%d.%d.%d", &compo_s2[0], &compo_s2[1], &compo_s2[2], &compo_s2[3]);
57
58        for (int i= 0; i< 4; i++) {
59                if (compo_s1[i]< compo_s2[i]) return -1;
60                if (compo_s1[i]> compo_s2[i]) return 1;
61        }
62
63        return 0;
64}
65
66#define VERSION_STRING_MAX_SIZE 20
67
68// Check if a new version of the software is available by
69// checking the contents of 
70// http://UPDATE_HOSTNAME/UPDATE_FILE
71//
72// Return:
73//  1: newer version available
74//  0: no newer version available
75//      -1: local version newer than remote!
76//      -2: cannot resolve host name
77//      -3: cannot connect to host
78//  -4: file does not exist (on server)
79//  -5: generic error
80
81static 
82int check_updates(std::string* new_version)
83{
84        // Create request on the heap as recommended in the documentation
85        wxHTTP* request= new wxHTTP();
86        if (!request) return -5;
87
88        wxInputStream *httpStream = NULL;
89   
90        int retval= 0;
91
92        request->SetHeader(_T("Content-type"), _T("text/html; charset=utf-8"));
93        request->SetTimeout(10); // 10 seconds of timeout
94
95        // Start connection request (actually only resolve hostname)
96        if (!request->Connect(_T(UPDATE_HOSTNAME))) {
97                retval= -2;
98                goto check_update_error;
99        }
100
101        // Set file to request & make connection
102        httpStream = request->GetInputStream(UPDATE_FILE);
103        if (!httpStream) {
104                // Due to a buggy wxHTTP implementation, many errors are reported
105                // this way. User only sees "connection error".
106                retval= -3;
107                goto check_update_error;
108        }
109
110        if (request->GetError()!= wxPROTO_NOERR) {
111                switch (request->GetError()) {
112                        case wxPROTO_CONNERR: retval= -3; break;
113                        case wxPROTO_NOFILE: retval= -4; break;
114                        default: retval= -5;
115                }
116                goto check_update_error;
117        }
118
119        // Read file contents up to VERSION_STRING_MAX_SIZE bytes
120        char buffer[VERSION_STRING_MAX_SIZE + 1];
121        {
122                unsigned int read_count= 0;
123                bool is_eof= false;
124
125                while (read_count< VERSION_STRING_MAX_SIZE && !is_eof) {
126                        httpStream->Read(&buffer[read_count], VERSION_STRING_MAX_SIZE - read_count);
127                        read_count+= static_cast<unsigned int>(httpStream->LastRead());
128                        is_eof= httpStream->Eof();
129                }
130                assert (read_count<= VERSION_STRING_MAX_SIZE);
131                buffer[read_count]= 0;  // String terminator
132        }
133
134        retval= versionstrcmp(buffer, VERSION);
135
136        if (new_version) (*new_version)= buffer;
137         
138check_update_error:
139        if (httpStream) wxDELETE(httpStream);
140        if (request) request->Destroy();
141        return retval; 
142}
143
144DECLARE_EVENT_TYPE(THREAD_FINISHED_EVENT, wxCommandEvent);
145
146DEFINE_EVENT_TYPE(THREAD_FINISHED_EVENT);
147DEFINE_EVENT_TYPE(CHECKUPDATE_FINISHED_EVENT);
148
149BEGIN_EVENT_TABLE(eviacam::CheckUpdates, wxEvtHandler)
150        EVT_COMMAND(wxID_ANY, THREAD_FINISHED_EVENT, eviacam::CheckUpdates::OnThreadFinished)
151END_EVENT_TABLE()
152
153namespace eviacam {
154
155void CheckUpdates::OnThreadFinished(wxCommandEvent& event)
156{
157        // This event handler translates the event sent from the worker thread,
158        // which stores version name using a SetClientData, into a new wxCommandEvent
159        // which uses SetString. We need to do so in order to maintain compatibility with
160        // wx2.x. There are chances to leak some memory if some THREAD_FINISHED_EVENT are
161        // discarded and thus not properly deallocated.
162        // TODO: when wx 3.0 takes over 2.x remove this stuff and send events directly
163        // from the thread using wxQueueEvent. See here for more info:
164        // // http://docs.wxwidgets.org/trunk/group__group__funcmacro__events.html#ga0cf60a1ad3a5f1e659f7ae591570f58d
165
166        assert(wxIsMainThread());
167
168        wxCommandEvent eventNew(CHECKUPDATE_FINISHED_EVENT);
169
170        // String
171        wxString* msg = static_cast<wxString*>(event.GetClientData());
172        eventNew.SetString(wxString(msg->mb_str(wxConvUTF8), wxConvUTF8)); // Take a deep copy of the string
173        delete msg;
174       
175        // Status code
176        eventNew.SetInt(event.GetInt());
177       
178        // Finish processing old event
179        event.Skip(true); 
180
181        // Fire new event. Use this instead of wxQueueEvent for wx2.8 compatibility
182        wxPostEvent(this, eventNew); 
183}
184
185CheckUpdates::CheckUpdates()
186: m_threadRunning(false)
187{
188}
189
190CheckUpdates::~CheckUpdates()
191{
192        // Wait for the thread to finish
193        while (m_threadRunning)
194                wxThread::This()->Sleep(1);
195}
196
197void CheckUpdates::Start()
198{
199        m_threadRunning = true;
200        new CheckUpdatesWorker(*this);
201}
202
203CheckUpdates::CheckUpdatesWorker::CheckUpdatesWorker(CheckUpdates& handler)
204: wxThread(wxTHREAD_DETACHED)
205, m_handler(&handler)
206{
207        wxThreadError retval= this->Create();
208        if (retval== wxTHREAD_NO_ERROR) retval= this->Run();
209
210        if (retval!= wxTHREAD_NO_ERROR) {
211                m_handler->m_threadRunning = false;
212
213                wxCommandEvent event(THREAD_FINISHED_EVENT);
214               
215                // Store information string using SetClientData instead of SetString
216                wxString* msg = new wxString(_("Error checking for updates. Try again later."));
217                event.SetClientData(msg);
218
219                event.SetInt(CheckUpdates::ERROR_CHECKING_NEW_VERSION);
220               
221                // Use this instead of wxQueueEvent for wx2.8 compatibility
222                wxPostEvent(m_handler, event); 
223        }
224}
225
226CheckUpdates::CheckUpdatesWorker::~CheckUpdatesWorker()
227{
228        m_handler->m_threadRunning = false;
229}
230
231wxThread::ExitCode CheckUpdates::CheckUpdatesWorker::Entry()
232{
233        std::string new_version;
234        int result= check_updates(&new_version);
235        wxString* msg = NULL;
236        wxCommandEvent event(THREAD_FINISHED_EVENT);
237       
238        switch (result) {
239                case 1: // newer version available
240                        msg = new wxString(new_version.c_str(), wxConvUTF8);
241                        event.SetInt(CheckUpdates::NEW_VERSION_AVAILABLE);
242                        break;
243                case 0: // no newer version available
244                case -1: // local version newer than remote!
245                        msg = new wxString(new_version.c_str(), wxConvUTF8);
246                        event.SetInt(CheckUpdates::NO_NEW_VERSION_AVAILABLE);
247                        break;
248                case -2: // cannot resolve host name
249                        msg = new wxString(_("Cannot resolve host name: "));
250                        msg->Append(_T(UPDATE_HOSTNAME));
251                        event.SetInt(CheckUpdates::ERROR_CHECKING_NEW_VERSION);
252                        break;
253                case -3: // cannot connect to host
254                        msg = new wxString(_("Conection failed: "));
255                        msg->Append(_T(UPDATE_HOSTNAME));
256                        event.SetInt(CheckUpdates::ERROR_CHECKING_NEW_VERSION);
257                        break;
258                case -4: // file does not exist (on server)
259                        msg = new wxString(_("Sorry. Version file not found. Please report us."));
260                        event.SetInt(CheckUpdates::ERROR_CHECKING_NEW_VERSION);
261                        break;
262                case -5: // generic error
263                        msg = new wxString(_("Sorry. Something bad happened."));
264                        event.SetInt(CheckUpdates::ERROR_CHECKING_NEW_VERSION);
265                        break;
266                default:
267                        assert (false);
268        }
269
270        // Store information string using SetClientData instead of SetString
271        event.SetClientData(msg);
272
273        // Use this instead of wxQueueEvent for wx2.8 compatibility
274        wxPostEvent(m_handler, event);
275       
276        return ExitCode(0);
277}
278
279}
Note: See TracBrowser for help on using the repository browser.