// carddav-processdata.cpp - CardDAV Object - Process Data subroutines. // // (c) 2012-2015 Xestia Software Development. // // This file is part of Xestia Address Book. // // Xestia Address Book 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 Address Book 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 Address Book. If not, see #include "carddav.h" #include "../version.h" #include #include #include #include #include #include #include #include "../vcard/vcard.h" #include "../common/dirs.h" void CardDAV::ProcessDataThread(){ PageData.Clear(); PageHeader.Clear(); SSLStatus = TRUE; AuthPassed = TRUE; AbortConnection = FALSE; CURL *conn; CURLcode conncode; wxString ServerAddressURL; wxString ServerAuth; wxString ServerAddressSSL; wxString ServerAddressNormal; conn = curl_easy_init(); struct CardDAVCURLPasser { CardDAV *Data; bool HeaderMode = TRUE; } CardDAVHeader, CardDAVFooter; CardDAVHeader.Data = this; CardDAVHeader.HeaderMode = TRUE; CardDAVFooter.Data = this; CardDAVFooter.HeaderMode = FALSE; wxString Data1; wxString Data2; wxString ETag; wxString ETagOriginal; wxString ETagServer; ServerAddressURL = ServerAddress + wxT(":") + wxString::Format(wxT("%i"), ServerPort) + wxT("/") + ServerPrefix + ServerFilenameLocation; ServerAddressSSL = wxT("https://") + ServerAddressURL; ServerAddressNormal = wxT("http://") + ServerAddressURL; ServerAuth = ServerUser + wxT(":") + ServerPass; // Try SSL first. /* char *ServerAdrSSLChar = new char[(ServerAddressSSL.Length() - 1)]; //memset(ServerAdrSSLChar, 0, ServerAddressSSL.Length()); strncpy(ServerAdrSSLChar, (const char*)ServerAddressSSL.mb_str(wxConvUTF8), (ServerAddressSSL.Length() - 1)); char *ServerAdrNorChar = new char[(ServerAddressNormal.Length() - 1)]; //memset(ServerAdrNorChar, 0, ServerAddressSSL.Length()); strncpy(ServerAdrNorChar, (const char*)ServerAddressNormal.mb_str(wxConvUTF8), (ServerAddressNormal.Length() - 1)); char *ServerAuthChar = new char[(ServerAuth.Length() - 1)]; //memset(ServerAuthChar, 0, ServerAddressSSL.Length()); strncpy(ServerAuthChar, (const char*)ServerAuth.mb_str(wxConvUTF8), (ServerAuth.Length() - 1)); */ //std::string WriteDataString = std::string(ServerUploadData.mb_str()); std::map::iterator ActIter; struct UploadDataStruc UploadData; ActIter = ActivityListPtr->find((int)ItemIndex); // Update result flag. ActIter->second = 1; // Setup the request mode if it is not empty. if (!ServerMethod.IsEmpty()){ curl_easy_setopt(conn, CURLOPT_CUSTOMREQUEST, (const char*)ServerMethod.mb_str(wxConvUTF8)); } if (ServerSSL){ wxString ServerCertFilename; bool MatchingCert = FALSE; curl_easy_setopt(conn, CURLOPT_URL, (const char*)ServerAddressSSL.mb_str(wxConvUTF8)); curl_easy_setopt(conn, CURLOPT_NOPROGRESS, 0); curl_easy_setopt(conn, CURLOPT_HTTPAUTH, CURLAUTH_ANY); curl_easy_setopt(conn, CURLOPT_TIMEOUT, 60); curl_easy_setopt(conn, CURLOPT_FAILONERROR, TRUE); curl_easy_setopt(conn, CURLOPT_USERAGENT, XSDAB_USERAGENT); curl_easy_setopt(conn, CURLOPT_USERPWD, (const char*)ServerAuth.mb_str(wxConvUTF8)); curl_easy_setopt(conn, CURLOPT_WRITEFUNCTION, WritebackFunc); curl_easy_setopt(conn, CURLOPT_WRITEDATA, &PageData); curl_easy_setopt(conn, CURLOPT_WRITEHEADER, &PageHeader); curl_easy_setopt(conn, CURLOPT_PROGRESSDATA, this); curl_easy_setopt(conn, CURLOPT_PROGRESSFUNCTION, ProgressFunc); curl_easy_setopt(conn, CURLOPT_NOSIGNAL, 1); if (UploadMode == TRUE){ UploadData.readptr = &ServerUploadData; UploadData.sizeleft = ServerUploadData.Len(); curl_easy_setopt(conn, CURLOPT_UPLOAD, 1); curl_easy_setopt(conn, CURLOPT_READDATA, &UploadData); curl_easy_setopt(conn, CURLOPT_READFUNCTION, UploadReadFunc); } ServerCertFilename = GetAccountDir(ServerAccount, TRUE); if (wxFile::Exists(ServerCertFilename) == TRUE){ curl_easy_setopt(conn, CURLOPT_SSL_VERIFYPEER, 1); curl_easy_setopt(conn, CURLOPT_SSL_VERIFYHOST, 2); curl_easy_setopt(conn, CURLOPT_CAINFO, (const char*)ServerCertFilename.mb_str(wxConvUTF8)); } //UploadData.readptr = &CardDAVDataQuery; //UploadData.sizeleft = CardDAVDataQuery.Len(); //curl_easy_setopt(conn, CURLOPT_UPLOAD, 1); //curl_easy_setopt(conn, CURLOPT_READDATA, &UploadData); //curl_easy_setopt(conn, CURLOPT_READFUNCTION, UploadReadFunc); //curl_easy_setopt(conn, CURLOPT_WRITEFUNCTION, writefunc); claconncode = (curl_easy_perform(conn)); // If CURLE_PEER_FAILED_VERIFICATION is returned, retry without // the local certificate in use. if (claconncode == CURLE_PEER_FAILED_VERIFICATION){ curl_easy_cleanup(conn); conn = curl_easy_init(); curl_easy_setopt(conn, CURLOPT_URL, (const char*)ServerAddressSSL.mb_str(wxConvUTF8)); curl_easy_setopt(conn, CURLOPT_NOPROGRESS, 0); curl_easy_setopt(conn, CURLOPT_HTTPAUTH, CURLAUTH_ANY); curl_easy_setopt(conn, CURLOPT_TIMEOUT, 60); curl_easy_setopt(conn, CURLOPT_FAILONERROR, TRUE); curl_easy_setopt(conn, CURLOPT_USERAGENT, XSDAB_USERAGENT); curl_easy_setopt(conn, CURLOPT_USERPWD, (const char*)ServerAuth.mb_str(wxConvUTF8)); curl_easy_setopt(conn, CURLOPT_WRITEFUNCTION, WritebackFunc); curl_easy_setopt(conn, CURLOPT_WRITEDATA, &PageData); curl_easy_setopt(conn, CURLOPT_WRITEHEADER, &PageHeader); curl_easy_setopt(conn, CURLOPT_PROGRESSDATA, this); curl_easy_setopt(conn, CURLOPT_PROGRESSFUNCTION, ProgressFunc); curl_easy_setopt(conn, CURLOPT_NOSIGNAL, 1); if (UploadMode == TRUE){ UploadData.readptr = &ServerUploadData; UploadData.sizeleft = ServerUploadData.Len(); curl_easy_setopt(conn, CURLOPT_UPLOAD, 1); curl_easy_setopt(conn, CURLOPT_READDATA, &UploadData); curl_easy_setopt(conn, CURLOPT_READFUNCTION, UploadReadFunc); } claconncode = (curl_easy_perform(conn)); // If claconncode is CURLE_OK then delete the certificate file as that // is no longer needed. if (claconncode == CURLE_OK){ // Delete the certificate file. wxRemoveFile(ServerCertFilename); } } // Check if it fails with a CURLE_SSL_CACERT then compare // the certificates as PEM files. if (claconncode == CURLE_SSL_CACERT && wxFile::Exists(ServerCertFilename) == TRUE){ //curl_easy_cleanup(conn); //conn = curl_easy_init(); CURL *sslerrconn; sslerrconn = curl_easy_init(); CURLcode sslerrconncode; //claconncode = (curl_easy_perform(conn)); wxString ServerAddressOnly = wxT("https://") + ServerAddress + wxT(":") + wxString::Format(wxT("%i"), ServerPort) + wxT("/"); curl_easy_setopt(sslerrconn, CURLOPT_URL, (const char*)ServerAddressOnly.mb_str(wxConvUTF8)); curl_easy_setopt(sslerrconn, CURLOPT_NOPROGRESS, 0); curl_easy_setopt(sslerrconn, CURLOPT_HTTPAUTH, CURLAUTH_ANY); curl_easy_setopt(sslerrconn, CURLOPT_TIMEOUT, 60); curl_easy_setopt(sslerrconn, CURLOPT_FAILONERROR, TRUE); curl_easy_setopt(sslerrconn, CURLOPT_USERAGENT, XSDAB_USERAGENT); curl_easy_setopt(sslerrconn, CURLOPT_WRITEFUNCTION, WritebackFunc); curl_easy_setopt(sslerrconn, CURLOPT_WRITEDATA, &PageData); curl_easy_setopt(sslerrconn, CURLOPT_WRITEHEADER, &PageHeader); curl_easy_setopt(sslerrconn, CURLOPT_PROGRESSDATA, this); curl_easy_setopt(sslerrconn, CURLOPT_PROGRESSFUNCTION, ProgressFunc); curl_easy_setopt(sslerrconn, CURLOPT_NOSIGNAL, 1); curl_easy_setopt(sslerrconn, CURLOPT_SSL_VERIFYPEER, 0); curl_easy_setopt(sslerrconn, CURLOPT_CERTINFO, 1); wxString SSLLocalData; wxString SSLServerData; sslerrconncode = (curl_easy_perform(sslerrconn)); SSLCertCol = BuildSSLCollection(sslerrconn); std::map::iterator SSLCDIter = SSLCertCol.SSLCollection.find(0); std::multimap::iterator SSLDataIter = SSLCDIter->second.CertData.find(wxT("Cert")); wxFFile SSLLocalFile; #if wxABI_VERSION < 20900 SSLLocalFile.Open(ServerCertFilename.c_str(), wxT("r")); #else SSLLocalFile.Open(ServerCertFilename, wxT("r")); #endif // Load the recovery database for tasks not done. if (SSLLocalFile.IsOpened() == TRUE){ // Check if we are using wxWidgets version 2.8 or less and // execute the required command accordingly. SSLLocalFile.ReadAll(&SSLLocalData, wxConvAuto()); } SSLServerData = SSLDataIter->second; if (SSLLocalData == SSLServerData){ // Server key matches with local key so retry with CURLOPT_SSL_VERIFYPEER // and CURLOPT_SSL_VERIFYHOST off. curl_easy_cleanup(conn); conn = curl_easy_init(); PageData.clear(); PageHeader.clear(); curl_easy_setopt(conn, CURLOPT_URL, (const char*)ServerAddressSSL.mb_str(wxConvUTF8)); curl_easy_setopt(conn, CURLOPT_NOPROGRESS, 0); curl_easy_setopt(conn, CURLOPT_HTTPAUTH, CURLAUTH_ANY); curl_easy_setopt(conn, CURLOPT_TIMEOUT, 60); curl_easy_setopt(conn, CURLOPT_FAILONERROR, TRUE); curl_easy_setopt(conn, CURLOPT_USERAGENT, XSDAB_USERAGENT); curl_easy_setopt(conn, CURLOPT_USERPWD, (const char*)ServerAuth.mb_str(wxConvUTF8)); curl_easy_setopt(conn, CURLOPT_WRITEFUNCTION, WritebackFunc); curl_easy_setopt(conn, CURLOPT_WRITEDATA, &PageData); curl_easy_setopt(conn, CURLOPT_WRITEHEADER, &PageHeader); curl_easy_setopt(conn, CURLOPT_PROGRESSDATA, this); curl_easy_setopt(conn, CURLOPT_PROGRESSFUNCTION, ProgressFunc); curl_easy_setopt(conn, CURLOPT_NOSIGNAL, 1); if (UploadMode == TRUE){ UploadData.readptr = &ServerUploadData; UploadData.sizeleft = ServerUploadData.Len(); curl_easy_setopt(conn, CURLOPT_UPLOAD, 1); curl_easy_setopt(conn, CURLOPT_READDATA, &UploadData); curl_easy_setopt(conn, CURLOPT_READFUNCTION, UploadReadFunc); } curl_easy_setopt(conn, CURLOPT_SSL_VERIFYHOST, 0); curl_easy_setopt(conn, CURLOPT_SSL_VERIFYPEER, 0); claconncode = (curl_easy_perform(conn)); MatchingCert = TRUE; } if (MatchingCert == FALSE){ claconncode = CURLE_SSL_CACERT; return; } curl_easy_cleanup(sslerrconn); } // Sort out SSL error. // When SSL cert error occurs, connect again and fetch certificates. // Display a message to the user explaining that an invalid // certificate has been given and let the user decide what // to do next. if (claconncode == CURLE_OK){ } else if (claconncode == CURLE_SSL_CACERT || claconncode == CURLE_PEER_FAILED_VERIFICATION){ CURL *sslerrconn; sslerrconn = curl_easy_init(); CURLcode sslerrconncode; wxString ServerAddressOnly = wxT("https://") + ServerAddress + wxT(":") + wxString::Format(wxT("%i"), ServerPort) + wxT("/"); // Replace conn with sslerrconn! curl_easy_setopt(sslerrconn, CURLOPT_URL, (const char*)ServerAddressOnly.mb_str(wxConvUTF8)); curl_easy_setopt(sslerrconn, CURLOPT_NOPROGRESS, 0); curl_easy_setopt(sslerrconn, CURLOPT_HTTPAUTH, CURLAUTH_ANY); curl_easy_setopt(sslerrconn, CURLOPT_TIMEOUT, 60); curl_easy_setopt(sslerrconn, CURLOPT_FAILONERROR, TRUE); curl_easy_setopt(sslerrconn, CURLOPT_USERAGENT, XSDAB_USERAGENT); curl_easy_setopt(sslerrconn, CURLOPT_WRITEFUNCTION, WritebackFunc); curl_easy_setopt(sslerrconn, CURLOPT_WRITEDATA, &PageData); curl_easy_setopt(sslerrconn, CURLOPT_WRITEHEADER, &PageHeader); curl_easy_setopt(sslerrconn, CURLOPT_PROGRESSDATA, this); curl_easy_setopt(sslerrconn, CURLOPT_PROGRESSFUNCTION, ProgressFunc); curl_easy_setopt(sslerrconn, CURLOPT_NOSIGNAL, 1); curl_easy_setopt(sslerrconn, CURLOPT_SSL_VERIFYPEER, 0); curl_easy_setopt(sslerrconn, CURLOPT_CERTINFO, 1); sslerrconncode = (curl_easy_perform(sslerrconn)); SSLCertCol = BuildSSLCollection(sslerrconn); SSLCertCol.SuccessCode = 1; return; } else if (claconncode == CURLE_HTTP_RETURNED_ERROR){ fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(claconncode)); int http_code = 0; curl_easy_getinfo(conn, CURLINFO_RESPONSE_CODE, &http_code); fprintf(stderr, "Error code was: %d\n", http_code); return; } else { fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(claconncode)); int http_code = 0; curl_easy_getinfo(conn, CURLINFO_RESPONSE_CODE, &http_code); fprintf(stderr, "Error code was: %d\n", http_code); return; } } else { // No SSL. curl_easy_setopt(conn, CURLOPT_URL, (const char*)ServerAddressNormal.mb_str(wxConvUTF8)); curl_easy_setopt(conn, CURLOPT_NOPROGRESS, 0); curl_easy_setopt(conn, CURLOPT_HTTPAUTH, CURLAUTH_ANY); curl_easy_setopt(conn, CURLOPT_TIMEOUT, 60); curl_easy_setopt(conn, CURLOPT_FAILONERROR, TRUE); curl_easy_setopt(conn, CURLOPT_USERAGENT, XSDAB_USERAGENT); curl_easy_setopt(conn, CURLOPT_USERPWD, (const char*)ServerAuth.mb_str(wxConvUTF8)); curl_easy_setopt(conn, CURLOPT_WRITEFUNCTION, WritebackFunc); curl_easy_setopt(conn, CURLOPT_WRITEDATA, &PageData); curl_easy_setopt(conn, CURLOPT_WRITEHEADER, &PageHeader); curl_easy_setopt(conn, CURLOPT_PROGRESSDATA, this); curl_easy_setopt(conn, CURLOPT_PROGRESSFUNCTION, ProgressFunc); curl_easy_setopt(conn, CURLOPT_NOSIGNAL, 1); if (UploadMode == TRUE){ UploadData.readptr = &ServerUploadData; UploadData.sizeleft = ServerUploadData.Len(); curl_easy_setopt(conn, CURLOPT_UPLOAD, 1); curl_easy_setopt(conn, CURLOPT_READDATA, &UploadData); curl_easy_setopt(conn, CURLOPT_READFUNCTION, UploadReadFunc); } conncode = (curl_easy_perform(conn)); if (conncode == CURLE_OK){ // Process the server header response and look for // 'addressbook' within the DAV header. wxStringTokenizer wxSHeaderLines(PageHeader, wxT("\r\n")); wxString wxSHeaderLine; std::map DAVHeaderLines; while (wxSHeaderLines.HasMoreTokens()){ wxSHeaderLine = wxSHeaderLines.GetNextToken(); if (wxSHeaderLine.Mid(0, 5) == wxT("ETag:")){ ETagData = wxSHeaderLine.Mid(5); ETagData.Trim(); ETagData.Trim(FALSE); // Check for commas. if (ETagData.Mid(0, 1) == wxT("\"") && ETagData.Mid((ETagData.Len() - 1), 1) == wxT("\"")){ ETagData.Remove(0, 1); ETagData.RemoveLast(); } } if (wxSHeaderLine.Mid(0, 4) == wxT("DAV:")){ // Look for address book in the line. if (wxSHeaderLine.Find(wxT("addressbook")) != wxNOT_FOUND){ HasCalDAVSupport = TRUE; } } } // Get the ETag from the header. if (UploadMode == TRUE){ wxString PageHeaderLine; wxStringTokenizer PageHeaderSplit(PageHeader, wxT("\r\n")); if (PageHeaderSplit.HasMoreTokens()){ PageHeaderLine = PageHeaderSplit.GetNextToken(); } } ActIter->second = 4; return; } else if (conncode == CURLE_HTTP_RETURNED_ERROR){ curl_easy_getinfo(conn, CURLINFO_RESPONSE_CODE, &HTTPErrorCode); fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(conncode)); fprintf(stderr, "curl_easy_perform() HTTP code was: %i\n", GetHTTPCode()); ActIter->second = 2; return; } else { fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(conncode)); ActIter->second = 2; return; } } // Catch all. //ActIter->second = 1; *ServerResult = TRUE; return; } void CardDAV::ProcessData(){ std::thread ConnectThread(&CardDAV::ProcessDataThread, this); ConnectThread.detach(); }