// frmNewAccount.cpp - frmNewAccount form functions // // (c) 2016-2017 Xestia Software Development. // // This file is part of Xestia Calendar. // // Xestia Calendar is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by the // Free Software Foundation, version 3 of the license. // // Xestia Calendar is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License along // with Xestia Calendar. If not, see #include "frmNewAccount.h" DEFINE_EVENT_TYPE(UPDATERESULTS); DEFINE_EVENT_TYPE(RUNCALDAVTEST); BEGIN_EVENT_TABLE(frmNewAccount, wxDialog) EVT_COMMAND(wxID_ANY, UPDATERESULTS, frmNewAccount::UpdateResults) EVT_COMMAND(wxID_ANY, RUNCALDAVTEST, frmNewAccount::RunCalDAVTest) END_EVENT_TABLE() frmNewAccount::frmNewAccount( wxWindow* parent ) : frmNewAccountADT( parent ) { // Disable the previous button upon form creation. btnPrevious->Disable(); txtServerAddress->Disable(); txtServerPort->Disable(); txtUsername->Disable(); txtPassword->Disable(); chkUseSSL->Disable(); } void frmNewAccount::UpdateRequirements( wxCommandEvent& event ) { // Update the options. if (cmbServerType->GetCurrentSelection() == 1){ txtServerAddress->Enable(); txtServerPort->Enable(); txtUsername->Enable(); txtPassword->Enable(); chkUseSSL->Enable(); } else if (cmbServerType->GetCurrentSelection() == 0){ txtServerAddress->Disable(); txtServerPort->Disable(); txtUsername->Disable(); txtPassword->Disable(); chkUseSSL->Disable(); } } void frmNewAccount::Navigate( wxCommandEvent& event ) { if (event.GetId() == wxID_NEXT) pageSeek++; else pageSeek--; if (pageSeek == 1){ // Skip this page. btnPrevious->Disable(); btnNext->Enable(); tabConn->Hide(); tabFinish->Hide(); tabType->Show(); btnNext->SetLabel(_("Next >")); } else if (pageSeek == 2){ if (cmbServerType->GetCurrentSelection() == 0){ tabType->Hide(); tabConn->Hide(); tabFinish->Show(); szrNewAccount->RecalcSizes(); pageSeek = 2; btnNext->Disable(); btnPrevious->Enable(); btnNext->SetLabel(_("Finish")); return; } // Check if server address matches against the blacklist. // Bring up warning message if it does. if (CheckBlacklist(txtServerAddress->GetValue())){ int MessageBoxResult = wxMessageBox(_("The server with the address given does not support the CalDAV protocol properly and shouldn't be used.\n\nData loss is very likely.\n\nDo you still want to continue using this server?"), _("Server warning"), wxYES_NO, this); if (MessageBoxResult == wxNO){ pageSeek--; return; } } btnNext->Disable(); btnNext->SetLabel(_("Next >")); bool ServerResult = FALSE; bool ServerAction = FALSE; bool UseSSL = TRUE; wxString ServerMessage; // Connection test screen. tabType->Hide(); tabConn->Show(); tabFinish->Hide(); szrNewAccount->RecalcSizes(); btnPrevious->Disable(); // Reset screen. lblServerConnResult->SetLabel(wxT("")); lblServerResponse->SetLabel(wxT("")); lblServerSSLResult->SetLabel(wxT("")); lblServerSSLValid->SetLabel(wxT("")); lblAbleToLoginResult->SetLabel(wxT("")); lblCalDAVSupportResult->SetLabel(wxT("")); // Depending on account type, run the test. if (cmbServerType->GetCurrentSelection() == 1){ wxCommandEvent RunTest(RUNCALDAVTEST); wxPostEvent(this, RunTest); } } else if (pageSeek == 3){ // Finish screen. tabType->Hide(); tabConn->Hide(); tabFinish->Show(); szrNewAccount->RecalcSizes(); btnPrevious->Enable(); btnNext->SetLabel(_("Finish")); if (txtAccountName->IsEmpty() || txtAccountName->GetValue().Len() < 4 && pageSeek == 3){ btnNext->Disable(); } else { btnNext->Enable(); } } else if (pageSeek == 4){ // Finished. wxString xestiaCALPrefDirectory; wxString xestiaCALDirectory; wxString accountSettingsFile; //wxFile ASFile; srand(time(0)); int randomNumber = rand() % 32767; wxString randomNumberSuffix = wxString::Format(wxT("%i"), randomNumber); bool directoryCreated = FALSE; #if defined(__HAIKU__) //preffilename = wxT("noo"); #elif defined(__WIN32__) xestiaCALPrefDirectory = GetUserPrefDir(); xestiaCALDirectory = GetUserDir(); accountSettingsFile = xestiaCALPrefDirectory + wxT("accounts"); // Open the file for writing. wxFileConfig *cfgFile = new wxFileConfig("", "", accountSettingsFile); // Check if account name already exists and return an error message // if this is the case. wxString accountName; long itemIndex = 0; bool continueAcc; continueAcc = cfgFile->GetFirstGroup(accountName, itemIndex); while (continueAcc){ if (txtAccountName->GetValue() == accountName){ wxMessageBox(_("The selected account name is already used, please use another account name."), _("Account name already used"), wxICON_ERROR); return; } cfgFile->SetPath(wxT("/")); continueAcc = cfgFile->GetNextGroup(accountName, itemIndex); } wxString directoryName = txtAccountName->GetValue().Mid(0, 30) + randomNumberSuffix; if (cmbServerType->GetCurrentSelection() == 0){ // Create the account directory. if (wxMkdir(xestiaCALDirectory + wxT("\\accounts\\") + directoryName + wxT(".local"), 0740) == true){ WriteAccountDetails(cfgFile, wxT("Local"), directoryName); } else { wxMessageBox(_("An error occured whilst creating the account directory."), _("Cannot create account directory")); return; } } else if (cmbServerType->GetCurrentSelection() == 1){ // Create the account directory. if (wxMkdir(xestiaCALDirectory + wxT("\\accounts\\") + directoryName + wxT(".caldav"), 0740) == true){ WriteAccountDetails(cfgFile, wxT("CalDAV"), directoryName); } else { wxMessageBox(_("An error occured whilst creating the account directory."), _("Cannot create account directory")); return; } } delete cfgFile; cfgFile = NULL; *reloadAccountConfig = TRUE; #else xestiaCALPrefDirectory = GetUserPrefDir(); xestiaCALDirectory = GetUserDir(); accountSettingsFile = xestiaCALPrefDirectory + wxT("accounts"); // Open the file for writing. wxFileConfig *cfgFile = new wxFileConfig("", "", accountSettingsFile); // Check if account name already exists and return an error message // if this is the case. wxString accountName; long itemIndex = 0; bool continueAcc; continueAcc = cfgFile->GetFirstGroup(accountName, itemIndex); while (continueAcc){ if (txtAccountName->GetValue() == accountName){ wxMessageBox(_("The selected account name is already used, please use another account name."), _("Account name already used"), wxICON_ERROR); return; } cfgFile->SetPath(wxT("/")); continueAcc = cfgFile->GetNextGroup(accountName, itemIndex); } wxString directoryName = txtAccountName->GetValue().Mid(0, 30) + randomNumberSuffix; if (cmbServerType->GetCurrentSelection() == 0){ // Create the account directory. if (wxMkdir(xestiaCALDirectory + wxT("/accounts/") + directoryName + wxT(".Local"), 0740) == true){ WriteAccountDetails(cfgFile, wxT("Local"), directoryName); } else { wxMessageBox(_("An error occured whilst creating the account directory."), _("Cannot create account directory")); return; } } else if (cmbServerType->GetCurrentSelection() == 1){ // Create the account directory. wxString directoryName = txtAccountName->GetValue().Mid(0, 30) + randomNumberSuffix; if (wxMkdir(xestiaCALDirectory + wxT("/accounts/") + directoryName + wxT(".caldav"), 0740) == true){ WriteAccountDetails(cfgFile, wxT("CalDAV"), directoryName); } else { wxMessageBox(_("An error occured whilst creating the account directory."), _("Cannot create account directory")); return; } } delete cfgFile; cfgFile = nullptr; *reloadAccountConfig = true; #endif this->Close(); } } void frmNewAccount::CloseWindow( wxCommandEvent& event ) { // Close the window. *reloadAccountConfig = FALSE; this->Close(); } void frmNewAccount::SetupPointers(bool *ReloadAccountInc, CalendarDataStorage *dataStorage){ // Setup the pointers for the new account window. reloadAccountConfig = ReloadAccountInc; } void frmNewAccount::CheckAccountName( wxCommandEvent& event ) { // Check that the account name is valid. wxString checkAccName = txtAccountName->GetValue(); if ((txtAccountName->IsEmpty() && pageSeek == 2) || checkAccName.Len() < 4){ btnNext->Disable(); } else { btnNext->Enable(); } } void frmNewAccount::WriteAccountDetails(wxFileConfig *cfgFileIn, wxString accountType, wxString directoryName){ // Write the new account details. cfgFileIn->SetPath(txtAccountName->GetValue()); cfgFileIn->Write(wxT("address"), txtServerAddress->GetValue()); cfgFileIn->Write(wxT("port"), txtServerPort->GetValue()); cfgFileIn->Write(wxT("username"), txtUsername->GetValue()); cfgFileIn->Write(wxT("password"), txtPassword->GetValue()); cfgFileIn->Write(wxT("prefix"), serverPrefix); cfgFileIn->Write(wxT("accountdir"), directoryName); if (chkUseSSL->GetValue() == TRUE){ cfgFileIn->Write(wxT("ssl"), wxT("true")); } else { cfgFileIn->Write(wxT("ssl"), wxT("false")); } cfgFileIn->Write(wxT("refresh"), wxT("1800")); cfgFileIn->Write(wxT("type"), accountType); } void frmNewAccount::UpdateResults( wxCommandEvent &event ) { NewAccountResult *resultData = static_cast(event.GetClientData()); lblServerConnResult->SetLabel((resultData->Connected ? _("Successful") : _("Failed"))); lblServerResponse->SetLabel((resultData->ValidResponse ? _("Yes") : _("No"))); if (chkUseSSL->GetValue()) { lblServerSSLResult->SetLabel((resultData->SSLStatus ? _("Yes") : _("No"))); lblServerSSLValid->SetLabel((resultData->SSLVerified == COSSL_VERIFIED ? _("Yes") : _("No"))); } else { lblServerSSLResult->SetLabel(_("Not Applicable")); lblServerSSLValid->SetLabel(_("Not Applicable")); } lblAbleToLoginResult->SetLabel((resultData->AuthPassed ? _("Yes") : _("No"))); lblCalDAVSupportResult->SetLabel((resultData->CanProcess ? _("Yes") : _("No"))); if (resultData->ErrorMessage != "") { lblConnectionResultText->SetLabel(_("An error occured whilst connecting to the server: ") + resultData->ErrorMessage); } if (VerifyResultData(resultData)) { lblConnectionResultText->SetLabel(_("Successfully connected to the server. Press Next to set the account name.")); btnNext->Enable(true); } else { btnNext->Enable(false); } tabConn->Layout(); btnPrevious->Enable(true); delete resultData; resultData = nullptr; } bool frmNewAccount::VerifyResultData(NewAccountResult *resultData) { if (!resultData->Connected) return false; if (!resultData->ValidResponse) return false; if (chkUseSSL->GetValue()) { if (!resultData->SSLStatus) return false; if (resultData->SSLVerified != COSSL_VERIFIED) return false; } if (!resultData->AuthPassed) return false; if (!resultData->CanProcess) return false; return true; } void frmNewAccount::RunCalDAVTest( wxCommandEvent &event ) { NewAccountResult *resultData = new NewAccountResult; lblServerConnResult->SetLabel(_("Testing...")); lblCalDAVSupportResult->SetLabel(wxT("")); lblServerResponse->SetLabel(wxT("")); lblServerSSLResult->SetLabel(wxT("")); lblServerSSLValid->SetLabel(wxT("")); lblAbleToLoginResult->SetLabel(wxT("")); lblConnectionResultText->SetLabel(wxT("")); bool usingSSLBypass = false; // Setup a CalDAV connection object for testing. CalDAVConnectionData connData; connData.hostname = txtServerAddress->GetValue().ToStdString(); connData.port = wxAtoi(txtServerPort->GetValue()); connData.username = txtUsername->GetValue().ToStdString(); connData.password = txtPassword->GetValue().ToStdString(); connData.useSSL = chkUseSSL->GetValue() ? true : false; CalDAV testConnection; testConnection.SetupConnectionData(&connData); /*CardDAV2 TestConnection(txtServerAddress->GetValue().ToStdString(), wxAtoi(txtServerPort->GetValue()), txtUsername->GetValue().ToStdString(), txtPassword->GetValue().ToStdString(), chkUseSSL->GetValue() ? true : false);*/ // Test the connection. //testConnection.SetupConnectionObject(); CalDAVServerResult testConnectionResult = testConnection.Connect(false); // If server is using SSL, verify that the SSL connection is valid. if (testConnection.SSLVerify() == COSSL_UNABLETOVERIFY){ #if defined(__APPLE__) testConnection.BypassSSLVerification(true); CalDAVServerResult testConnection = testConnection.Connect(false); testConnection.BypassSSLVerification(false); int SSLResult = DisplayTrustPanel(&TestConnection); if (SSLResult != NSOKButton){ lblServerConnResult->SetLabel(_("Failed")); lblServerResponse->SetLabel(_("Not applicable")); lblServerSSLResult->SetLabel(_("Used")); lblServerSSLValid->SetLabel(_("No")); lblConnectionResultText->SetLabel(_("An error occured whilst connnecting: ") + TestConnection.GetErrorMessage()); btnPrevious->Enable(true); return; } else { // Evalulate the trust object. SecTrustResultType evalResult = ProcessResultType(&testConnection); switch(evalResult){ case kSecTrustResultProceed: lblServerSSLValid->SetLabel(_("Verified")); break; case kSecTrustResultConfirm: lblServerSSLValid->SetLabel(_("Verified (user)")); break; default: lblServerSSLValid->SetLabel(_("Unable to verify")); } lblServerResponse->SetLabel(_("Not applicable")); lblServerSSLResult->SetLabel(_("Used")); if (evalResult != kSecTrustResultProceed){ return; } } #elif defined(__WIN32__) testConnection.BypassSSLVerification(true); CalDAVServerResult testConnectionResult = testConnection.Connect(false); testConnection.BypassSSLVerification(false); bool modifiedCertificateData = false; CRYPTUI_VIEWCERTIFICATE_STRUCTW certificateDialogData = BuildCertificateData(&testConnection, (HWND)this->GetHandle()); if (!CryptUIDlgViewCertificate(&certificateDialogData, &modifiedCertificateData)){ wxMessageBox(_("An error occured while trying to open the certificate dialog."), _("Error opening Certificate Information dialog")); } if (modifiedCertificateData == false){ lblServerConnResult->SetLabel(_("Failed")); lblServerResponse->SetLabel(_("Not applicable")); lblServerSSLResult->SetLabel(_("Used")); lblServerSSLValid->SetLabel(_("No")); lblConnectionResultText->SetLabel(_("An error occured whilst connnecting: ") + testConnection.GetErrorMessage()); btnPrevious->Enable(true); return; } #else // Connect again and fetch SSL certificate information. testConnection.BypassSSLVerification(true); CalDAVServerResult testConnectionResult = testConnection.Connect(false); testConnection.BypassSSLVerification(false); SSLCertCollectionString certData = testConnection.BuildSSLCollection(); frmInvalidSSLCertificate *frmICPtr = new frmInvalidSSLCertificate(this); frmICPtr->LoadDataNew(certData, txtServerAddress->GetValue().ToStdString()); frmICPtr->ShowModal(); int sslResult = frmICPtr->GetResult(); // Clean up before processing response. delete frmICPtr; frmICPtr = nullptr; // Process the response from the user. if (sslResult == 1){ // Accept the Certificate. usingSSLBypass = true; testConnection.BypassSSLVerification(true); CalDAVServerResult testConnectionResult = testConnection.Connect(true); testConnection.BypassSSLVerification(false); } else if (sslResult == 2){ // Reject the certificate, abort the task and mark as failed. // TODO: Integrate into the code. //lblConnectionResultText->SetLabel(_("An error occured whilst connnecting: ") + CardDAVConn.GetErrorMessage() + wxString::Format(wxT(" (%i)\n%s"), sslcode, CardDAVConn.GetErrorBuffer().mb_str())); resultData->Connected = true; resultData->SSLStatus = true; resultData->SSLVerified = COSSL_UNABLETOVERIFY; resultData->ValidResponse = false; resultData->AuthPassed = false; resultData->CanProcess = false; resultData->ErrorMessage = _("Server is using self-signed certificate and was rejected."); wxCommandEvent resultsEvent(UPDATERESULTS); resultsEvent.SetClientData(resultData); wxPostEvent(this, resultsEvent); return; } #endif } if (usingSSLBypass == true){ testConnection.BypassSSLVerification(true); } testConnectionResult = testConnection.Connect(true); // Get the server prefix if the connection was successful. if (testConnectionResult.result == CALDAVQUERYRESULT_OK){ std::string receivedServerPrefix; receivedServerPrefix = testConnection.GetUserPrincipal(); serverPrefix = receivedServerPrefix; } CalDAVServerSupport testConnectionSupport = testConnection.GetServerSupport(); if (usingSSLBypass == true){ testConnection.BypassSSLVerification(false); } (testConnectionResult.result == CALDAVQUERYRESULT_OK || testConnectionResult.result == CALDAVQUERYRESULT_SSLFAILURE) ? resultData->Connected = true : resultData->Connected = false; resultData->SSLStatus = testConnection.CanDoSSL(); resultData->SSLVerified = testConnection.SSLVerify(); resultData->ValidResponse = testConnection.HasValidResponse(); resultData->AuthPassed = testConnection.AbleToLogin(); resultData->CanProcess = testConnectionSupport.basicSupport; resultData->ErrorMessage = testConnection.GetErrorMessage(); // Post event back confirming the tests. wxCommandEvent resultsEvent(UPDATERESULTS); resultsEvent.SetClientData(resultData); wxPostEvent(this, resultsEvent); }