// 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);
}