// 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" using namespace std; CardDAV2::CardDAV2(string ServerAddress, int ServerPort, string ServerUser, string ServerPass, bool ServerSSL){ this->ServerAddress = ServerAddress; this->ServerPort = ServerPort; this->ServerUser = ServerUser; this->ServerPass = ServerPass; this->ServerSSL = ServerSSL; TestMode = true; this->SetupConnectionObject(); } CardDAV2::CardDAV2(string ServerAddress, int ServerPort, string ServerUser, string ServerPass, bool ServerSSL, string ServerPrefix, string ServerAccount){ this->ServerAddress = ServerAddress; this->ServerPort = ServerPort; this->ServerUser = ServerUser; this->ServerPass = ServerPass; this->ServerSSL = ServerSSL; this->ServerPrefix = ServerPrefix; this->ServerAccount = ServerAccount; TestMode = false; this->SetupConnectionObject(); } size_t CardDAV2::WritebackFunc(char *ptr, size_t size, size_t nmemb, void *stream){ return static_cast(stream)->CardDAV2Object->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. CardDAV2PassObject *data = static_cast(stream); data->DataSetting->append(ptr); // Get the SSL engine pointer and trust if required on certain operating systems. if (data->ServerUsingSSL == true) { #if defined(__APPLE__) const struct curl_tlssessioninfo *TLSInfo; CURLcode TLSCode; TLSCode = curl_easy_getinfo(data->ConnectionSessionObject, CURLINFO_TLS_SSL_PTR, &TLSInfo); SecTrustRef CertificateData; if (TLSInfo->internals != nullptr && TLSCode == CURLE_OK) { SSLCopyPeerTrust((SSLContext*)TLSInfo->internals, &CertificateData); data->SSLContext = CertificateData; } #elif defined(__WIN32__) const struct curl_tlssessioninfo *TLSInfo; CURLcode TLSCode; TLSCode = curl_easy_getinfo(data->ConnectionSessionObject, CURLINFO_TLS_SSL_PTR, &TLSInfo); if (TLSInfo->internals != nullptr && TLSCode == CURLE_OK) { // Free the previous certificate data. //CertFreeCertificateContext(CertificateData); PCCERT_CONTEXT CertificateData; PCtxtHandle SSLHandle = (PCtxtHandle)TLSInfo->internals; SECURITY_STATUS GetData = QueryContextAttributes(SSLHandle, SECPKG_ATTR_REMOTE_CERT_CONTEXT, &CertificateData); data->SSLContext = CertificateData; } #endif } return size * nmemb; } void CardDAV2::SetCertificateData() { } CardDAV2::~CardDAV2(){ curl_easy_cleanup(ConnectionSession); ConnectionSession = nullptr; if (HeaderList != nullptr){ curl_slist_free_all(HeaderList); HeaderList = nullptr; } #if defined(__WIN32__) if (CertificateData != nullptr) { CertFreeCertificateContext(CertificateData); } #endif } #if defined(__APPLE__) SecTrustRef CardDAV2::BuildSSLCollection(){ return CertificateData; } #elif defined(__WIN32__) PCCERT_CONTEXT CardDAV2::BuildSSLCollection(){ return CertificateData; } #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; CURLcode result = 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; } #endif void CardDAV2::BypassSSLVerification(bool EnableBypass) { EnableSSLBypass = EnableBypass; SSLSelfSigned = EnableBypass; } 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 { SessionResult = curl_easy_perform(ConnectionSession); } switch(SessionResult){ case CURLE_OK: case CURLE_HTTP_RETURNED_ERROR: SSLStatus = true; SSLVerified = COSSL_VERIFIED; ConnectResult = COCONNECT_OK; break; case CURLE_SSL_INVALIDCERTSTATUS: case CURLE_SSL_CACERT: case CURLE_SSL_CONNECT_ERROR: SSLStatus = true; ConnectResult = COCONNECT_OK; SSLVerified = COSSL_UNABLETOVERIFY; break; default: ConnectResult = COCONNECT_INVALID; break; }; // Set the certificate data (if required). #if defined(__APPLE__) if (ServerSSL) { CertificateData = PageHeaderObject.SSLContext; } #elif defined(__WIN32__) if (ServerSSL) { CertificateData = PageHeaderObject.SSLContext; } #endif // 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 == 401){ 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 >= 400) { 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){ AuthPassed = true; ValidResponse = true; } else if (SessionResponseCode == 403){ AuthPassed = false; ValidResponse = true; } else if (SessionResponseCode >= 400) { 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. 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){ // 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(); string ServerAddressURL = BuildURL(ServerPrefix + Location); curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddressURL.c_str()); curl_easy_setopt(ConnectionSession, CURLOPT_CUSTOMREQUEST, "PUT"); curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDS, Data.c_str()); curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDSIZE, strlen(Data.c_str())); HeaderList = curl_slist_append(HeaderList, "Content-Type: text/vcard; charset=utf-8"); curl_easy_setopt(ConnectionSession, CURLOPT_HTTPHEADER, HeaderList); if (TestMode == true){ SessionResult = curl_easy_perform(ConnectionSession); } else { SessionResult = curl_easy_perform(ConnectionSession); } 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 == 201 || SessionResponseCode == 204){ AuthPassed = true; ValidResponse = true; } else if (SessionResponseCode == 403){ AuthPassed = false; ValidResponse = true; } else if (SessionResponseCode >= 400){ 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; } CanProcess = true; ServerResponse.RequestResult = COREQUEST_OK; ServerResponse.EntityTag = ""; ServerResponse.SessionCode = SessionResult; ServerResponse.ResultCode = SessionResponseCode; ServerResponse.ResultMessage = SessionErrorBuffer; return ServerResponse; } COServerResponse CardDAV2::EditContact(std::string Location, std::string Data){ // 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(); string ServerAddressURL = BuildURL(ServerPrefix + Location); curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddressURL.c_str()); curl_easy_setopt(ConnectionSession, CURLOPT_CUSTOMREQUEST, "PUT"); curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDS, Data.c_str()); curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDSIZE, strlen(Data.c_str())); HeaderList = curl_slist_append(HeaderList, "Content-Type: text/vcard; charset=utf-8"); curl_easy_setopt(ConnectionSession, CURLOPT_HTTPHEADER, HeaderList); if (TestMode == true){ SessionResult = curl_easy_perform(ConnectionSession); } else { SessionResult = curl_easy_perform(ConnectionSession); } 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 == 201 || SessionResponseCode == 204){ AuthPassed = true; ValidResponse = true; } else if (SessionResponseCode == 403){ AuthPassed = false; ValidResponse = true; } else if (SessionResponseCode >= 400){ 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; } CanProcess = true; ServerResponse.RequestResult = COREQUEST_OK; ServerResponse.EntityTag = ""; ServerResponse.SessionCode = SessionResult; ServerResponse.ResultCode = SessionResponseCode; ServerResponse.ResultMessage = SessionErrorBuffer; return ServerResponse; } COServerResponse CardDAV2::DeleteContact(std::string Location){ // 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(); string ServerAddressURL = BuildURL(ServerPrefix + Location); curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddressURL.c_str()); curl_easy_setopt(ConnectionSession, CURLOPT_CUSTOMREQUEST, "DELETE"); if (TestMode == true){ SessionResult = curl_easy_perform(ConnectionSession); } else { SessionResult = curl_easy_perform(ConnectionSession); } 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 == 202 || SessionResponseCode == 204){ AuthPassed = true; ValidResponse = true; } else if (SessionResponseCode == 403){ AuthPassed = false; ValidResponse = true; } else if (SessionResponseCode >= 400){ 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; } CanProcess = true; ServerResponse.RequestResult = COREQUEST_OK; ServerResponse.EntityTag = ""; ServerResponse.SessionCode = SessionResult; ServerResponse.ResultCode = SessionResponseCode; ServerResponse.ResultMessage = SessionErrorBuffer; return ServerResponse; } COServerResponse CardDAV2::GetServerEntityTagValue(std::string Location){ // 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(); static const char* GetETagQuery = "" "" "" "" "" ""; string ServerAddressURL = BuildURL(ServerPrefix + Location); curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddressURL.c_str()); curl_easy_setopt(ConnectionSession, CURLOPT_CUSTOMREQUEST, "REPORT"); curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDS, GetETagQuery); curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDSIZE, strlen(GetETagQuery)); if (TestMode == true){ SessionResult = curl_easy_perform(ConnectionSession); } else { SessionResult = curl_easy_perform(ConnectionSession); } 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 == 207){ AuthPassed = true; ValidResponse = true; } else if (SessionResponseCode == 403){ AuthPassed = false; ValidResponse = true; } else if (SessionResponseCode >= 400){ 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; } CanProcess = true; ServerResponse.RequestResult = COREQUEST_OK; ServerResponse.EntityTag = GetETagValue(); ServerResponse.SessionCode = SessionResult; ServerResponse.ResultCode = SessionResponseCode; ServerResponse.ResultMessage = SessionErrorBuffer; return ServerResponse; } COServerResponse CardDAV2::GetContact(std::string Location, std::string *ContactData){ // 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(); string ServerAddressURL = BuildURL(ServerPrefix + Location); curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddressURL.c_str()); curl_easy_setopt(ConnectionSession, CURLOPT_CUSTOMREQUEST, "GET"); if (TestMode == true){ SessionResult = curl_easy_perform(ConnectionSession); } else { SessionResult = curl_easy_perform(ConnectionSession); } 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){ AuthPassed = true; ValidResponse = true; } else if (SessionResponseCode == 403){ AuthPassed = false; ValidResponse = true; } else if (SessionResponseCode >= 400){ 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; } CanProcess = true; ServerResponse.RequestResult = COREQUEST_OK; ServerResponse.EntityTag = ""; ServerResponse.SessionCode = SessionResult; ServerResponse.ResultCode = SessionResponseCode; ServerResponse.ResultMessage = SessionErrorBuffer; (*ContactData) = PageData; return ServerResponse; } COContactList CardDAV2::GetContactList(std::string SyncToken){ COContactList ServerContactList; // Check if authentication was successful, otherwise don't do anything. if (AuthPassed == false){ ServerContactList.ServerResponse.RequestResult = COREQUEST_ERROR_NOTCONNECTED; ServerContactList.ServerResponse.EntityTag = ""; ServerContactList.ServerResponse.SessionCode = 0; ServerContactList.ServerResponse.ResultCode = 0; ServerContactList.ServerResponse.ResultMessage = ""; return ServerContactList; } ServerSSL ? SetupDefaultParametersSSL(true) : SetupDefaultParametersNonSSL(true); ResetResults(); std::string SyncData; if (SyncToken.size() > 0){ SyncData = "\n" "\n" ""; SyncData.append(SyncToken); SyncData.append("\n" "1\n" "\n" " \n" "\n" ""); } else { SyncData = "\n" "\n" "1\n" "\n" " \n" "\n" ""; } string ServerAddressURL = BuildURL(ServerPrefix); curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddressURL.c_str()); curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDS, SyncData.c_str()); curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDSIZE, strlen(SyncData.c_str())); curl_easy_setopt(ConnectionSession, CURLOPT_CUSTOMREQUEST, "REPORT"); HeaderList = curl_slist_append(HeaderList, "Content-Type: application/xml; charset=utf-8"); HeaderList = curl_slist_append(HeaderList, "Depth: 1"); curl_easy_setopt(ConnectionSession, CURLOPT_HTTPHEADER, HeaderList); if (TestMode == true){ SessionResult = curl_easy_perform(ConnectionSession); } else { SessionResult = curl_easy_perform(ConnectionSession); } 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 == 207){ AuthPassed = true; ValidResponse = true; } else if (SessionResponseCode == 403){ AuthPassed = false; ValidResponse = true; } else if (SessionResponseCode >= 400){ AuthPassed = false; ValidResponse = true; } else { AuthPassed = false; ValidResponse = false; } if (ValidResponse == false || AuthPassed == false){ ServerContactList.ServerResponse.RequestResult = COREQUEST_ERROR_SERVER; ServerContactList.ServerResponse.EntityTag = ""; ServerContactList.ServerResponse.SessionCode = SessionResult; ServerContactList.ServerResponse.ResultCode = SessionResponseCode; ServerContactList.ServerResponse.ResultMessage = ""; return ServerContactList; } CanProcess = true; ProcessContactData(&ServerContactList); ServerContactList.ServerResponse.RequestResult = COREQUEST_OK; ServerContactList.ServerResponse.EntityTag = ""; ServerContactList.ServerResponse.SessionCode = SessionResult; ServerContactList.ServerResponse.ResultCode = SessionResponseCode; ServerContactList.ServerResponse.ResultMessage = SessionErrorBuffer; return ServerContactList; } 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; PageDataObject.CardDAV2Object = this; PageDataObject.ConnectionSessionObject = ConnectionSession; PageDataObject.DataSetting = &PageData; PageDataObject.ServerUsingSSL = false; PageHeaderObject.CardDAV2Object = this; PageHeaderObject.ConnectionSessionObject = ConnectionSession; PageHeaderObject.DataSetting = &PageHeader; PageHeaderObject.ServerUsingSSL = false; curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddress.c_str()); curl_easy_setopt(ConnectionSession, CURLOPT_NOPROGRESS, 1L); curl_easy_setopt(ConnectionSession, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST|CURLAUTH_BASIC); 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, &PageDataObject); curl_easy_setopt(ConnectionSession, CURLOPT_WRITEHEADER, &PageHeaderObject); curl_easy_setopt(ConnectionSession, CURLOPT_NOSIGNAL, 1L); curl_easy_setopt(ConnectionSession, CURLOPT_CUSTOMREQUEST, "GET"); curl_easy_setopt(ConnectionSession, CURLOPT_HTTPHEADER, nullptr); curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDS, nullptr); curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDSIZE, 0L); if (DoAuthentication == true){ curl_easy_setopt(ConnectionSession, CURLOPT_USERPWD, UsernamePassword.c_str()); } else { curl_easy_setopt(ConnectionSession, CURLOPT_USERPWD, NULL); } } void CardDAV2::SetupDefaultParametersSSL(bool DoAuthentication){ // Setup the default parameters. string ServerAddressURL = "https://" + ServerAddress + ":" + to_string(ServerPort) + "/"; string UsernamePassword = ServerUser + ":" + ServerPass; PageDataObject.CardDAV2Object = this; PageDataObject.ConnectionSessionObject = ConnectionSession; PageDataObject.DataSetting = &PageData; PageDataObject.ServerUsingSSL = true; PageHeaderObject.CardDAV2Object = this; PageHeaderObject.ConnectionSessionObject = ConnectionSession; PageHeaderObject.DataSetting = &PageHeader; PageHeaderObject.ServerUsingSSL = true; curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddressURL.c_str()); curl_easy_setopt(ConnectionSession, CURLOPT_NOPROGRESS, 1L); curl_easy_setopt(ConnectionSession, CURLOPT_CERTINFO, 1L); curl_easy_setopt(ConnectionSession, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST|CURLAUTH_BASIC); curl_easy_setopt(ConnectionSession, CURLOPT_TIMEOUT, 60); curl_easy_setopt(ConnectionSession, CURLOPT_FAILONERROR, 0L); curl_easy_setopt(ConnectionSession, CURLOPT_USERAGENT, XSDAB_USERAGENT); curl_easy_setopt(ConnectionSession, CURLOPT_WRITEFUNCTION, CardDAV2::WritebackFunc); curl_easy_setopt(ConnectionSession, CURLOPT_WRITEDATA, &PageDataObject); curl_easy_setopt(ConnectionSession, CURLOPT_WRITEHEADER, &PageHeaderObject); curl_easy_setopt(ConnectionSession, CURLOPT_ERRORBUFFER, SessionErrorBuffer); curl_easy_setopt(ConnectionSession, CURLOPT_CUSTOMREQUEST, "GET"); curl_easy_setopt(ConnectionSession, CURLOPT_HTTPHEADER, nullptr); curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDS, nullptr); curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDSIZE, 0L); if (DoAuthentication == true){ curl_easy_setopt(ConnectionSession, CURLOPT_USERPWD, UsernamePassword.c_str()); } else { curl_easy_setopt(ConnectionSession, CURLOPT_USERPWD, NULL); } if (EnableSSLBypass == true){ curl_easy_setopt(ConnectionSession, CURLOPT_SSL_VERIFYHOST, 0L); curl_easy_setopt(ConnectionSession, CURLOPT_SSL_VERIFYPEER, 0L); curl_easy_setopt(ConnectionSession, CURLOPT_SSL_VERIFYSTATUS, 0L); } else { curl_easy_setopt(ConnectionSession, CURLOPT_SSL_VERIFYHOST, 2L); curl_easy_setopt(ConnectionSession, CURLOPT_SSL_VERIFYPEER, 1L); curl_easy_setopt(ConnectionSession, CURLOPT_SSL_VERIFYSTATUS, 1L); } #if !defined(__APPLE__) || defined(__WIN32__) if (TestMode == false && ServerAccount.size() > 0){ // Check if the server certificate file exists. string CertificateFilename = GetAccountDir(ServerAccount, true); if (wxFile::Exists(CertificateFilename)){ curl_easy_setopt(ConnectionSession, CURLOPT_CAINFO, CertificateFilename.c_str()); } } #endif } string CardDAV2::BuildURL(string URI){ string ServerAddressURL; if (ServerSSL == true){ ServerAddressURL = "https://" + ServerAddress + ":" + to_string(ServerPort) + URI; } else { ServerAddressURL = "http://" + 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'; SessionResult = CURLE_OK; PageData = ""; PageHeader = ""; if (HeaderList != nullptr){ curl_slist_free_all(HeaderList); HeaderList = nullptr; } } string CardDAV2::GetETagValue(){ xmlDocPtr xmlCardDAVDoc; xmlCardDAVDoc = xmlReadMemory(PageData.c_str(), (int)PageData.size(), "noname.xml", NULL, 0); xmlNodePtr nodeLevel1; xmlNodePtr nodeLevel2; xmlNodePtr nodeLevel3; xmlNodePtr nodeLevel4; xmlNodePtr nodeLevel5; xmlNodePtr nodeLevel6; //std::map xmlDataMap; std::string DataFilename; std::string ETagData; std::string xmlStringSafe; std::string ETagValue; // Tranverse through the catacombs of the response to get our ETag for the file. for (nodeLevel1 = xmlCardDAVDoc->children; nodeLevel1 != NULL; nodeLevel1 = nodeLevel1->next) { bool HREFFound = FALSE; bool ETagFound = FALSE; for (nodeLevel2 = nodeLevel1->children; nodeLevel2 != NULL; nodeLevel2 = nodeLevel2->next) { for (nodeLevel3 = nodeLevel2->children; nodeLevel3 != NULL; nodeLevel3 = nodeLevel3->next) { if (!xmlStrcmp(nodeLevel3->name, (const xmlChar *)"href") || !xmlStrcmp(nodeLevel3->name, (const xmlChar *)"d:href") || !xmlStrcmp(nodeLevel3->name, (const xmlChar *)"D:href") ){ // Get the filename. for (nodeLevel4 = nodeLevel3->children; nodeLevel4 != NULL; nodeLevel4 = nodeLevel4->next) { if (!xmlStrcmp(nodeLevel4->name, (const xmlChar *)"text") || !xmlStrcmp(nodeLevel4->name, (const xmlChar *)"d:text") || !xmlStrcmp(nodeLevel4->name, (const xmlChar *)"D:text") ){ DataFilename = wxString::FromUTF8((const char*)nodeLevel4->content); wxStringTokenizer wSTDFilename(DataFilename, wxT("/")); while (wSTDFilename.HasMoreTokens()){ DataFilename = wSTDFilename.GetNextToken().ToStdString(); } HREFFound = TRUE; } } } else { for (nodeLevel4 = nodeLevel3->children; nodeLevel4 != NULL; nodeLevel4 = nodeLevel4->next) { for (nodeLevel5 = nodeLevel4->children; nodeLevel5 != NULL; nodeLevel5 = nodeLevel5->next) { if (!xmlStrcmp(nodeLevel5->name, (const xmlChar *)"getetag") || !xmlStrcmp(nodeLevel5->name, (const xmlChar *)"d:getetag") || !xmlStrcmp(nodeLevel5->name, (const xmlChar *)"D:getetag") ){ for (nodeLevel6 = nodeLevel5->children; nodeLevel6 != NULL; nodeLevel6 = nodeLevel6->next) { // Strip the quotes from the ETag. ETagData = (const char*)nodeLevel6->content; if (ETagData[0] == '"' && ETagData[(ETagData.size() - 1)] == '"'){ ETagData.erase(0, 1); ETagData.erase((ETagData.size() - 1)); } ETagFound = TRUE; } } } } } } } if (HREFFound == TRUE && ETagFound == TRUE){ // Add to the map data. ETagValue = ETagData; HREFFound = FALSE; ETagFound = FALSE; break; } } xmlFreeDoc(xmlCardDAVDoc); return ETagValue; } string CardDAV2::GetETagHeader(){ // Go through each of the lines looking for the // 'DAV:' section. string HeaderName; string HeaderValue; bool FastForward = false; for (int HeaderSeek = 0; HeaderSeek < PageHeader.size(); HeaderSeek++){ if (FastForward == true){ if (PageHeader[HeaderSeek] == '\n'){ FastForward = false; } continue; } try { PageHeader.substr(HeaderSeek, 5) == "ETag:"; } catch (const out_of_range &oor){ break; } if (PageHeader.substr(HeaderSeek, 5) == "ETag:"){ 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); } // Check for quotation marks at the start and end and strip // them out. if (HeaderValue.size() >= 2){ if (HeaderValue[0] == '"'){ HeaderValue.erase((HeaderValue.size() - 1)); HeaderValue.erase(0); } } return HeaderValue; } vector CardDAV2::GetDAVHeader(){ // Go through each of the lines looking for the // 'DAV:' section. string HeaderName; string HeaderValue; 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; } void CardDAV2::ProcessContactData(COContactList *ContactList){ xmlDocPtr xmlCardDAVDoc; xmlCardDAVDoc = xmlReadMemory(PageData.c_str(), (int)PageData.size(), "noname.xml", NULL, 0); xmlNodePtr MultiStatusNode; xmlNodePtr ResponseNode; xmlNodePtr ResponseDataNode; xmlNodePtr PropStatNode; xmlNodePtr ValueNode; xmlNodePtr ETagNode; xmlNodePtr StatusNode; std::string HREFValue; std::string ETagValue; std::string StatusValue; std::string SyncValue; // Go through the document! MultiStatusNode = xmlCardDAVDoc->children; if (MultiStatusNode == nullptr){ return; } bool SyncTokenFound = false; // Tranverse through the catacombs of the response to get our ETag for the file and // the server syncronisation token. for (ResponseNode = MultiStatusNode->children; ResponseNode != nullptr; ResponseNode = ResponseNode->next){ // Check if tag is response or sync-token. if (!xmlStrcmp(ResponseNode->name, (const xmlChar *)"response") || !xmlStrcmp(ResponseNode->name, (const xmlChar *)"d:response") || !xmlStrcmp(ResponseNode->name, (const xmlChar *)"D:response")){ COContactStatus ContactStatus = COCS_UNKNOWN; for (ResponseDataNode = ResponseNode->children; ResponseDataNode != nullptr; ResponseDataNode = ResponseDataNode->next){ if (!xmlStrcmp(ResponseDataNode->name, (const xmlChar *)"href") || !xmlStrcmp(ResponseDataNode->name, (const xmlChar *)"d:href") || !xmlStrcmp(ResponseDataNode->name, (const xmlChar *)"D:href")){ HREFValue = (const char*)ResponseDataNode->children->content; // Get the filename after the last forward slash. int LastSlash = 0; for (int HREFValueSeek = 0; HREFValueSeek < HREFValue.size(); HREFValueSeek++){ if (HREFValue[HREFValueSeek] == '/'){ LastSlash = HREFValueSeek; } } HREFValue = HREFValue.substr((LastSlash + 1)); } else if (!xmlStrcmp(ResponseDataNode->name, (const xmlChar *)"propstat") || !xmlStrcmp(ResponseDataNode->name, (const xmlChar *)"d:propstat") || !xmlStrcmp(ResponseDataNode->name, (const xmlChar *)"D:propstat")){ for (PropStatNode = ResponseDataNode->children; PropStatNode != nullptr; PropStatNode = PropStatNode->next){ if (!xmlStrcmp(PropStatNode->name, (const xmlChar *)"prop") || !xmlStrcmp(PropStatNode->name, (const xmlChar *)"d:prop") || !xmlStrcmp(PropStatNode->name, (const xmlChar *)"D:prop")){ for (ETagNode = PropStatNode->children; ETagNode != nullptr; ETagNode = ETagNode->next){ if (!xmlStrcmp(ETagNode->name, (const xmlChar *)"getetag") || !xmlStrcmp(ETagNode->name, (const xmlChar *)"getetag") || !xmlStrcmp(ETagNode->name, (const xmlChar *)"getetag")){ ETagValue = (const char*)ETagNode->children->content; if (ETagValue.size() > 2 && ETagValue.substr(0,1) == "\""){ ETagValue.erase((ETagValue.size() - 1),1); ETagValue.erase(0,1); } } } } else if (!xmlStrcmp(PropStatNode->name, (const xmlChar *)"status") || !xmlStrcmp(PropStatNode->name, (const xmlChar *)"d:status") || !xmlStrcmp(PropStatNode->name, (const xmlChar *)"D:status")){ StatusValue = (const char*)PropStatNode->children->content; if (StatusValue == "HTTP/1.1 200 OK"){ ContactStatus = COCS_UPDATED; } else if (StatusValue == "HTTP/1.1 404 Not Found"){ ContactStatus = COCS_DELETED; } else { ContactStatus = COCS_UNKNOWN; } } } } } COContactData ContactInformation; ContactInformation.Location = HREFValue; ContactInformation.Data = ETagValue; ContactInformation.Status = ContactStatus; HREFValue.clear(); ETagValue.clear(); StatusValue.clear(); ContactList->ListData.push_back(ContactInformation); } else if (!xmlStrcmp(ResponseNode->name, (const xmlChar *)"sync-token") || !xmlStrcmp(ResponseNode->name, (const xmlChar *)"d:sync-token") || !xmlStrcmp(ResponseNode->name, (const xmlChar *)"D:sync-token")){ SyncValue = (const char*)ResponseNode->children->content; } } ContactList->SyncToken = SyncValue; xmlFreeDoc(xmlCardDAVDoc); return; }