1 // This file is part of BOINC.
2 // http://boinc.berkeley.edu
3 // Copyright (C) 2008 University of California
4 //
5 // BOINC is free software; you can redistribute it and/or modify it
6 // under the terms of the GNU Lesser General Public License
7 // as published by the Free Software Foundation,
8 // either version 3 of the License, or (at your option) any later version.
9 //
10 // BOINC is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 // See the GNU Lesser General Public License for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public License
16 // along with BOINC.  If not, see <http://www.gnu.org/licenses/>.
17 
18 #if defined(__GNUG__) && !defined(__APPLE__)
19 #pragma implementation "BOINCDialupManager.h"
20 #endif
21 
22 #include "stdwx.h"
23 #include "network.h"
24 #include "diagnostics.h"
25 #include "util.h"
26 #include "mfile.h"
27 #include "miofile.h"
28 #include "parse.h"
29 #include "error_numbers.h"
30 #include "BOINCGUIApp.h"
31 #include "SkinManager.h"
32 #include "MainDocument.h"
33 #include "BOINCTaskBar.h"
34 #include "BOINCBaseFrame.h"
35 #include "BOINCDialupManager.h"
36 #include "DlgOptions.h"
37 
38 
CBOINCDialUpManager()39 CBOINCDialUpManager::CBOINCDialUpManager() {
40     wxLogTrace(wxT("Function Start/End"), wxT("CBOINCDialUpManager::CBOINCDialUpManager - Function Begin"));
41 
42 #ifdef __WXMSW__
43     m_pDialupManager = wxDialUpManager::Create();
44     wxASSERT(m_pDialupManager->IsOk());
45 #endif
46     ResetReminderTimers();
47     m_bSetConnectionTimer = false;
48     m_bNotifyConnectionAvailable = false;
49     m_bConnectedSuccessfully = false;
50     m_bResetTimers = false;
51     m_bWasDialing = false;
52     m_iNetworkStatus = 0;
53     m_iConnectAttemptRetVal = 0;
54 
55 
56     // Construct the default dialog title for dial-up messages
57     //
58     // %s is the application name
59     //    i.e. 'BOINC Manager', 'GridRepublic Manager'
60     m_strDialogTitle.Printf(
61         _("%s - Network Status"),
62         wxGetApp().GetSkinManager()->GetAdvanced()->GetApplicationName().c_str()
63     );
64 
65     wxLogTrace(wxT("Function Start/End"), wxT("CBOINCDialUpManager::CBOINCDialUpManager - Function End"));
66 }
67 
68 
~CBOINCDialUpManager()69 CBOINCDialUpManager::~CBOINCDialUpManager() {
70     wxLogTrace(wxT("Function Start/End"), wxT("CBOINCDialUpManager::~CBOINCDialUpManager - Function Begin"));
71 
72 #ifdef __WXMSW__
73     delete m_pDialupManager;
74 #endif
75     wxLogTrace(wxT("Function Start/End"), wxT("CBOINCDialUpManager::~CBOINCDialUpManager - Function End"));
76 }
77 
78 
IsOk()79 bool CBOINCDialUpManager::IsOk() {
80 #ifdef __WXMSW__
81     return m_pDialupManager->IsOk();
82 #else
83     return true;
84 #endif
85 }
86 
87 
GetISPNames(wxArrayString & names)88 size_t CBOINCDialUpManager::GetISPNames(wxArrayString& names) {
89     return m_pDialupManager->GetISPNames(names);
90 }
91 
92 
OnPoll()93 void CBOINCDialUpManager::OnPoll() {
94     CMainDocument*      pDoc = wxGetApp().GetDocument();
95     CBOINCBaseFrame*    pFrame = wxGetApp().GetFrame();
96     static bool         bAlreadyRunningLoop = false;
97     bool                bIsOnline = false;
98     bool                bWantConnection = false;
99     bool                bWantDisconnect = false;
100     CC_STATUS           cc_status;
101 
102 
103     // We are ready to rock and roll.
104     if (!bAlreadyRunningLoop && pDoc && pFrame) {
105         wxASSERT(wxDynamicCast(pDoc, CMainDocument));
106         wxASSERT(wxDynamicCast(pFrame, CBOINCBaseFrame));
107 
108         bAlreadyRunningLoop = true;
109 
110         // cache the various states
111 
112         // The dialup manager tells us if we are still dialing or if we have
113         //   successfully connected.  IsNetworkAlive/IsOnline both report the
114         //   success or failure of the dialup device to establish a connection
115         //   to the outside world.
116         pDoc->GetCoreClientStatus(cc_status);
117 
118         bIsOnline = (cc_status.network_status == NETWORK_STATUS_ONLINE);
119         bWantConnection = (cc_status.network_status == NETWORK_STATUS_WANT_CONNECTION);
120         bWantDisconnect = (cc_status.network_status == NETWORK_STATUS_WANT_DISCONNECT);
121 
122         // The timers are used to keep from spamming the user with the same
123         //   messages over each iteration of the poll loop.  we only need to
124         //   reset them during a connect event in case we randomly loose
125         //   a connection.
126         if (m_bResetTimers) {
127             wxLogTrace(wxT("Function Status"), wxT("CBOINCDialUpManager::poll - Resetting dial-up notification timers"));
128 
129             m_bResetTimers = false;
130             m_bSetConnectionTimer = false;
131             ResetReminderTimers();
132         }
133 
134         // Log out the trace information for debugging purposes.
135         /*
136         wxLogTrace(wxT("Function Status"), wxT("CBOINCDialUpManager::poll - Dialup Flags"));
137         wxLogTrace(wxT("Function Status"),
138             wxT("CBOINCDialUpManager::poll - -- bIsOnline = '%d', bIsDialing = '%d', m_bWasDialing = '%d', iNetworkStatus = '%d', bWantConnection = '%d'"),
139             bIsOnline, bIsDialing, m_bWasDialing, iNetworkStatus, bWantConnection
140         );
141         wxLogTrace(wxT("Function Status"),
142             wxT("CBOINCDialUpManager::poll - -- m_bResetTimers = '%d', m_bNotifyConnectionAvailable = '%d', m_bConnectedSuccessfully = '%d'"),
143             m_bResetTimers, m_bNotifyConnectionAvailable, m_bConnectedSuccessfully
144         );
145         wxLogTrace(wxT("Function Status"),
146             wxT("CBOINCDialUpManager::poll - -- confirm_before_connecting = '%d', hangup_if_dialed = '%d'"),
147             pDoc->state.global_prefs.confirm_before_connecting, pDoc->state.global_prefs.hangup_if_dialed
148         );
149         */
150 #ifdef __WXMSW__
151         bool  bIsDialing = m_pDialupManager->IsDialing();
152         if (!bIsOnline && !bIsDialing && !m_bWasDialing && bWantConnection) {
153             wxLogTrace(wxT("Function Status"), wxT("CBOINCDialUpManager::poll - !bIsOnline && !bIsDialing && !m_bWasDialing && bWantConnection"));
154             if (pFrame->IsShown()) {
155                 // BOINC Manager is visable and can process user input.
156                 m_bSetConnectionTimer = true;
157                 Connect();
158             }
159         } else if (!bIsDialing && !m_bWasDialing) {
160             // We are not doing anything now, were we up to something before?
161             if (bIsOnline && m_bConnectedSuccessfully && m_bNotifyConnectionAvailable) {
162                 // Ah ha, we are online and we initiated the connection, so we need to
163                 //   notify the CC that the network is available.
164                 wxLogTrace(wxT("Function Status"), wxT("CBOINCDialUpManager::poll - bIsOnline && m_bConnectedSuccessfully && m_bNotifyConnectionAvailable"));
165                 NetworkAvailable();
166             } else if (bWantDisconnect && m_bConnectedSuccessfully) {
167                 // We are online, and the CC says it is safe to disconnect.  Since we
168                 //   initiated the connection we need to disconnect now.
169                 wxLogTrace(wxT("Function Status"), wxT("CBOINCDialUpManager::poll - bWantDisconnect && m_bConnectedSuccessfully"));
170                 Disconnect();
171             }
172         } else if (!bIsDialing && m_bWasDialing) {
173             // We initiated a connection attempt and now we are either online or failed to
174             //   connect because of a modem error or a users credentials were wrong.
175             wxLogTrace(wxT("Function Status"), wxT("CBOINCDialUpManager::poll - !bIsDialing && m_bWasDialing"));
176 
177             if (m_bSetConnectionTimer) {
178                 m_bSetConnectionTimer = false;
179                 m_dtDialupConnectionTimeout = wxDateTime::Now();
180                 m_iConnectAttemptRetVal = ERR_NO_NETWORK_CONNECTION;
181             }
182 
183             wxTimeSpan tsTimeout = wxDateTime::Now() - m_dtDialupConnectionTimeout;
184             if (30 > tsTimeout.GetSeconds()) {
185                 if(m_iConnectAttemptRetVal != BOINC_SUCCESS) {
186                     return;
187                 }
188             }
189 
190             m_bWasDialing = false;
191             m_bResetTimers = true;
192             if (!m_iConnectAttemptRetVal) {
193                 ConnectionSucceeded();
194             } else {
195                 ConnectionFailed();
196             }
197         } else if (bIsDialing && !m_bWasDialing) {
198             // Setup the state machine so that it knows when we have finished the connection
199             //   attempt.
200             wxLogTrace(wxT("Function Status"), wxT("CBOINCDialUpManager::poll - bIsDialing && !m_bWasDialing"));
201             m_bWasDialing = true;
202         }
203 #endif
204         bAlreadyRunningLoop = false;
205     }
206 }
207 
208 
Connect()209 int CBOINCDialUpManager::Connect() {
210     CMainDocument*      pDoc = wxGetApp().GetDocument();
211     CBOINCBaseFrame*    pFrame = wxGetApp().GetFrame();
212     CSkinAdvanced*      pSkinAdvanced = wxGetApp().GetSkinManager()->GetAdvanced();
213     wxTimeSpan          tsLastDialupRequest;
214     int                 iAnswer;
215     wxString            strDialogMessage = wxEmptyString;
216     GLOBAL_PREFS_MASK   mask;
217 
218 
219     wxASSERT(pDoc);
220     wxASSERT(pFrame);
221     wxASSERT(pSkinAdvanced);
222     wxASSERT(wxDynamicCast(pDoc, CMainDocument));
223     wxASSERT(wxDynamicCast(pFrame, CBOINCBaseFrame));
224     wxASSERT(wxDynamicCast(pSkinAdvanced, CSkinAdvanced));
225 
226 
227     tsLastDialupRequest = wxDateTime::Now() - m_dtLastDialupRequest;
228     if ((tsLastDialupRequest.GetMinutes() >= (pFrame->GetReminderFrequency() * 60)) && (pFrame->GetReminderFrequency() != 0)) {
229         wxLogTrace(wxT("Function Status"), wxT("CBOINCDialUpManager::Connect - Begin connection process"));
230         m_dtLastDialupRequest = wxDateTime::Now();
231 
232         if(pFrame->GetDialupConnectionName().size()) {
233             // We have a valid connection name that we can dial.
234             // Update current working preferences (including any overrides) from client
235             pDoc->rpc.get_global_prefs_working_struct(pDoc->state.global_prefs, mask);
236             if(pDoc->state.global_prefs.confirm_before_connecting) {
237                 // %s is the project name
238                 //    i.e. 'BOINC', 'GridRepublic'
239                 strDialogMessage.Printf(
240                     _("%s needs to connect to the Internet.\nMay it do so now?"),
241                     pSkinAdvanced->GetApplicationShortName().c_str()
242                 );
243                 iAnswer = wxGetApp().SafeMessageBox(
244                     strDialogMessage,
245                     m_strDialogTitle,
246                     wxYES_NO | wxICON_QUESTION,
247                     pFrame
248                 );
249             } else {
250                 // %s is the project name
251                 //    i.e. 'BOINC', 'GridRepublic'
252                 strDialogMessage.Printf(
253                     _("%s is connecting to the Internet."),
254                     pSkinAdvanced->GetApplicationShortName().c_str()
255                 );
256                 pFrame->ShowAlert(
257                     m_strDialogTitle,
258                     strDialogMessage,
259                     wxOK | wxICON_INFORMATION,
260                     true
261                 );
262                 iAnswer = wxYES;
263             }
264 
265             // Are we allow to connect?
266             if (wxYES == iAnswer) {
267                 m_bNotifyConnectionAvailable = true;
268                 m_bConnectedSuccessfully = false;
269                 m_pDialupManager->Dial(
270                     pFrame->GetDialupConnectionName(),
271                     wxEmptyString,
272                     wxEmptyString,
273                     true
274                 );
275             }
276         } else {
277             // The user hasn't given us a valid connection to dial.  Inform them
278             //   that we need a connection and that they may need to set a default
279             //   connection.
280         }
281     }
282 
283     return 0;
284 }
285 
286 
ConnectionSucceeded()287 int CBOINCDialUpManager::ConnectionSucceeded() {
288     CBOINCBaseFrame*    pFrame = wxGetApp().GetFrame();
289     CSkinAdvanced*      pSkinAdvanced = wxGetApp().GetSkinManager()->GetAdvanced();
290     wxString            strDialogMessage = wxEmptyString;
291 
292 
293     wxASSERT(pFrame);
294     wxASSERT(pSkinAdvanced);
295     wxASSERT(wxDynamicCast(pFrame, CBOINCBaseFrame));
296     wxASSERT(wxDynamicCast(pSkinAdvanced, CSkinAdvanced));
297 
298 
299     // %s is the project name
300     //    i.e. 'BOINC', 'GridRepublic'
301     strDialogMessage.Printf(
302         _("%s has successfully connected to the Internet."),
303         pSkinAdvanced->GetApplicationShortName().c_str()
304     );
305     pFrame->ShowAlert(
306         m_strDialogTitle,
307         strDialogMessage,
308         wxOK | wxICON_INFORMATION,
309         true
310     );
311     m_bConnectedSuccessfully = true;
312 
313     return 0;
314 }
315 
316 
ConnectionFailed()317 int CBOINCDialUpManager::ConnectionFailed() {
318     CBOINCBaseFrame*    pFrame = wxGetApp().GetFrame();
319     CSkinAdvanced*      pSkinAdvanced = wxGetApp().GetSkinManager()->GetAdvanced();
320     wxString            strDialogMessage = wxEmptyString;
321 
322     wxASSERT(pFrame);
323     wxASSERT(pSkinAdvanced);
324     wxASSERT(wxDynamicCast(pFrame, CBOINCBaseFrame));
325     wxASSERT(wxDynamicCast(pSkinAdvanced, CSkinAdvanced));
326 
327     // %s is the project name
328     //    i.e. 'BOINC', 'GridRepublic'
329     strDialogMessage.Printf(
330         _("%s failed to connect to the Internet."),
331         pSkinAdvanced->GetApplicationShortName().c_str()
332     );
333     pFrame->ShowAlert(
334         m_strDialogTitle,
335         strDialogMessage,
336         wxOK | wxICON_ERROR,
337         true
338     );
339     m_bConnectedSuccessfully = false;
340 
341     return 0;
342 }
343 
344 
NetworkAvailable()345 int CBOINCDialUpManager::NetworkAvailable() {
346     CMainDocument*      pDoc = wxGetApp().GetDocument();
347     CBOINCBaseFrame*    pFrame = wxGetApp().GetFrame();
348     CSkinAdvanced*      pSkinAdvanced = wxGetApp().GetSkinManager()->GetAdvanced();
349     wxString            strDialogMessage = wxEmptyString;
350 
351 
352     wxASSERT(pDoc);
353     wxASSERT(pFrame);
354     wxASSERT(pSkinAdvanced);
355     wxASSERT(wxDynamicCast(pDoc, CMainDocument));
356     wxASSERT(wxDynamicCast(pFrame, CBOINCBaseFrame));
357     wxASSERT(wxDynamicCast(pSkinAdvanced, CSkinAdvanced));
358 
359 
360     wxLogTrace(wxT("Function Status"), wxT("CBOINCDialUpManager::NetworkAvailable - Connection Detected, notifing user of update to all projects"));
361 
362     m_bNotifyConnectionAvailable = false;
363 
364     // We are already online but BOINC for some reason is in a state
365     //   where it belives it has some pending work to do, so give it
366     //   a nudge
367 
368     // %s is the project name
369     //    i.e. 'BOINC', 'GridRepublic'
370     strDialogMessage.Printf(
371         _("%s has detected it is now connected to the Internet.\nUpdating all projects and retrying all transfers."),
372         pSkinAdvanced->GetApplicationShortName().c_str()
373     );
374 
375     pFrame->ShowAlert(
376         m_strDialogTitle,
377         strDialogMessage,
378         wxOK | wxICON_INFORMATION,
379         true
380     );
381 
382     // Signal BOINC to update all projects and transfers.
383     pDoc->rpc.network_available();
384 
385     return 0;
386 }
387 
388 
Disconnect()389 int CBOINCDialUpManager::Disconnect() {
390     CMainDocument*      pDoc = wxGetApp().GetDocument();
391     CBOINCBaseFrame*    pFrame = wxGetApp().GetFrame();
392     CSkinAdvanced*      pSkinAdvanced = wxGetApp().GetSkinManager()->GetAdvanced();
393     wxString            strDialogMessage = wxEmptyString;
394     GLOBAL_PREFS_MASK   mask;
395 
396 
397     wxASSERT(pDoc);
398     wxASSERT(pFrame);
399     wxASSERT(pSkinAdvanced);
400     wxASSERT(wxDynamicCast(pDoc, CMainDocument));
401     wxASSERT(wxDynamicCast(pFrame, CBOINCBaseFrame));
402     wxASSERT(wxDynamicCast(pSkinAdvanced, CSkinAdvanced));
403 
404 
405     wxLogTrace(wxT("Function Status"), wxT("CBOINCDialUpManager::Disconnect - Connection Detected, disconnect requested via the CC."));
406 
407     // Update current working preferences (including any overrides) from client
408     pDoc->rpc.get_global_prefs_working_struct(pDoc->state.global_prefs, mask);
409     if (pDoc->state.global_prefs.hangup_if_dialed) {
410         wxLogTrace(wxT("Function Status"), wxT("CBOINCDialUpManager::Disconnect - Connection Detected, Don't need the network, Hanging up."));
411         if (m_pDialupManager->HangUp()) {
412 
413             // %s is the project name
414             //    i.e. 'BOINC', 'GridRepublic'
415             strDialogMessage.Printf(
416                 _("%s has successfully disconnected from the Internet."),
417                 pSkinAdvanced->GetApplicationShortName().c_str()
418             );
419             pFrame->ShowAlert(
420                 m_strDialogTitle,
421                 strDialogMessage,
422                 wxOK | wxICON_INFORMATION,
423                 true
424             );
425             m_bConnectedSuccessfully = false;
426 
427         } else {
428 
429             // %s is the project name
430             //    i.e. 'BOINC', 'GridRepublic'
431             strDialogMessage.Printf(
432                 _("%s failed to disconnected from the Internet."),
433                 pSkinAdvanced->GetApplicationShortName().c_str()
434             );
435             pFrame->ShowAlert(
436                 m_strDialogTitle,
437                 strDialogMessage,
438                 wxOK | wxICON_ERROR
439             );
440         }
441     }
442 
443     return 0;
444 }
445 
446 
ResetReminderTimers()447 void CBOINCDialUpManager::ResetReminderTimers() {
448     m_dtLastDialupRequest = wxDateTime((time_t)0);
449     m_dtDialupConnectionTimeout = wxDateTime((time_t)0);
450 }
451 
452