From daa33d641181d15710614cad752187a87263bcc9 Mon Sep 17 00:00:00 2001 From: Steve Brokenshire Date: Sat, 20 Aug 2016 00:13:49 +0100 Subject: [PATCH] Initial version of CardDAV2 class Inherits from the ConnectionObject interface. --- source/carddav2/carddav2.cpp | 980 +++++++++++++++++++++++++++++++++++ source/carddav2/carddav2.h | 111 ++++ 2 files changed, 1091 insertions(+) create mode 100644 source/carddav2/carddav2.cpp create mode 100644 source/carddav2/carddav2.h diff --git a/source/carddav2/carddav2.cpp b/source/carddav2/carddav2.cpp new file mode 100644 index 0000000..f5bc2a3 --- /dev/null +++ b/source/carddav2/carddav2.cpp @@ -0,0 +1,980 @@ +// CardDAV2.cpp - CardDAV v2 class +// +// (c) 2012-2016 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 "carddav2.h" + +#include + +using namespace std; + +size_t CardDAV2::WritebackFunc(char *ptr, size_t size, size_t nmemb, void *stream){ + + return static_cast(stream)->WritebackFuncImplementation(ptr, size, nmemb, stream); + +} + +size_t CardDAV2::WritebackFuncImplementation(char *ptr, size_t size, size_t nmemb, void *stream){ + + // Writeback function for the CardDAV object. + + string *data = static_cast(stream); + data->append(ptr); + + // Get the SSL engine pointer and trust if required on certain operating systems. + + if (ServerSSL){ + +#if defined(__APPLE__) + + const struct curl_tlssessioninfo *TLSInfo; + CURLcode TLSCode; + CURL *Connection = GetConnectionObject(); + TLSCode = curl_easy_getinfo(Connection, CURLINFO_TLS_SSL_PTR, &TLSInfo); + + if (TLSInfo->internals != nullptr && TLSCode == CURLE_OK){ + SSLCopyPeerTrust((SSLContext*)TLSInfo->internals, &SecTrustObject); + } + +#elif defined(__WIN32__) + + const struct curl_tlssessioninfo *TLSInfo; + CURLcode TLSCode; + CURL *Connection = GetConnectionObject(); + TLSCode = curl_easy_getinfo(Connection, CURLINFO_TLS_SSL_PTR, &TLSInfo); + + if (TLSInfo->internals != nullptr && TLSCode == CURLE_OK){ + + // Free the previous certificate data. + + CertFreeCertificateContext(CertificateData); + + PCtxtHandle SSLHandle = (PCtxtHandle)TLSInfo->internals; + SECURITY_STATUS GetData = QueryContextAttributes(SSLHandle, SECPKG_ATTR_REMOTE_CERT_CONTEXT, &CertificateData); + + } + +#endif + + } + + return size * nmemb; + +} + +CardDAV2::~CardDAV2(){ + curl_easy_cleanup(ConnectionSession); + ConnectionSession = nullptr; +} + +#if defined(__APPLE__) + +#elif defined(__WIN32__) + +#else + +SSLCertCollectionString CardDAV2::BuildSSLCollection(){ + + // Build and return the SSL collection. + + SSLCertCollectionString SSLCertInfo; + + // Grab the certificate data. + + union { + struct curl_slist *certdata; + struct curl_certinfo *certinfo; + } certptr; + + certptr.certdata = NULL; + + curl_easy_getinfo(ConnectionSession, CURLINFO_CERTINFO, &certptr.certinfo); + + std::string CertPropName; + std::string CertPropValue; + + for (int i = 0; i < certptr.certinfo->num_of_certs; i++){ + + struct curl_slist *slist; + SSLCertDataString SSLCertDataInc; + + for (slist = certptr.certinfo->certinfo[i]; slist; slist = slist->next){ + + // Using wxStringTokenizer from wxWidgets. + + wxStringTokenizer CertDataInc(wxString::FromUTF8(slist->data), ":"); + + // Get first token as the property name. + + CertPropName = CertDataInc.GetNextToken().ToStdString(); + + // Get remaining tokens as the property value. + + while(CertDataInc.HasMoreTokens()){ + + CertPropValue.append(CertDataInc.GetNextToken()); + + } + + SSLCertDataInc.CertData.insert(std::make_pair(CertPropName, CertPropValue)); + CertPropName.clear(); + CertPropValue.clear(); + + } + + SSLCertInfo.SSLCollection.insert(std::make_pair(i, SSLCertDataInc)); + + } + + return SSLCertInfo; + +} + +void CardDAV2::BypassSSLVerification(bool EnableBypass){ + EnableSSLBypass = EnableBypass; + SSLSelfSigned = EnableBypass; +} + +#endif + +void CardDAV2::SetupConnectionObject(){ + ConnectionSession = curl_easy_init(); +} + +bool CardDAV2::IsTaskCompleted(){ + return false; +} + +COConnectResult CardDAV2::Connect(bool DoAuthentication){ + + ServerSSL ? SetupDefaultParametersSSL(DoAuthentication) : SetupDefaultParametersNonSSL(DoAuthentication); + ResetResults(); + + COConnectResult ConnectResult = COCONNECT_UNITTESTFAIL; + string ServerAddressURL = BuildURL("/principals/"); + + curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddressURL.c_str()); + + if (TestMode == true){ + SessionResult = curl_easy_perform(ConnectionSession); + } else { + + } + + switch(SessionResult){ + case CURLE_OK: + SSLStatus = true; + SSLVerified = COSSL_VERIFIED; + ConnectResult = COCONNECT_OK; + break; + case CURLE_SSL_CACERT: + case CURLE_SSL_CONNECT_ERROR: + SSLStatus = true; + ConnectResult = COCONNECT_OK; + SSLVerified = COSSL_UNABLETOVERIFY; + break; + default: + ConnectResult = COCONNECT_INVALID; + break; + }; + + // Check if an error occured before continuing. + + // Check if authentication was successful. + + long SessionResponseCode = 0; + + curl_easy_getinfo(ConnectionSession, CURLINFO_RESPONSE_CODE, &SessionResponseCode); + + if (DoAuthentication == true){ + + // Get the HTTP status code (Should be 200 and not 403). + // Return error otherwise. + + if (SessionResponseCode == 200){ + ConnectResult = COCONNECT_OK; + AuthPassed = true; + ValidResponse = true; + } else if (SessionResponseCode == 403){ + ConnectResult = COCONNECT_AUTHFAIL; + AuthPassed = false; + ValidResponse = true; + } else if (SessionResponseCode >= 200) { + ConnectResult = COCONNECT_INVALID; + AuthPassed = false; + ValidResponse = true; + } else { + ConnectResult = COCONNECT_INVALID; + AuthPassed = false; + ValidResponse = false; + } + + } else { + + ValidResponse = true; + + } + + // Check the header to see if CardDAV is supported. + + vector DAVHeaderValues = GetDAVHeader(); + + for (vector::iterator DAVHeaderValuesIter = DAVHeaderValues.begin(); + DAVHeaderValuesIter != DAVHeaderValues.end(); DAVHeaderValuesIter++){ + + if ((*DAVHeaderValuesIter) == "addressbook"){ + CanProcess = true; + break; + } + + } + + return ConnectResult; + +} + +COServerResponse CardDAV2::GetDefaultPrefix(string *ServerPrefix){ + + // Check if authentication was successful, otherwise don't do anything. + + COServerResponse ServerResponse; + + if (AuthPassed == false){ + ServerResponse.RequestResult = COREQUEST_ERROR_NOTCONNECTED; + ServerResponse.EntityTag = ""; + ServerResponse.SessionCode = 0; + ServerResponse.ResultCode = 0; + ServerResponse.ResultMessage = ""; + return ServerResponse; + } + + ServerSSL ? SetupDefaultParametersSSL(true) : SetupDefaultParametersNonSSL(true); + ResetResults(); + + // Need to do three requests: + + // 1. Get the current user principal URI. + // 2. Get the address book home URI. + // 3. Get the default address book URI. + + // Setup the first query finding out where the principal URL is. + + const char* CurrentUserPrincipalXMLQuery = "\n" + "\n" + " " + " \n" + " " + ""; + + // Setup the second query finding out where the address book home URL is. + + const char* AddressBookHomeXMLQuery = "\n" + "\n" + " \n" + " \n" + " \n" + ""; + + // Setup the third query finding out where the default address book URL is. + + const char* DefaultAddressBookXMLQuery = "\n" + "\n" + " \n" + " \n" + " \n" + ""; + + string ServerAddressURL = BuildURL("/principals/"); + curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddressURL.c_str()); + curl_easy_setopt(ConnectionSession, CURLOPT_CUSTOMREQUEST, "PROPFIND"); + curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDS, CurrentUserPrincipalXMLQuery); + curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDSIZE, strlen(CurrentUserPrincipalXMLQuery)); + + if (TestMode == true){ + SessionResult = curl_easy_perform(ConnectionSession); + } else { + + } + + switch(SessionResult){ + case CURLE_OK: + SSLStatus = true; + SSLVerified = COSSL_VERIFIED; + break; + case CURLE_SSL_CACERT: + case CURLE_SSL_CONNECT_ERROR: + SSLStatus = true; + SSLVerified = COSSL_UNABLETOVERIFY; + break; + default: + break; + }; + + long SessionResponseCode = 0; + + curl_easy_getinfo(ConnectionSession, CURLINFO_RESPONSE_CODE, &SessionResponseCode); + + if (SessionResponseCode == 200 || SessionResponseCode == 207){ + AuthPassed = true; + ValidResponse = true; + } else if (SessionResponseCode == 403){ + AuthPassed = false; + ValidResponse = true; + } else if (SessionResponseCode >= 200) { + AuthPassed = false; + ValidResponse = true; + } else { + AuthPassed = false; + ValidResponse = false; + } + + if (ValidResponse == false && AuthPassed == false){ + ServerResponse.RequestResult = COREQUEST_ERROR_SERVER; + ServerResponse.EntityTag = ""; + ServerResponse.SessionCode = SessionResult; + ServerResponse.ResultCode = SessionResponseCode; + ServerResponse.ResultMessage = ""; + return ServerResponse; + } + + // Process the first response. + + string UserPrincipalURI = GetUserPrincipalURI(); + + // Cleanup and reset for the second connection. + + ServerSSL ? SetupDefaultParametersSSL(true) : SetupDefaultParametersNonSSL(true); + ResetResults(); + + ServerAddressURL = BuildURL(UserPrincipalURI); + curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddressURL.c_str()); + curl_easy_setopt(ConnectionSession, CURLOPT_CUSTOMREQUEST, "PROPFIND"); + curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDS, AddressBookHomeXMLQuery); + curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDSIZE, strlen(AddressBookHomeXMLQuery)); + + if (TestMode == true){ + SessionResult = curl_easy_perform(ConnectionSession); + } else { + + } + + switch(SessionResult){ + case CURLE_OK: + SSLStatus = true; + SSLVerified = COSSL_VERIFIED; + break; + case CURLE_SSL_CACERT: + case CURLE_SSL_CONNECT_ERROR: + SSLStatus = true; + SSLVerified = COSSL_UNABLETOVERIFY; + break; + default: + break; + }; + + SessionResponseCode = 0; + + curl_easy_getinfo(ConnectionSession, CURLINFO_RESPONSE_CODE, &SessionResponseCode); + + if (SessionResponseCode == 200 || SessionResponseCode == 207){ + //ConnectResult = COCONNECT_OK; + AuthPassed = true; + ValidResponse = true; + } else if (SessionResponseCode == 403){ + //ConnectResult = COCONNECT_AUTHFAIL; + AuthPassed = false; + ValidResponse = true; + } else if (SessionResponseCode >= 200) { + //ConnectResult = COCONNECT_INVALID; + AuthPassed = false; + ValidResponse = true; + } else { + //ConnectResult = COCONNECT_INVALID; + AuthPassed = false; + ValidResponse = false; + } + + if (ValidResponse == false && AuthPassed == false){ + ServerResponse.RequestResult = COREQUEST_ERROR_SERVER; + ServerResponse.EntityTag = ""; + ServerResponse.SessionCode = SessionResult; + ServerResponse.ResultCode = SessionResponseCode; + ServerResponse.ResultMessage = ""; + return ServerResponse; + } + + // Process the second response. + + string AddressBookHomeURI = GetAddressBookHomeURI(); + + // Cleanup and reset for the second connection. + + ServerSSL ? SetupDefaultParametersSSL(true) : SetupDefaultParametersNonSSL(true); + ResetResults(); + + ServerAddressURL = BuildURL(AddressBookHomeURI); + curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddressURL.c_str()); + curl_easy_setopt(ConnectionSession, CURLOPT_CUSTOMREQUEST, "PROPFIND"); + curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDS, DefaultAddressBookXMLQuery); + curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDSIZE, strlen(DefaultAddressBookXMLQuery)); + + if (TestMode == true){ + SessionResult = curl_easy_perform(ConnectionSession); + } else { + + } + + switch(SessionResult){ + case CURLE_OK: + SSLStatus = true; + SSLVerified = COSSL_VERIFIED; + break; + case CURLE_SSL_CACERT: + case CURLE_SSL_CONNECT_ERROR: + SSLStatus = true; + SSLVerified = COSSL_UNABLETOVERIFY; + break; + default: + break; + }; + + SessionResponseCode = 0; + + curl_easy_getinfo(ConnectionSession, CURLINFO_RESPONSE_CODE, &SessionResponseCode); + + if (SessionResponseCode == 200 || SessionResponseCode == 207){ + AuthPassed = true; + ValidResponse = true; + } else if (SessionResponseCode == 403){ + AuthPassed = false; + ValidResponse = true; + } else if (SessionResponseCode >= 200) { + AuthPassed = false; + ValidResponse = true; + } else { + AuthPassed = false; + ValidResponse = false; + } + + if (ValidResponse == false && AuthPassed == false){ + ServerResponse.RequestResult = COREQUEST_ERROR_SERVER; + ServerResponse.EntityTag = ""; + ServerResponse.SessionCode = SessionResult; + ServerResponse.ResultCode = SessionResponseCode; + ServerResponse.ResultMessage = ""; + return ServerResponse; + } + + // Process the second response. + + (*ServerPrefix) = GetDefaultAddressBookURI(); + + CanProcess = true; + + ServerResponse.RequestResult = COREQUEST_OK; + ServerResponse.EntityTag = ""; + ServerResponse.SessionCode = SessionResult; + ServerResponse.ResultCode = SessionResponseCode; + ServerResponse.ResultMessage = SessionErrorBuffer; + return ServerResponse; + +} + +std::string CardDAV2::GetUserPrincipalURI(){ + + xmlDocPtr xmlCardDAVDoc; + xmlCardDAVDoc = xmlReadMemory(PageData.c_str(), (int)PageData.size(), "noname.xml", NULL, 0); + string UserPrincipalURI = ""; + + xmlNodePtr nodeLevel1; + xmlNodePtr nodeLevel2; + xmlNodePtr nodeLevel3; + xmlNodePtr nodeLevel4; + xmlNodePtr nodeLevel5; + xmlNodePtr nodeLevel6; + xmlNodePtr nodeLevel7; + + for (nodeLevel1 = xmlCardDAVDoc->children; + nodeLevel1 != NULL; + nodeLevel1 = nodeLevel1->next) + { + + for (nodeLevel2 = nodeLevel1->children; + nodeLevel2 != NULL; + nodeLevel2 = nodeLevel2->next) + { + + + for (nodeLevel3 = nodeLevel2->children; + nodeLevel3 != NULL; + nodeLevel3 = nodeLevel3->next) + { + + for (nodeLevel4 = nodeLevel3->children; + nodeLevel4 != NULL; + nodeLevel4 = nodeLevel4->next) + { + + for (nodeLevel5 = nodeLevel4->children; + nodeLevel5 != NULL; + nodeLevel5 = nodeLevel5->next) + { + + for (nodeLevel6 = nodeLevel5->children; + nodeLevel6 != NULL; + nodeLevel6 = nodeLevel6->next) + { + + if (!xmlStrcmp(nodeLevel6->name, (const xmlChar *)"href") || + !xmlStrcmp(nodeLevel6->name, (const xmlChar *)"d:href") || + !xmlStrcmp(nodeLevel6->name, (const xmlChar *)"D:href") + ){ + + // Found the part so extract the principal URL address. + + for (nodeLevel7 = nodeLevel6->children; + nodeLevel7 != NULL; + nodeLevel7 = nodeLevel7->next) + { + + UserPrincipalURI = ((const char*)nodeLevel7->content); + + } + + } + + } + + } + + } + + } + + } + + } + + xmlFreeDoc(xmlCardDAVDoc); + + return UserPrincipalURI; + +} + +std::string CardDAV2::GetAddressBookHomeURI(){ + + xmlDocPtr xmlCardDAVDoc; + xmlCardDAVDoc = xmlReadMemory(PageData.c_str(), (int)PageData.size(), "noname.xml", NULL, 0); + string AddressBookHomeURI = ""; + + xmlNodePtr nodeLevel1; + xmlNodePtr nodeLevel2; + xmlNodePtr nodeLevel3; + xmlNodePtr nodeLevel4; + xmlNodePtr nodeLevel5; + xmlNodePtr nodeLevel6; + xmlNodePtr nodeLevel7; + + for (nodeLevel1 = xmlCardDAVDoc->children; + nodeLevel1 != NULL; + nodeLevel1 = nodeLevel1->next) + { + + for (nodeLevel2 = nodeLevel1->children; + nodeLevel2 != NULL; + nodeLevel2 = nodeLevel2->next) + { + + + for (nodeLevel3 = nodeLevel2->children; + nodeLevel3 != NULL; + nodeLevel3 = nodeLevel3->next) + { + + for (nodeLevel4 = nodeLevel3->children; + nodeLevel4 != NULL; + nodeLevel4 = nodeLevel4->next) + { + + for (nodeLevel5 = nodeLevel4->children; + nodeLevel5 != NULL; + nodeLevel5 = nodeLevel5->next) + { + + for (nodeLevel6 = nodeLevel5->children; + nodeLevel6 != NULL; + nodeLevel6 = nodeLevel6->next) + { + + if (!xmlStrcmp(nodeLevel6->name, (const xmlChar *)"href") || + !xmlStrcmp(nodeLevel6->name, (const xmlChar *)"d:href") || + !xmlStrcmp(nodeLevel6->name, (const xmlChar *)"D:href") + ){ + + // Found the part so extract the principal URL address. + + for (nodeLevel7 = nodeLevel6->children; + nodeLevel7 != NULL; + nodeLevel7 = nodeLevel7->next) + { + + AddressBookHomeURI = ((const char*)nodeLevel7->content); + + } + + } + + } + + } + + } + + } + + } + + } + + xmlFreeDoc(xmlCardDAVDoc); + + return AddressBookHomeURI; + +} + +std::string CardDAV2::GetDefaultAddressBookURI(){ + + xmlDocPtr xmlCardDAVDoc; + xmlCardDAVDoc = xmlReadMemory(PageData.c_str(), (int)PageData.size(), "noname.xml", NULL, 0); + string DefaultAddressBookURI = ""; + + xmlNodePtr nodeLevel1; + xmlNodePtr nodeLevel2; + xmlNodePtr nodeLevel3; + xmlNodePtr nodeLevel4; + xmlNodePtr nodeLevel5; + xmlNodePtr nodeLevel6; + xmlNodePtr nodeLevel7; + + for (nodeLevel1 = xmlCardDAVDoc->children; + nodeLevel1 != NULL; + nodeLevel1 = nodeLevel1->next) + { + + for (nodeLevel2 = nodeLevel1->children; + nodeLevel2 != NULL; + nodeLevel2 = nodeLevel2->next) + { + + + for (nodeLevel3 = nodeLevel2->children; + nodeLevel3 != NULL; + nodeLevel3 = nodeLevel3->next) + { + + for (nodeLevel4 = nodeLevel3->children; + nodeLevel4 != NULL; + nodeLevel4 = nodeLevel4->next) + { + + for (nodeLevel5 = nodeLevel4->children; + nodeLevel5 != NULL; + nodeLevel5 = nodeLevel5->next) + { + + for (nodeLevel6 = nodeLevel5->children; + nodeLevel6 != NULL; + nodeLevel6 = nodeLevel6->next) + { + + if (!xmlStrcmp(nodeLevel6->name, (const xmlChar *)"href") || + !xmlStrcmp(nodeLevel6->name, (const xmlChar *)"d:href") || + !xmlStrcmp(nodeLevel6->name, (const xmlChar *)"D:href") + ){ + + // Found the part so extract the principal URL address. + + for (nodeLevel7 = nodeLevel6->children; + nodeLevel7 != NULL; + nodeLevel7 = nodeLevel7->next) + { + + DefaultAddressBookURI = ((const char*)nodeLevel7->content); + + } + + } + + } + + } + + } + + } + + } + + } + + xmlFreeDoc(xmlCardDAVDoc); + + return DefaultAddressBookURI; + +} + +COServerResponse CardDAV2::AddContact(std::string Location, std::string Data){ + +} + +COServerResponse CardDAV2::EditContact(std::string Location, std::string Data){ + +} + +COServerResponse CardDAV2::DeleteContact(std::string Location, std::string EntityTag){ + +} + +COServerResponse CardDAV2::GetServerEntityTagValue(std::string Location){ + +} + +COServerResponse CardDAV2::GetContact(std::string Location){ + +} + +COContactList CardDAV2::GetContactList(std::string SyncToken){ + +} + +bool CardDAV2::CanDoProcessing(){ + return CanProcess; +} + +bool CardDAV2::CanDoSSL(){ + return SSLStatus; +} + +COSSLVerified CardDAV2::SSLVerify(){ + return SSLVerified; +} + +bool CardDAV2::AbleToLogin(){ + return AuthPassed; +} + +bool CardDAV2::HasValidResponse(){ + return ValidResponse; +} + +bool CardDAV2::IsSelfSigned(){ + return SSLSelfSigned; +} + +void CardDAV2::SetupDefaultParametersNonSSL(bool DoAuthentication){ + + std::string ServerAddress = ""; + + string ServerAddressURL = "http://" + ServerAddress + ":" + to_string(ServerPort) + "/"; + string UsernamePassword = ServerUser + ":" + ServerPass; + + curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddress.c_str()); + curl_easy_setopt(ConnectionSession, CURLOPT_NOPROGRESS, 1L); + curl_easy_setopt(ConnectionSession, CURLOPT_HTTPAUTH, CURLAUTH_ANY); + curl_easy_setopt(ConnectionSession, CURLOPT_TIMEOUT, 60); + curl_easy_setopt(ConnectionSession, CURLOPT_FAILONERROR, true); + curl_easy_setopt(ConnectionSession, CURLOPT_USERAGENT, XSDAB_USERAGENT); + curl_easy_setopt(ConnectionSession, CURLOPT_WRITEFUNCTION, CardDAV2::WritebackFunc); + curl_easy_setopt(ConnectionSession, CURLOPT_WRITEDATA, &PageData); + curl_easy_setopt(ConnectionSession, CURLOPT_WRITEHEADER, &PageHeader); + curl_easy_setopt(ConnectionSession, CURLOPT_NOSIGNAL, 1); + curl_easy_setopt(ConnectionSession, CURLOPT_CUSTOMREQUEST, "GET"); + + if (DoAuthentication == true){ + curl_easy_setopt(ConnectionSession, CURLOPT_USERPWD, UsernamePassword.c_str()); + } else { + curl_easy_setopt(ConnectionSession, CURLOPT_USERPWD, ":"); + } + +} + +void CardDAV2::SetupDefaultParametersSSL(bool DoAuthentication){ + + // Setup the default parameters. + + string ServerAddressURL = "https://" + ServerAddress + ":" + to_string(ServerPort) + "/"; + string UsernamePassword = ServerUser + ":" + ServerPass; + + curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddressURL.c_str()); + curl_easy_setopt(ConnectionSession, CURLOPT_NOPROGRESS, 1L); + curl_easy_setopt(ConnectionSession, CURLOPT_HTTPAUTH, CURLAUTH_ANY); + curl_easy_setopt(ConnectionSession, CURLOPT_TIMEOUT, 60); + curl_easy_setopt(ConnectionSession, CURLOPT_FAILONERROR, true); + curl_easy_setopt(ConnectionSession, CURLOPT_USERAGENT, XSDAB_USERAGENT); + curl_easy_setopt(ConnectionSession, CURLOPT_WRITEFUNCTION, CardDAV2::WritebackFunc); + curl_easy_setopt(ConnectionSession, CURLOPT_WRITEDATA, &PageData); + curl_easy_setopt(ConnectionSession, CURLOPT_WRITEHEADER, &PageHeader); + curl_easy_setopt(ConnectionSession, CURLOPT_ERRORBUFFER, SessionErrorBuffer); + curl_easy_setopt(ConnectionSession, CURLOPT_NOSIGNAL, 1); + curl_easy_setopt(ConnectionSession, CURLOPT_CERTINFO, 1); + curl_easy_setopt(ConnectionSession, CURLOPT_VERBOSE, 1); + curl_easy_setopt(ConnectionSession, CURLOPT_CUSTOMREQUEST, "GET"); + + if (DoAuthentication == true){ + curl_easy_setopt(ConnectionSession, CURLOPT_USERPWD, UsernamePassword.c_str()); + } else { + curl_easy_setopt(ConnectionSession, CURLOPT_USERPWD, ":"); + } + + if (EnableSSLBypass == true){ + curl_easy_setopt(ConnectionSession, CURLOPT_SSL_VERIFYHOST, 0); + curl_easy_setopt(ConnectionSession, CURLOPT_SSL_VERIFYPEER, 0); + } else { + curl_easy_setopt(ConnectionSession, CURLOPT_SSL_VERIFYHOST, 2); + curl_easy_setopt(ConnectionSession, CURLOPT_SSL_VERIFYPEER, 1); + } + +} + +string CardDAV2::BuildURL(string URI){ + + string ServerAddressURL; + + if (SSLStatus == true){ + ServerAddressURL = "https://" + ServerAddress + ":" + to_string(ServerPort) + URI; + } else { + ServerAddressURL = "https://" + ServerAddress + ":" + to_string(ServerPort) + URI; + } + + return ServerAddressURL; + +} + +string CardDAV2::GetErrorMessage(){ + + ErrorMessage = SessionErrorBuffer; + return ErrorMessage; + +} + +void CardDAV2::ResetResults(){ + + SSLStatus = false; + COSSLVerified SSLVerified = COSSL_NORESULT; + ValidResponse = false; + AuthPassed = false; + CanProcess = false; + SSLSelfSigned = false; + TaskCompleted = false; + ErrorMessage = ""; + SessionErrorBuffer[0] = '\0'; + PageData = ""; + PageHeader = ""; + +} + +vector CardDAV2::GetDAVHeader(){ + + // Go through each of the lines looking for the + // 'DAV:' section. + + + string HeaderName; + string HeaderValue; + bool DAVFound = false; + bool FastForward = false; + vector DAVHeaderList; + + for (int HeaderSeek = 0; HeaderSeek < PageHeader.size(); HeaderSeek++){ + + if (FastForward == true){ + + if (PageHeader[HeaderSeek] == '\n'){ + FastForward = false; + } + + continue; + + } + + try { + PageHeader.substr(HeaderSeek, 4) == "DAV:"; + } + + catch (const out_of_range &oor){ + break; + } + + if (PageHeader.substr(HeaderSeek, 4) == "DAV:"){ + + int CharacterSeek = 5; + + while ((HeaderSeek + CharacterSeek) < PageHeader.size()){ + + if (PageHeader.substr((HeaderSeek + CharacterSeek), 2) == "\r\n"){ + break; + } + + HeaderValue += PageHeader.substr((HeaderSeek + CharacterSeek), 1); + CharacterSeek++; + } + + break; + + } else { + + FastForward = true; + continue; + + } + + if (PageHeader[HeaderSeek] == '\n'){ + HeaderName = ""; + } + + //HeaderName += PageHeader.substr(HeaderSeek, 1); + + } + + // Split the header data. + + std::string DAVHeaderValue; + + for (int HeaderSeek = 0; HeaderSeek < HeaderValue.size(); HeaderSeek++){ + + if (HeaderValue.substr(HeaderSeek, 1) == ","){ + DAVHeaderList.push_back(DAVHeaderValue); + DAVHeaderValue = ""; + HeaderSeek++; + continue; + } + + DAVHeaderValue += HeaderValue[HeaderSeek]; + + } + + if (DAVHeaderValue.size() > 0){ + + DAVHeaderList.push_back(DAVHeaderValue); + + } + + return DAVHeaderList; + +} \ No newline at end of file diff --git a/source/carddav2/carddav2.h b/source/carddav2/carddav2.h new file mode 100644 index 0000000..0c41fdb --- /dev/null +++ b/source/carddav2/carddav2.h @@ -0,0 +1,111 @@ +// CardDAV2.h - CardDAV v2 class header +// +// (c) 2012-2016 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 + +#ifndef __CARDDAV2_CARDDAV2_H__ +#define __CARDDAV2_CARDDAV2_H__ + +#include "../connobject/ConnectionObject.h" +#include "../version.h" +#include "../common/sslcertstructs.h" + +#include +#include +#include +#include + +#include +#include + +class CardDAV2 : public ConnectionObject { + + public: + + using ConnectionObject::ConnectionObject; + + // Destructor. + + ~CardDAV2(); + + // Functions from the ConnectionObject interface. + + void SetupConnectionObject(); + + bool IsTaskCompleted(); + + COConnectResult Connect(bool DoAuthentication); + + COServerResponse GetDefaultPrefix(std::string *ServerPrefix); + COServerResponse AddContact(std::string Location, std::string Data); + COServerResponse EditContact(std::string Location, std::string Data); + COServerResponse DeleteContact(std::string Location, std::string EntityTag); + COServerResponse GetServerEntityTagValue(std::string Location); + COServerResponse GetContact(std::string Location); + COContactList GetContactList(std::string SyncToken); + + bool CanDoProcessing(); + bool CanDoSSL(); + COSSLVerified SSLVerify(); + bool AbleToLogin(); + bool HasValidResponse(); + bool IsSelfSigned(); + std::string GetErrorMessage(); + + void BypassSSLVerification(bool EnableBypass); + +#if defined(__APPLE__) +#elif defined(__WIN32__) +#else + SSLCertCollectionString BuildSSLCollection(); + +#endif + + protected: + private: + + // Variables to set for the CardDAV2 class. + + CURL *ConnectionSession = nullptr; + CURLcode SessionResult = CURLE_OK; + + void SetupDefaultParametersNonSSL(bool DoAuthentication); + void SetupDefaultParametersSSL(bool DoAuthentication); + + std::string PageData; + std::string PageHeader; + char SessionErrorBuffer[CURL_ERROR_SIZE]; + + static size_t WritebackFunc(char *ptr, size_t size, size_t nmemb, void *stream); + size_t WritebackFuncImplementation(char *ptr, size_t size, size_t nmemb, void *stream); + + std::string BuildURL(std::string URI); + void ResetResults(); + std::vector GetDAVHeader(); + + std::string GetUserPrincipalURI(); + std::string GetAddressBookHomeURI(); + std::string GetDefaultAddressBookURI(); + +#if defined(__APPLE__) +#elif defined(__WIN32__) +#else + bool EnableSSLBypass = false; +#endif + +}; + +#endif \ No newline at end of file -- 2.39.2