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 "WizardAttach.h"
20 #endif
21 
22 #include "stdwx.h"
23 #include "diagnostics.h"
24 #include "util.h"
25 #include "mfile.h"
26 #include "miofile.h"
27 #include "parse.h"
28 #include "error_numbers.h"
29 #include "wizardex.h"
30 #include "error_numbers.h"
31 #include "browser.h"
32 #include "BOINCGUIApp.h"
33 #include "SkinManager.h"
34 #include "MainDocument.h"
35 #include "BOINCBaseWizard.h"
36 #include "BOINCBaseFrame.h"
37 #include "WizardAttach.h"
38 #include "ProjectInfoPage.h"
39 #include "ProjectPropertiesPage.h"
40 #include "ProjectProcessingPage.h"
41 #include "ProjectWelcomePage.h"
42 #include "AccountManagerInfoPage.h"
43 #include "AccountManagerPropertiesPage.h"
44 #include "AccountManagerProcessingPage.h"
45 #include "TermsOfUsePage.h"
46 #include "AccountInfoPage.h"
47 #include "CompletionPage.h"
48 #include "CompletionErrorPage.h"
49 #include "NotDetectedPage.h"
50 #include "UnavailablePage.h"
51 #include "NoInternetConnectionPage.h"
52 #include "NotFoundPage.h"
53 #include "AlreadyExistsPage.h"
54 #include "ProxyInfoPage.h"
55 #include "ProxyPage.h"
56 
57 
58 /*!
59  * CWizardAttach type definition
60  */
61 
IMPLEMENT_DYNAMIC_CLASS(CWizardAttach,CBOINCBaseWizard)62 IMPLEMENT_DYNAMIC_CLASS( CWizardAttach, CBOINCBaseWizard )
63 
64 /*!
65  * CWizardAttach event table definition
66  */
67 
68 BEGIN_EVENT_TABLE( CWizardAttach, CBOINCBaseWizard )
69 ////@begin CWizardAttach event table entries
70     EVT_WIZARDEX_FINISHED( ID_ATTACHWIZARD, CWizardAttach::OnFinished )
71 ////@end CWizardAttach event table entries
72 END_EVENT_TABLE()
73 
74 /*!
75  * CWizardAttach constructors
76  */
77 
78 CWizardAttach::CWizardAttach()
79 {
80 }
81 
CWizardAttach(wxWindow * parent,wxWindowID id,const wxString & title,const wxPoint & pos,long style)82 CWizardAttach::CWizardAttach( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, long style )
83 {
84     Create(parent, id, title, pos, style);
85 }
86 
87 /*!
88  * CWizardAttach creator
89  */
90 
Create(wxWindow * parent,wxWindowID id,const wxString &,const wxPoint & pos,long style)91 bool CWizardAttach::Create( wxWindow* parent, wxWindowID id, const wxString& /* title */, const wxPoint& pos, long style )
92 {
93 
94 ////@begin CWizardAttach member initialisation
95     m_ProjectInfoPage = NULL;
96     m_ProjectPropertiesPage = NULL;
97     m_ProjectProcessingPage = NULL;
98     m_ProjectWelcomePage = NULL;
99     m_AccountManagerInfoPage = NULL;
100     m_AccountManagerPropertiesPage = NULL;
101     m_AccountManagerProcessingPage = NULL;
102     m_TermsOfUsePage = NULL;
103     m_AccountInfoPage = NULL;
104     m_CompletionPage = NULL;
105     m_CompletionErrorPage = NULL;
106     m_ErrNotDetectedPage = NULL;
107     m_ErrUnavailablePage = NULL;
108     m_ErrNoInternetConnectionPage = NULL;
109     m_ErrNotFoundPage = NULL;
110     m_ErrAlreadyExistsPage = NULL;
111     m_ErrProxyInfoPage = NULL;
112     m_ErrProxyPage = NULL;
113     m_ErrUserDisagreesPage = NULL;
114 ////@end CWizardAttach member initialisation
115 
116     // Cancel Checking
117     m_bCancelInProgress = false;
118 
119     // Wizard Detection
120 
121     IsAttachToProjectWizard = true;
122     IsChangeWCGApps = false;
123     IsFirstPass = false;
124     IsAccountManagerWizard = false;
125     IsAccountManagerUpdateWizard = false;
126 
127     // Global wizard status
128     project_config.clear();
129     account_in.clear();
130     account_out.clear();
131     account_created_successfully = false;
132     attached_to_project_successfully = false;
133     m_bCloseWhenCompleted = false;
134     m_strProjectName.Empty();
135     m_strProjectUrl.Empty();
136     m_strProjectAuthenticator.Empty();
137     m_strProjectSetupCookie.Empty();
138     m_strReturnURL.Empty();
139     m_bCredentialsCached = false;
140     m_bCredentialsDetected = false;
141     m_bCookieRequired = false;
142     m_strCookieFailureURL.Empty();
143 
144 
145     CSkinAdvanced*  pSkinAdvanced = wxGetApp().GetSkinManager()->GetAdvanced();
146     CSkinWizardATP* pSkinWizardATP = wxGetApp().GetSkinManager()->GetWizards()->GetWizardATP();
147 
148     wxASSERT(pSkinAdvanced);
149     wxASSERT(pSkinWizardATP);
150     wxASSERT(wxDynamicCast(pSkinAdvanced, CSkinAdvanced));
151     wxASSERT(wxDynamicCast(pSkinWizardATP, CSkinWizardATP));
152 
153 
154     wxString strTitle;
155     if (!pSkinWizardATP->GetWizardTitle().IsEmpty()) {
156         strTitle = pSkinWizardATP->GetWizardTitle();
157     } else {
158         strTitle = pSkinAdvanced->GetApplicationName();
159     }
160 
161 ////@begin CWizardAttach creation
162     CBOINCBaseWizard::Create( parent, id, strTitle, pos, style );
163 
164     CreateControls();
165 ////@end CWizardAttach creation
166 
167     return TRUE;
168 }
169 
170 /*!
171  * Control creation for CWizardAttach
172  */
173 
CreateControls()174 void CWizardAttach::CreateControls()
175 {
176     wxLogTrace(wxT("Function Start/End"), wxT("CWizardAttach::CreateControls - Function Begin"));
177 
178 ////@begin CWizardAttach content construction
179     CWizardAttach* itemWizard1 = this;
180 
181     m_AccountManagerInfoPage = new CAccountManagerInfoPage;
182     m_AccountManagerInfoPage->Create( itemWizard1 );
183     GetPageAreaSizer()->Add(m_AccountManagerInfoPage);
184 
185     m_AccountManagerPropertiesPage = new CAccountManagerPropertiesPage;
186     m_AccountManagerPropertiesPage->Create( itemWizard1 );
187     GetPageAreaSizer()->Add(m_AccountManagerPropertiesPage);
188 
189     m_AccountManagerProcessingPage = new CAccountManagerProcessingPage;
190     m_AccountManagerProcessingPage->Create( itemWizard1 );
191     GetPageAreaSizer()->Add(m_AccountManagerProcessingPage);
192 
193     m_ProjectInfoPage = new CProjectInfoPage;
194     m_ProjectInfoPage->Create( itemWizard1 );
195     GetPageAreaSizer()->Add(m_ProjectInfoPage);
196 
197     m_ProjectPropertiesPage = new CProjectPropertiesPage;
198     m_ProjectPropertiesPage->Create( itemWizard1 );
199     GetPageAreaSizer()->Add(m_ProjectPropertiesPage);
200 
201     m_ProjectProcessingPage = new CProjectProcessingPage;
202     m_ProjectProcessingPage->Create( itemWizard1 );
203     GetPageAreaSizer()->Add(m_ProjectProcessingPage);
204 
205     m_ProjectWelcomePage = new CProjectWelcomePage;
206     m_ProjectWelcomePage->Create( itemWizard1 );
207     GetPageAreaSizer()->Add(m_ProjectWelcomePage);
208 
209     m_AccountInfoPage = new CAccountInfoPage;
210     m_AccountInfoPage->Create( itemWizard1 );
211     GetPageAreaSizer()->Add(m_AccountInfoPage);
212 
213     m_TermsOfUsePage = new CTermsOfUsePage;
214     m_TermsOfUsePage->Create( itemWizard1 );
215     GetPageAreaSizer()->Add(m_TermsOfUsePage);
216 
217     m_CompletionPage = new CCompletionPage;
218     m_CompletionPage->Create( itemWizard1 );
219     GetPageAreaSizer()->Add(m_CompletionPage);
220 
221     m_CompletionErrorPage = new CCompletionErrorPage;
222     m_CompletionErrorPage->Create( itemWizard1 );
223     GetPageAreaSizer()->Add(m_CompletionErrorPage);
224 
225     m_ErrNotDetectedPage = new CErrNotDetectedPage;
226     m_ErrNotDetectedPage->Create( itemWizard1 );
227     GetPageAreaSizer()->Add(m_ErrNotDetectedPage);
228 
229     m_ErrUnavailablePage = new CErrUnavailablePage;
230     m_ErrUnavailablePage->Create( itemWizard1 );
231     GetPageAreaSizer()->Add(m_ErrUnavailablePage);
232 
233     m_ErrNoInternetConnectionPage = new CErrNoInternetConnectionPage;
234     m_ErrNoInternetConnectionPage->Create( itemWizard1 );
235     GetPageAreaSizer()->Add(m_ErrNoInternetConnectionPage);
236 
237     m_ErrNotFoundPage = new CErrNotFoundPage;
238     m_ErrNotFoundPage->Create( itemWizard1 );
239     GetPageAreaSizer()->Add(m_ErrNotFoundPage);
240 
241     m_ErrAlreadyExistsPage = new CErrAlreadyExistsPage;
242     m_ErrAlreadyExistsPage->Create( itemWizard1 );
243     GetPageAreaSizer()->Add(m_ErrAlreadyExistsPage);
244 
245     m_ErrProxyInfoPage = new CErrProxyInfoPage;
246     m_ErrProxyInfoPage->Create( itemWizard1 );
247     GetPageAreaSizer()->Add(m_ErrProxyInfoPage);
248 
249     m_ErrProxyPage = new CErrProxyPage;
250     m_ErrProxyPage->Create( itemWizard1 );
251     GetPageAreaSizer()->Add(m_ErrProxyPage);
252 
253 ////@end CWizardAttach content construction
254 
255     wxLogTrace(wxT("Function Start/End"), wxT("CWizardAttach::CreateControls - Function End"));
256 }
257 
258 /*!
259  * Runs the wizard.
260  */
Run(wxString strProjectName,wxString strProjectURL,wxString strProjectAuthenticator,wxString strProjectInstitution,wxString strProjectDescription,wxString strProjectKnown,wxString strProjectSetupCookie,bool bAccountKeyDetected,bool bEmbedded)261 bool CWizardAttach::Run(
262         wxString strProjectName,
263         wxString strProjectURL,
264         wxString strProjectAuthenticator,
265         wxString strProjectInstitution,
266         wxString strProjectDescription,
267         wxString strProjectKnown,
268         wxString strProjectSetupCookie,
269         bool     bAccountKeyDetected,
270         bool     bEmbedded
271 ){
272     SetProjectName(strProjectName);
273     if (strProjectURL.size()) {
274         SetProjectURL(strProjectURL);
275         SetCredentialsCached(bAccountKeyDetected);
276     }
277     SetProjectInstitution(strProjectInstitution);
278     SetProjectDescription(strProjectDescription);
279     if (strProjectAuthenticator.size()) {
280         SetProjectAuthenticator(strProjectAuthenticator);
281     }
282     if (strProjectSetupCookie.size()) {
283         SetProjectSetupCookie(strProjectSetupCookie);
284     }
285     SetProjectKnown(strProjectKnown.length() > 0);
286 
287     if (strProjectURL.size() && strProjectAuthenticator.size() && !bAccountKeyDetected) {
288         SetCredentialsDetected(true);
289         SetCloseWhenCompleted(true);
290     }
291 
292     if (m_ProjectPropertiesPage && m_ProjectInfoPage && m_ProjectWelcomePage) {
293         IsAttachToProjectWizard = true;
294         IsAccountManagerWizard = false;
295         if (strProjectName.size() && strProjectURL.size() && ((strProjectSetupCookie.IsEmpty()) || !bEmbedded)) {
296             return RunWizard(m_ProjectWelcomePage);
297         } else if (strProjectURL.size() && (IsCredentialsCached() || IsCredentialsDetected() || (strProjectSetupCookie.size() && bEmbedded))) {
298             return RunWizard(m_ProjectPropertiesPage);
299         } else {
300             return RunWizard(m_ProjectInfoPage);
301         }
302     }
303 
304     return FALSE;
305 }
306 
307 
SyncToAccountManager()308 bool CWizardAttach::SyncToAccountManager() {
309     ACCT_MGR_INFO ami;
310     CMainDocument* pDoc = wxGetApp().GetDocument();
311 
312     wxASSERT(pDoc);
313     wxASSERT(wxDynamicCast(pDoc, CMainDocument));
314 
315     IsAttachToProjectWizard = false;
316     IsAccountManagerWizard = true;
317 
318     pDoc->rpc.acct_mgr_info(ami);
319 
320     if (ami.acct_mgr_url.size()) {
321         SetProjectName(wxString(ami.acct_mgr_name.c_str(), wxConvUTF8));
322         SetProjectURL(wxString(ami.acct_mgr_url.c_str(), wxConvUTF8));
323 
324         SetCredentialsCached(ami.have_credentials);
325         SetCookieRequired(ami.cookie_required);
326         SetCookieFailureURL(wxString(ami.cookie_failure_url.c_str(), wxConvUTF8));
327         if (IsCredentialsCached()) {
328             IsAccountManagerUpdateWizard = true;
329         }
330     }
331 
332     if (ami.acct_mgr_url.size() && !m_bCredentialsCached) {
333         std::string login;
334         std::string password_hash;
335         std::string return_url;
336 
337         if (detect_account_manager_credentials(ami.acct_mgr_url, login, password_hash, return_url)) {
338             wxString strLogin;
339             wxString strPasswordHash;
340             wxString strReturnURL;
341 
342             strLogin = wxURL::Unescape(wxString(login.c_str(), wxConvUTF8));
343             strPasswordHash = wxURL::Unescape(wxString(password_hash.c_str(), wxConvUTF8));
344             strReturnURL = wxURL::Unescape(wxString(return_url.c_str(), wxConvUTF8));
345 
346             SetCredentialsDetected(true);
347             SetReturnURL(strReturnURL);
348             SetAccountEmailAddress(strLogin);
349             SetAccountUsername(strLogin);
350             SetAccountPassword(
351                 wxString(_T("hash:")) + strPasswordHash
352             );
353         }
354     }
355 
356     if (m_AccountManagerInfoPage || m_AccountManagerPropertiesPage) {
357         IsAttachToProjectWizard = false;
358         IsAccountManagerWizard = true;
359         if (!ami.acct_mgr_url.size()) {
360             return RunWizard(m_AccountManagerInfoPage);
361         } else {
362             return RunWizard(m_AccountManagerPropertiesPage);
363         }
364     }
365 
366     return FALSE;
367 }
368 
369 /*!
370  * Should we show tooltips?
371  */
372 
ShowToolTips()373 bool CWizardAttach::ShowToolTips()
374 {
375     return TRUE;
376 }
377 
378 /*!
379  * Get bitmap resources
380  */
381 
GetBitmapResource(const wxString & WXUNUSED (name))382 wxBitmap CWizardAttach::GetBitmapResource( const wxString& WXUNUSED(name) )
383 {
384     // Bitmap retrieval
385 ////@begin CWizardAttach bitmap retrieval
386     return wxNullBitmap;
387 ////@end CWizardAttach bitmap retrieval
388 }
389 
390 /*!
391  * Get icon resources
392  */
393 
GetIconResource(const wxString & WXUNUSED (name))394 wxIcon CWizardAttach::GetIconResource( const wxString& WXUNUSED(name) )
395 {
396     // Icon retrieval
397 ////@begin CWizardAttach icon retrieval
398     return wxNullIcon;
399 ////@end CWizardAttach icon retrieval
400 }
401 
402 /*!
403  * Determine if the wizard page has a next page
404  */
405 
HasNextPage(wxWizardPageEx * page)406 bool CWizardAttach::HasNextPage( wxWizardPageEx* page )
407 {
408     bool bNoNextPageDetected = false;
409 
410     bNoNextPageDetected |= (page == m_CompletionPage);
411     bNoNextPageDetected |= (page == m_CompletionErrorPage);
412     bNoNextPageDetected |= (page == m_ErrNotDetectedPage);
413     bNoNextPageDetected |= (page == m_ErrUnavailablePage);
414     bNoNextPageDetected |= (page == m_ErrNoInternetConnectionPage);
415     bNoNextPageDetected |= (page == m_ErrAlreadyExistsPage);
416 
417     if (bNoNextPageDetected)
418         return false;
419     return true;
420 }
421 
422 /*!
423  * Determine if the wizard page has a previous page
424  */
425 
HasPrevPage(wxWizardPageEx * page)426 bool CWizardAttach::HasPrevPage( wxWizardPageEx* page )
427 {
428     bool bNoPrevPageDetected = false;
429 
430     bNoPrevPageDetected |= (page == m_ProjectWelcomePage);
431     bNoPrevPageDetected |= (page == m_ProjectInfoPage);
432     bNoPrevPageDetected |= (page == m_AccountManagerInfoPage);
433     bNoPrevPageDetected |= (page == m_CompletionPage);
434     bNoPrevPageDetected |= (page == m_CompletionErrorPage);
435 
436     if (bNoPrevPageDetected)
437         return false;
438     return true;
439 }
440 
441 /*!
442  * Translate a Page ID into the wxWizardPageEx instance pointer.
443  */
444 
TranslatePage(unsigned long ulPageID)445 wxWizardPageEx* CWizardAttach::TranslatePage(unsigned long ulPageID) {
446     wxWizardPageEx* pPage = NULL;
447 
448     if (ID_PROJECTINFOPAGE == ulPageID)
449         pPage = m_ProjectInfoPage;
450 
451     if (ID_PROJECTPROPERTIESPAGE == ulPageID)
452         pPage = m_ProjectPropertiesPage;
453 
454     if (ID_PROJECTPROCESSINGPAGE == ulPageID)
455         pPage = m_ProjectProcessingPage;
456 
457     if (ID_PROJECTWELCOMEPAGE == ulPageID)
458         pPage = m_ProjectWelcomePage;
459 
460     if (ID_ACCOUNTMANAGERINFOPAGE == ulPageID)
461         pPage = m_AccountManagerInfoPage;
462 
463     if (ID_ACCOUNTMANAGERPROPERTIESPAGE == ulPageID)
464         pPage = m_AccountManagerPropertiesPage;
465 
466     if (ID_ACCOUNTMANAGERPROCESSINGPAGE == ulPageID)
467         pPage = m_AccountManagerProcessingPage;
468 
469     if (ID_TERMSOFUSEPAGE == ulPageID)
470         pPage = m_TermsOfUsePage;
471 
472     if (ID_ACCOUNTINFOPAGE == ulPageID)
473         pPage = m_AccountInfoPage;
474 
475     if (ID_COMPLETIONPAGE == ulPageID)
476         pPage = m_CompletionPage;
477 
478     if (ID_COMPLETIONERRORPAGE == ulPageID)
479         pPage = m_CompletionErrorPage;
480 
481     if (ID_ERRNOTDETECTEDPAGE == ulPageID)
482         pPage = m_ErrNotDetectedPage;
483 
484     if (ID_ERRUNAVAILABLEPAGE == ulPageID)
485         pPage = m_ErrUnavailablePage;
486 
487     if (ID_ERRNOINTERNETCONNECTIONPAGE == ulPageID)
488         pPage = m_ErrNoInternetConnectionPage;
489 
490     if (ID_ERRNOTFOUNDPAGE == ulPageID)
491         pPage = m_ErrNotFoundPage;
492 
493     if (ID_ERRALREADYEXISTSPAGE == ulPageID)
494         pPage = m_ErrAlreadyExistsPage;
495 
496     if (ID_ERRPROXYINFOPAGE == ulPageID)
497         pPage = m_ErrProxyInfoPage;
498 
499     if (ID_ERRPROXYPAGE == ulPageID)
500         pPage = m_ErrProxyPage;
501 
502     return pPage;
503 }
504 
505 /*!
506  * Remove the page transition from the stack.
507  */
PopPageTransition()508 wxWizardPageEx* CWizardAttach::PopPageTransition() {
509     wxWizardPageEx* pPage = NULL;
510     if (GetCurrentPage()) {
511         if (!m_PageTransition.empty()) {
512             pPage = m_PageTransition.top();
513 
514             wxLogTrace(wxT("Function Status"), wxT("CWizardAttach::PopPageTransition - Popping Page: '%p'"), pPage);
515             m_PageTransition.pop();
516 
517             // TODO: Figure out the best way to handle the situation where the wizard has been launched with a
518             //   project init file and the volunteer hits the back button on the m_ProjectPropertiesPage/
519             //   m_AccountManagerPropertiesPage page.  Ideally they go back to the m_ProjectInfoPage/
520             //   m_AccountManagerInfoPage page, but since the wizard launched in automatic attach mode
521             //   that page isn't on the stack and the manager crashes.
522             //
523             //   It is probably enough to just push the correct InfoPage on the stack before launching the
524             //   wizard in automatic mode.  I need to think about it some more.
525             //
526             if ((pPage == m_ProjectPropertiesPage) || (pPage == m_ProjectProcessingPage) ||
527                 (pPage == m_AccountManagerPropertiesPage) || (pPage == m_AccountManagerProcessingPage))
528             {
529                 // We want to go back to the page before we attempted to communicate
530                 //   with any server.
531                 pPage = m_PageTransition.top();
532 
533                 wxLogTrace(wxT("Function Status"), wxT("CWizardAttach::PopPageTransition - Popping Page: '%p'"), pPage);
534                 m_PageTransition.pop();
535 
536             }
537             wxASSERT(pPage);
538             return pPage;
539         }
540     }
541     return NULL;
542 }
543 
544 
545 /*!
546  * Push a page onto the stack.
547  */
548 
PushPage(unsigned long ulPageID)549 wxWizardPageEx* CWizardAttach::PushPage( unsigned long ulPageID ) {
550     if (GetCurrentPage()) {
551         wxWizardPageEx* pPage = TranslatePage(ulPageID);
552         if (pPage) {
553             wxLogTrace(wxT("Function Status"), wxT("CWizardAttach::PushPage - Pushing Page: '%p'"), pPage);
554             m_PageTransition.push(pPage);
555             return pPage;
556         }
557     }
558     return NULL;
559 }
560 
561 
562 /*!
563  * Add the page transition to the stack.
564  */
PushPageTransition(wxWizardPageEx * pCurrentPage,unsigned long ulPageID)565 wxWizardPageEx* CWizardAttach::PushPageTransition( wxWizardPageEx* pCurrentPage, unsigned long ulPageID ) {
566     if (GetCurrentPage()) {
567         wxWizardPageEx* pPage = TranslatePage(ulPageID);
568         if (pPage) {
569             if (m_PageTransition.empty()) {
570                 wxLogTrace(wxT("Function Status"), wxT("CWizardAttach::PushPageTransition - Pushing Page: '%p'"), pPage);
571                 m_PageTransition.push(NULL);
572             }
573             if (m_PageTransition.top() != pCurrentPage) {
574                 wxLogTrace(wxT("Function Status"), wxT("CWizardAttach::PushPageTransition - Pushing Page: '%p'"), pPage);
575                 m_PageTransition.push(pCurrentPage);
576             }
577             return pPage;
578         }
579     }
580     return NULL;
581 }
582 
_ProcessCancelEvent(wxWizardExEvent & event)583 void CWizardAttach::_ProcessCancelEvent( wxWizardExEvent& event ) {
584 
585     bool bCancelWithoutNextPage = false;
586     wxWizardPageEx* page = GetCurrentPage();
587 
588     m_bCancelInProgress = true;
589 
590     int iRetVal = wxGetApp().SafeMessageBox(
591         _("Do you really want to cancel?"),
592         _("Question"),
593         wxICON_QUESTION | wxYES_NO,
594         this
595     );
596 
597     // Reenable the next and back buttons if they have been disabled
598     GetNextButton()->Enable(HasNextPage(page));
599     GetBackButton()->Enable(HasPrevPage(page));
600 
601     // Generic rules
602     bCancelWithoutNextPage |= (page == m_ErrNotDetectedPage);
603     bCancelWithoutNextPage |= (page == m_ErrUnavailablePage);
604     bCancelWithoutNextPage |= (page == m_ErrNoInternetConnectionPage);
605 
606     if (IsAttachToProjectWizard) {
607         bCancelWithoutNextPage |= (page == m_ErrAlreadyExistsPage);
608     } else {
609         bCancelWithoutNextPage |= (page == m_ProjectWelcomePage);
610    }
611 
612     if (wxYES != iRetVal) {
613         event.Veto();
614         m_bCancelInProgress = false;
615     } else {
616         m_bCancelInProgress = true;
617     }
618 }
619 
620 /*!
621  * wxEVT_WIZARD_FINISHED event handler for ID_ATTACHPROJECTWIZARD
622  */
623 
OnFinished(wxWizardExEvent & event)624 void CWizardAttach::OnFinished( wxWizardExEvent& event ) {
625 
626     if (IsAccountManagerWizard) {
627         // Attached to an account manager
628         if (!GetReturnURL().empty() && GetAttachedToProjectSuccessfully()) {
629             wxLaunchDefaultBrowser(GetReturnURL());
630         }
631     } else {
632         // Attached to a project
633         if (GetAccountCreatedSuccessfully() && GetAttachedToProjectSuccessfully()) {
634             wxLaunchDefaultBrowser(GetProjectURL() + wxT("account_finish.php?auth=") + GetProjectAuthenticator());
635         }
636     }
637 
638     // Let the framework clean things up.
639     event.Skip();
640 }
641 
642