1 // CardDAV2.cpp - CardDAV v2 class
3 // (c) 2012-2016 Xestia Software Development.
5 // This file is part of Xestia Address Book.
7 // Xestia Address Book is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU General Public License as published by the
9 // Free Software Foundation, version 3 of the license.
11 // Xestia Address Book is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License along
17 // with Xestia Address Book. If not, see <http://www.gnu.org/licenses/>
23 CardDAV2::CardDAV2(string ServerAddress, int ServerPort, string ServerUser, string ServerPass, bool ServerSSL){
25 this->ServerAddress = ServerAddress;
26 this->ServerPort = ServerPort;
27 this->ServerUser = ServerUser;
28 this->ServerPass = ServerPass;
29 this->ServerSSL = ServerSSL;
32 this->SetupConnectionObject();
36 CardDAV2::CardDAV2(string ServerAddress, int ServerPort, string ServerUser, string ServerPass, bool ServerSSL, string ServerPrefix, string ServerAccount){
38 this->ServerAddress = ServerAddress;
39 this->ServerPort = ServerPort;
40 this->ServerUser = ServerUser;
41 this->ServerPass = ServerPass;
42 this->ServerSSL = ServerSSL;
43 this->ServerPrefix = ServerPrefix;
44 this->ServerAccount = ServerAccount;
48 this->SetupConnectionObject();
52 size_t CardDAV2::WritebackFunc(char *ptr, size_t size, size_t nmemb, void *stream){
54 return static_cast<CardDAV2PassObject*>(stream)->CardDAV2Object->WritebackFuncImplementation(ptr, size, nmemb, stream);
58 size_t CardDAV2::WritebackFuncImplementation(char *ptr, size_t size, size_t nmemb, void *stream){
60 // Writeback function for the CardDAV object.
62 CardDAV2PassObject *data = static_cast<CardDAV2PassObject*>(stream);
63 data->DataSetting->append(ptr);
65 // Get the SSL engine pointer and trust if required on certain operating systems.
67 if (data->ServerUsingSSL == true) {
69 #if defined(__APPLE__)
71 const struct curl_tlssessioninfo *TLSInfo;
73 TLSCode = curl_easy_getinfo(data->ConnectionSessionObject, CURLINFO_TLS_SSL_PTR, &TLSInfo);
75 SecTrustRef CertificateData;
77 if (TLSInfo->internals != nullptr && TLSCode == CURLE_OK) {
78 SSLCopyPeerTrust((SSLContext*)TLSInfo->internals, &CertificateData);
79 data->SSLContext = CertificateData;
82 #elif defined(__WIN32__)
84 const struct curl_tlssessioninfo *TLSInfo;
86 TLSCode = curl_easy_getinfo(data->ConnectionSessionObject, CURLINFO_TLS_SSL_PTR, &TLSInfo);
88 if (TLSInfo->internals != nullptr && TLSCode == CURLE_OK) {
90 // Free the previous certificate data.
92 //CertFreeCertificateContext(CertificateData);
94 PCCERT_CONTEXT CertificateData;
96 PCtxtHandle SSLHandle = (PCtxtHandle)TLSInfo->internals;
97 SECURITY_STATUS GetData = QueryContextAttributes(SSLHandle, SECPKG_ATTR_REMOTE_CERT_CONTEXT, &CertificateData);
99 data->SSLContext = CertificateData;
111 void CardDAV2::SetCertificateData() {
115 CardDAV2::~CardDAV2(){
117 curl_easy_cleanup(ConnectionSession);
118 ConnectionSession = nullptr;
120 if (HeaderList != nullptr){
121 curl_slist_free_all(HeaderList);
122 HeaderList = nullptr;
125 #if defined(__WIN32__)
127 if (CertificateData != nullptr) {
129 CertFreeCertificateContext(CertificateData);
137 #if defined(__APPLE__)
139 SecTrustRef CardDAV2::BuildSSLCollection(){
141 return CertificateData;
145 #elif defined(__WIN32__)
147 PCCERT_CONTEXT CardDAV2::BuildSSLCollection(){
149 return CertificateData;
155 SSLCertCollectionString CardDAV2::BuildSSLCollection(){
157 // Build and return the SSL collection.
159 SSLCertCollectionString SSLCertInfo;
161 // Grab the certificate data.
164 struct curl_slist *certdata;
165 struct curl_certinfo *certinfo;
168 certptr.certdata = NULL;
170 CURLcode result = curl_easy_getinfo(ConnectionSession, CURLINFO_CERTINFO, &certptr.certinfo);
172 std::string CertPropName;
173 std::string CertPropValue;
175 for (int i = 0; i < certptr.certinfo->num_of_certs; i++){
177 struct curl_slist *slist;
178 SSLCertDataString SSLCertDataInc;
180 for (slist = certptr.certinfo->certinfo[i]; slist; slist = slist->next){
182 // Using wxStringTokenizer from wxWidgets.
184 wxStringTokenizer CertDataInc(wxString::FromUTF8(slist->data), ":");
186 // Get first token as the property name.
188 CertPropName = CertDataInc.GetNextToken().ToStdString();
190 // Get remaining tokens as the property value.
192 while(CertDataInc.HasMoreTokens()){
194 CertPropValue.append(CertDataInc.GetNextToken());
198 SSLCertDataInc.CertData.insert(std::make_pair(CertPropName, CertPropValue));
199 CertPropName.clear();
200 CertPropValue.clear();
204 SSLCertInfo.SSLCollection.insert(std::make_pair(i, SSLCertDataInc));
214 void CardDAV2::BypassSSLVerification(bool EnableBypass) {
215 EnableSSLBypass = EnableBypass;
216 SSLSelfSigned = EnableBypass;
219 void CardDAV2::SetupConnectionObject(){
220 ConnectionSession = curl_easy_init();
223 bool CardDAV2::IsTaskCompleted(){
227 COConnectResult CardDAV2::Connect(bool DoAuthentication){
229 ServerSSL ? SetupDefaultParametersSSL(DoAuthentication) : SetupDefaultParametersNonSSL(DoAuthentication);
232 COConnectResult ConnectResult = COCONNECT_UNITTESTFAIL;
233 string ServerAddressURL = BuildURL("/principals/");
235 curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddressURL.c_str());
237 if (TestMode == true){
238 SessionResult = curl_easy_perform(ConnectionSession);
240 SessionResult = curl_easy_perform(ConnectionSession);
243 switch(SessionResult){
245 case CURLE_HTTP_RETURNED_ERROR:
247 SSLVerified = COSSL_VERIFIED;
248 ConnectResult = COCONNECT_OK;
250 case CURLE_SSL_INVALIDCERTSTATUS:
251 case CURLE_SSL_CACERT:
252 case CURLE_SSL_CONNECT_ERROR:
254 ConnectResult = COCONNECT_OK;
255 SSLVerified = COSSL_UNABLETOVERIFY;
258 ConnectResult = COCONNECT_INVALID;
262 // Set the certificate data (if required).
264 #if defined(__APPLE__)
268 CertificateData = PageHeaderObject.SSLContext;
272 #elif defined(__WIN32__)
276 CertificateData = PageHeaderObject.SSLContext;
282 // Check if an error occured before continuing.
284 // Check if authentication was successful.
286 long SessionResponseCode = 0;
288 curl_easy_getinfo(ConnectionSession, CURLINFO_RESPONSE_CODE, &SessionResponseCode);
290 if (DoAuthentication == true){
292 // Get the HTTP status code (Should be 200 and not 403).
293 // Return error otherwise.
295 if (SessionResponseCode == 200){
296 ConnectResult = COCONNECT_OK;
298 ValidResponse = true;
299 } else if (SessionResponseCode == 401){
300 ConnectResult = COCONNECT_AUTHFAIL;
302 ValidResponse = true;
303 } else if (SessionResponseCode >= 200) {
304 ConnectResult = COCONNECT_INVALID;
306 ValidResponse = true;
308 ConnectResult = COCONNECT_INVALID;
310 ValidResponse = false;
315 ValidResponse = true;
319 // Check the header to see if CardDAV is supported.
321 vector<string> DAVHeaderValues = GetDAVHeader();
323 for (vector<string>::iterator DAVHeaderValuesIter = DAVHeaderValues.begin();
324 DAVHeaderValuesIter != DAVHeaderValues.end(); DAVHeaderValuesIter++){
326 if ((*DAVHeaderValuesIter) == "addressbook"){
333 return ConnectResult;
337 COServerResponse CardDAV2::GetDefaultPrefix(string *ServerPrefix){
339 // Check if authentication was successful, otherwise don't do anything.
341 COServerResponse ServerResponse;
343 if (AuthPassed == false){
344 ServerResponse.RequestResult = COREQUEST_ERROR_NOTCONNECTED;
345 ServerResponse.EntityTag = "";
346 ServerResponse.SessionCode = 0;
347 ServerResponse.ResultCode = 0;
348 ServerResponse.ResultMessage = "";
349 return ServerResponse;
352 ServerSSL ? SetupDefaultParametersSSL(true) : SetupDefaultParametersNonSSL(true);
355 // Need to do three requests:
357 // 1. Get the current user principal URI.
358 // 2. Get the address book home URI.
359 // 3. Get the default address book URI.
361 // Setup the first query finding out where the principal URL is.
363 const char* CurrentUserPrincipalXMLQuery = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"
364 "<D:propfind xmlns:D=\"DAV:\">\n"
366 " <D:current-user-principal/>\n"
370 // Setup the second query finding out where the address book home URL is.
372 const char* AddressBookHomeXMLQuery = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"
373 "<D:propfind xmlns:D=\"DAV:\""
374 " xmlns:C=\"urn:ietf:params:xml:ns:carddav\">\n"
376 " <C:addressbook-home-set/>\n"
380 // Setup the third query finding out where the default address book URL is.
382 const char* DefaultAddressBookXMLQuery = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"
383 "<D:propfind xmlns:D=\"DAV:\""
384 " xmlns:C=\"urn:ietf:params:xml:ns:carddav\">\n"
386 " <C:default-addressbook-URL/>\n"
390 string ServerAddressURL = BuildURL("/principals/");
391 curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddressURL.c_str());
392 curl_easy_setopt(ConnectionSession, CURLOPT_CUSTOMREQUEST, "PROPFIND");
393 curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDS, CurrentUserPrincipalXMLQuery);
394 curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDSIZE, strlen(CurrentUserPrincipalXMLQuery));
396 if (TestMode == true){
397 SessionResult = curl_easy_perform(ConnectionSession);
402 switch(SessionResult){
405 SSLVerified = COSSL_VERIFIED;
407 case CURLE_SSL_CACERT:
408 case CURLE_SSL_CONNECT_ERROR:
410 SSLVerified = COSSL_UNABLETOVERIFY;
416 long SessionResponseCode = 0;
418 curl_easy_getinfo(ConnectionSession, CURLINFO_RESPONSE_CODE, &SessionResponseCode);
420 if (SessionResponseCode == 200 || SessionResponseCode == 207){
422 ValidResponse = true;
423 } else if (SessionResponseCode == 403){
425 ValidResponse = true;
426 } else if (SessionResponseCode >= 400) {
428 ValidResponse = true;
431 ValidResponse = false;
434 if (ValidResponse == false && AuthPassed == false){
435 ServerResponse.RequestResult = COREQUEST_ERROR_SERVER;
436 ServerResponse.EntityTag = "";
437 ServerResponse.SessionCode = SessionResult;
438 ServerResponse.ResultCode = SessionResponseCode;
439 ServerResponse.ResultMessage = "";
440 return ServerResponse;
443 // Process the first response.
445 string UserPrincipalURI = GetUserPrincipalURI();
447 // Cleanup and reset for the second connection.
449 ServerSSL ? SetupDefaultParametersSSL(true) : SetupDefaultParametersNonSSL(true);
452 ServerAddressURL = BuildURL(UserPrincipalURI);
453 curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddressURL.c_str());
454 curl_easy_setopt(ConnectionSession, CURLOPT_CUSTOMREQUEST, "PROPFIND");
455 curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDS, AddressBookHomeXMLQuery);
456 curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDSIZE, strlen(AddressBookHomeXMLQuery));
458 if (TestMode == true){
459 SessionResult = curl_easy_perform(ConnectionSession);
464 switch(SessionResult){
467 SSLVerified = COSSL_VERIFIED;
469 case CURLE_SSL_CACERT:
470 case CURLE_SSL_CONNECT_ERROR:
472 SSLVerified = COSSL_UNABLETOVERIFY;
478 SessionResponseCode = 0;
480 curl_easy_getinfo(ConnectionSession, CURLINFO_RESPONSE_CODE, &SessionResponseCode);
482 if (SessionResponseCode == 200 || SessionResponseCode == 207){
484 ValidResponse = true;
485 } else if (SessionResponseCode == 403){
487 ValidResponse = true;
488 } else if (SessionResponseCode >= 400) {
490 ValidResponse = true;
493 ValidResponse = false;
496 if (ValidResponse == false && AuthPassed == false){
497 ServerResponse.RequestResult = COREQUEST_ERROR_SERVER;
498 ServerResponse.EntityTag = "";
499 ServerResponse.SessionCode = SessionResult;
500 ServerResponse.ResultCode = SessionResponseCode;
501 ServerResponse.ResultMessage = "";
502 return ServerResponse;
505 // Process the second response.
507 string AddressBookHomeURI = GetAddressBookHomeURI();
509 // Cleanup and reset for the second connection.
511 ServerSSL ? SetupDefaultParametersSSL(true) : SetupDefaultParametersNonSSL(true);
514 ServerAddressURL = BuildURL(AddressBookHomeURI);
515 curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddressURL.c_str());
516 curl_easy_setopt(ConnectionSession, CURLOPT_CUSTOMREQUEST, "PROPFIND");
517 curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDS, DefaultAddressBookXMLQuery);
518 curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDSIZE, strlen(DefaultAddressBookXMLQuery));
520 if (TestMode == true){
521 SessionResult = curl_easy_perform(ConnectionSession);
526 switch(SessionResult){
529 SSLVerified = COSSL_VERIFIED;
531 case CURLE_SSL_CACERT:
532 case CURLE_SSL_CONNECT_ERROR:
534 SSLVerified = COSSL_UNABLETOVERIFY;
540 SessionResponseCode = 0;
542 curl_easy_getinfo(ConnectionSession, CURLINFO_RESPONSE_CODE, &SessionResponseCode);
544 if (SessionResponseCode == 200 || SessionResponseCode == 207){
546 ValidResponse = true;
547 } else if (SessionResponseCode == 403){
549 ValidResponse = true;
550 } else if (SessionResponseCode >= 200) {
552 ValidResponse = true;
555 ValidResponse = false;
558 if (ValidResponse == false || AuthPassed == false){
559 ServerResponse.RequestResult = COREQUEST_ERROR_SERVER;
560 ServerResponse.EntityTag = "";
561 ServerResponse.SessionCode = SessionResult;
562 ServerResponse.ResultCode = SessionResponseCode;
563 ServerResponse.ResultMessage = "";
564 return ServerResponse;
567 // Process the second response.
569 (*ServerPrefix) = GetDefaultAddressBookURI();
573 ServerResponse.RequestResult = COREQUEST_OK;
574 ServerResponse.EntityTag = "";
575 ServerResponse.SessionCode = SessionResult;
576 ServerResponse.ResultCode = SessionResponseCode;
577 ServerResponse.ResultMessage = SessionErrorBuffer;
578 return ServerResponse;
582 std::string CardDAV2::GetUserPrincipalURI(){
584 xmlDocPtr xmlCardDAVDoc;
585 xmlCardDAVDoc = xmlReadMemory(PageData.c_str(), (int)PageData.size(), "noname.xml", NULL, 0);
586 string UserPrincipalURI = "";
588 xmlNodePtr nodeLevel1;
589 xmlNodePtr nodeLevel2;
590 xmlNodePtr nodeLevel3;
591 xmlNodePtr nodeLevel4;
592 xmlNodePtr nodeLevel5;
593 xmlNodePtr nodeLevel6;
594 xmlNodePtr nodeLevel7;
596 for (nodeLevel1 = xmlCardDAVDoc->children;
598 nodeLevel1 = nodeLevel1->next)
601 for (nodeLevel2 = nodeLevel1->children;
603 nodeLevel2 = nodeLevel2->next)
607 for (nodeLevel3 = nodeLevel2->children;
609 nodeLevel3 = nodeLevel3->next)
612 for (nodeLevel4 = nodeLevel3->children;
614 nodeLevel4 = nodeLevel4->next)
617 for (nodeLevel5 = nodeLevel4->children;
619 nodeLevel5 = nodeLevel5->next)
622 for (nodeLevel6 = nodeLevel5->children;
624 nodeLevel6 = nodeLevel6->next)
627 if (!xmlStrcmp(nodeLevel6->name, (const xmlChar *)"href") ||
628 !xmlStrcmp(nodeLevel6->name, (const xmlChar *)"d:href") ||
629 !xmlStrcmp(nodeLevel6->name, (const xmlChar *)"D:href")
632 // Found the <href> part so extract the principal URL address.
634 for (nodeLevel7 = nodeLevel6->children;
636 nodeLevel7 = nodeLevel7->next)
639 UserPrincipalURI = ((const char*)nodeLevel7->content);
657 xmlFreeDoc(xmlCardDAVDoc);
659 return UserPrincipalURI;
663 std::string CardDAV2::GetAddressBookHomeURI(){
665 xmlDocPtr xmlCardDAVDoc;
666 xmlCardDAVDoc = xmlReadMemory(PageData.c_str(), (int)PageData.size(), "noname.xml", NULL, 0);
667 string AddressBookHomeURI = "";
669 xmlNodePtr nodeLevel1;
670 xmlNodePtr nodeLevel2;
671 xmlNodePtr nodeLevel3;
672 xmlNodePtr nodeLevel4;
673 xmlNodePtr nodeLevel5;
674 xmlNodePtr nodeLevel6;
675 xmlNodePtr nodeLevel7;
677 for (nodeLevel1 = xmlCardDAVDoc->children;
679 nodeLevel1 = nodeLevel1->next)
682 for (nodeLevel2 = nodeLevel1->children;
684 nodeLevel2 = nodeLevel2->next)
688 for (nodeLevel3 = nodeLevel2->children;
690 nodeLevel3 = nodeLevel3->next)
693 for (nodeLevel4 = nodeLevel3->children;
695 nodeLevel4 = nodeLevel4->next)
698 for (nodeLevel5 = nodeLevel4->children;
700 nodeLevel5 = nodeLevel5->next)
703 for (nodeLevel6 = nodeLevel5->children;
705 nodeLevel6 = nodeLevel6->next)
708 if (!xmlStrcmp(nodeLevel6->name, (const xmlChar *)"href") ||
709 !xmlStrcmp(nodeLevel6->name, (const xmlChar *)"d:href") ||
710 !xmlStrcmp(nodeLevel6->name, (const xmlChar *)"D:href")
713 // Found the <href> part so extract the principal URL address.
715 for (nodeLevel7 = nodeLevel6->children;
717 nodeLevel7 = nodeLevel7->next)
720 AddressBookHomeURI = ((const char*)nodeLevel7->content);
738 xmlFreeDoc(xmlCardDAVDoc);
740 return AddressBookHomeURI;
744 std::string CardDAV2::GetDefaultAddressBookURI(){
746 xmlDocPtr xmlCardDAVDoc;
747 xmlCardDAVDoc = xmlReadMemory(PageData.c_str(), (int)PageData.size(), "noname.xml", NULL, 0);
748 string DefaultAddressBookURI = "";
750 xmlNodePtr nodeLevel1;
751 xmlNodePtr nodeLevel2;
752 xmlNodePtr nodeLevel3;
753 xmlNodePtr nodeLevel4;
754 xmlNodePtr nodeLevel5;
755 xmlNodePtr nodeLevel6;
756 xmlNodePtr nodeLevel7;
758 for (nodeLevel1 = xmlCardDAVDoc->children;
760 nodeLevel1 = nodeLevel1->next)
763 for (nodeLevel2 = nodeLevel1->children;
765 nodeLevel2 = nodeLevel2->next)
769 for (nodeLevel3 = nodeLevel2->children;
771 nodeLevel3 = nodeLevel3->next)
774 for (nodeLevel4 = nodeLevel3->children;
776 nodeLevel4 = nodeLevel4->next)
779 for (nodeLevel5 = nodeLevel4->children;
781 nodeLevel5 = nodeLevel5->next)
784 for (nodeLevel6 = nodeLevel5->children;
786 nodeLevel6 = nodeLevel6->next)
789 if (!xmlStrcmp(nodeLevel6->name, (const xmlChar *)"href") ||
790 !xmlStrcmp(nodeLevel6->name, (const xmlChar *)"d:href") ||
791 !xmlStrcmp(nodeLevel6->name, (const xmlChar *)"D:href")
794 // Found the <href> part so extract the principal URL address.
796 for (nodeLevel7 = nodeLevel6->children;
798 nodeLevel7 = nodeLevel7->next)
801 DefaultAddressBookURI = ((const char*)nodeLevel7->content);
819 xmlFreeDoc(xmlCardDAVDoc);
821 return DefaultAddressBookURI;
825 COServerResponse CardDAV2::AddContact(std::string Location, std::string Data){
827 // Check if authentication was successful, otherwise don't do anything.
829 COServerResponse ServerResponse;
831 if (AuthPassed == false){
832 ServerResponse.RequestResult = COREQUEST_ERROR_NOTCONNECTED;
833 ServerResponse.EntityTag = "";
834 ServerResponse.SessionCode = 0;
835 ServerResponse.ResultCode = 0;
836 ServerResponse.ResultMessage = "";
837 return ServerResponse;
840 ServerSSL ? SetupDefaultParametersSSL(true) : SetupDefaultParametersNonSSL(true);
843 string ServerAddressURL = BuildURL(ServerPrefix + Location);
844 curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddressURL.c_str());
845 curl_easy_setopt(ConnectionSession, CURLOPT_CUSTOMREQUEST, "PUT");
846 curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDS, Data.c_str());
847 curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDSIZE, strlen(Data.c_str()));
849 HeaderList = curl_slist_append(HeaderList, "Content-Type: text/vcard; charset=utf-8");
851 curl_easy_setopt(ConnectionSession, CURLOPT_HTTPHEADER, HeaderList);
853 if (TestMode == true){
854 SessionResult = curl_easy_perform(ConnectionSession);
856 SessionResult = curl_easy_perform(ConnectionSession);
859 switch(SessionResult){
862 SSLVerified = COSSL_VERIFIED;
864 case CURLE_SSL_CACERT:
865 case CURLE_SSL_CONNECT_ERROR:
867 SSLVerified = COSSL_UNABLETOVERIFY;
873 long SessionResponseCode = 0;
875 curl_easy_getinfo(ConnectionSession, CURLINFO_RESPONSE_CODE, &SessionResponseCode);
877 if (SessionResponseCode == 200 || SessionResponseCode == 201 || SessionResponseCode == 204){
879 ValidResponse = true;
880 } else if (SessionResponseCode == 403){
882 ValidResponse = true;
883 } else if (SessionResponseCode >= 400){
885 ValidResponse = true;
888 ValidResponse = false;
891 if (ValidResponse == false || AuthPassed == false){
892 ServerResponse.RequestResult = COREQUEST_ERROR_SERVER;
893 ServerResponse.EntityTag = "";
894 ServerResponse.SessionCode = SessionResult;
895 ServerResponse.ResultCode = SessionResponseCode;
896 ServerResponse.ResultMessage = "";
897 return ServerResponse;
902 ServerResponse.RequestResult = COREQUEST_OK;
903 ServerResponse.EntityTag = "";
904 ServerResponse.SessionCode = SessionResult;
905 ServerResponse.ResultCode = SessionResponseCode;
906 ServerResponse.ResultMessage = SessionErrorBuffer;
907 return ServerResponse;
911 COServerResponse CardDAV2::EditContact(std::string Location, std::string Data){
913 // Check if authentication was successful, otherwise don't do anything.
915 COServerResponse ServerResponse;
917 if (AuthPassed == false){
918 ServerResponse.RequestResult = COREQUEST_ERROR_NOTCONNECTED;
919 ServerResponse.EntityTag = "";
920 ServerResponse.SessionCode = 0;
921 ServerResponse.ResultCode = 0;
922 ServerResponse.ResultMessage = "";
923 return ServerResponse;
926 ServerSSL ? SetupDefaultParametersSSL(true) : SetupDefaultParametersNonSSL(true);
929 string ServerAddressURL = BuildURL(ServerPrefix + Location);
930 curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddressURL.c_str());
931 curl_easy_setopt(ConnectionSession, CURLOPT_CUSTOMREQUEST, "PUT");
932 curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDS, Data.c_str());
933 curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDSIZE, strlen(Data.c_str()));
935 HeaderList = curl_slist_append(HeaderList, "Content-Type: text/vcard; charset=utf-8");
937 curl_easy_setopt(ConnectionSession, CURLOPT_HTTPHEADER, HeaderList);
939 if (TestMode == true){
940 SessionResult = curl_easy_perform(ConnectionSession);
942 SessionResult = curl_easy_perform(ConnectionSession);
945 switch(SessionResult){
948 SSLVerified = COSSL_VERIFIED;
950 case CURLE_SSL_CACERT:
951 case CURLE_SSL_CONNECT_ERROR:
953 SSLVerified = COSSL_UNABLETOVERIFY;
959 long SessionResponseCode = 0;
961 curl_easy_getinfo(ConnectionSession, CURLINFO_RESPONSE_CODE, &SessionResponseCode);
963 if (SessionResponseCode == 200 || SessionResponseCode == 201 || SessionResponseCode == 204){
965 ValidResponse = true;
966 } else if (SessionResponseCode == 403){
968 ValidResponse = true;
969 } else if (SessionResponseCode >= 400){
971 ValidResponse = true;
974 ValidResponse = false;
977 if (ValidResponse == false || AuthPassed == false){
978 ServerResponse.RequestResult = COREQUEST_ERROR_SERVER;
979 ServerResponse.EntityTag = "";
980 ServerResponse.SessionCode = SessionResult;
981 ServerResponse.ResultCode = SessionResponseCode;
982 ServerResponse.ResultMessage = "";
983 return ServerResponse;
988 ServerResponse.RequestResult = COREQUEST_OK;
989 ServerResponse.EntityTag = "";
990 ServerResponse.SessionCode = SessionResult;
991 ServerResponse.ResultCode = SessionResponseCode;
992 ServerResponse.ResultMessage = SessionErrorBuffer;
993 return ServerResponse;
997 COServerResponse CardDAV2::DeleteContact(std::string Location){
999 // Check if authentication was successful, otherwise don't do anything.
1001 COServerResponse ServerResponse;
1003 if (AuthPassed == false){
1004 ServerResponse.RequestResult = COREQUEST_ERROR_NOTCONNECTED;
1005 ServerResponse.EntityTag = "";
1006 ServerResponse.SessionCode = 0;
1007 ServerResponse.ResultCode = 0;
1008 ServerResponse.ResultMessage = "";
1009 return ServerResponse;
1012 ServerSSL ? SetupDefaultParametersSSL(true) : SetupDefaultParametersNonSSL(true);
1015 string ServerAddressURL = BuildURL(ServerPrefix + Location);
1016 curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddressURL.c_str());
1017 curl_easy_setopt(ConnectionSession, CURLOPT_CUSTOMREQUEST, "DELETE");
1019 if (TestMode == true){
1020 SessionResult = curl_easy_perform(ConnectionSession);
1022 SessionResult = curl_easy_perform(ConnectionSession);
1025 switch(SessionResult){
1028 SSLVerified = COSSL_VERIFIED;
1030 case CURLE_SSL_CACERT:
1031 case CURLE_SSL_CONNECT_ERROR:
1033 SSLVerified = COSSL_UNABLETOVERIFY;
1039 long SessionResponseCode = 0;
1041 curl_easy_getinfo(ConnectionSession, CURLINFO_RESPONSE_CODE, &SessionResponseCode);
1043 if (SessionResponseCode == 200 || SessionResponseCode == 202 || SessionResponseCode == 204){
1045 ValidResponse = true;
1046 } else if (SessionResponseCode == 403){
1048 ValidResponse = true;
1049 } else if (SessionResponseCode >= 400){
1051 ValidResponse = true;
1054 ValidResponse = false;
1057 if (ValidResponse == false || AuthPassed == false){
1058 ServerResponse.RequestResult = COREQUEST_ERROR_SERVER;
1059 ServerResponse.EntityTag = "";
1060 ServerResponse.SessionCode = SessionResult;
1061 ServerResponse.ResultCode = SessionResponseCode;
1062 ServerResponse.ResultMessage = "";
1063 return ServerResponse;
1068 ServerResponse.RequestResult = COREQUEST_OK;
1069 ServerResponse.EntityTag = "";
1070 ServerResponse.SessionCode = SessionResult;
1071 ServerResponse.ResultCode = SessionResponseCode;
1072 ServerResponse.ResultMessage = SessionErrorBuffer;
1073 return ServerResponse;
1077 COServerResponse CardDAV2::GetServerEntityTagValue(std::string Location){
1079 // Check if authentication was successful, otherwise don't do anything.
1081 COServerResponse ServerResponse;
1083 if (AuthPassed == false){
1084 ServerResponse.RequestResult = COREQUEST_ERROR_NOTCONNECTED;
1085 ServerResponse.EntityTag = "";
1086 ServerResponse.SessionCode = 0;
1087 ServerResponse.ResultCode = 0;
1088 ServerResponse.ResultMessage = "";
1089 return ServerResponse;
1092 ServerSSL ? SetupDefaultParametersSSL(true) : SetupDefaultParametersNonSSL(true);
1095 static const char* GetETagQuery =
1096 "<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
1097 "<C:addressbook-query xmlns:D=\"DAV:\""
1098 " xmlns:C=\"urn:ietf:params:xml:ns:carddav\">"
1099 "<D:prop><D:getetag/>"
1102 "</C:addressbook-query>";
1104 string ServerAddressURL = BuildURL(ServerPrefix + Location);
1105 curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddressURL.c_str());
1106 curl_easy_setopt(ConnectionSession, CURLOPT_CUSTOMREQUEST, "REPORT");
1107 curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDS, GetETagQuery);
1108 curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDSIZE, strlen(GetETagQuery));
1110 if (TestMode == true){
1111 SessionResult = curl_easy_perform(ConnectionSession);
1113 SessionResult = curl_easy_perform(ConnectionSession);
1116 switch(SessionResult){
1119 SSLVerified = COSSL_VERIFIED;
1121 case CURLE_SSL_CACERT:
1122 case CURLE_SSL_CONNECT_ERROR:
1124 SSLVerified = COSSL_UNABLETOVERIFY;
1130 long SessionResponseCode = 0;
1132 curl_easy_getinfo(ConnectionSession, CURLINFO_RESPONSE_CODE, &SessionResponseCode);
1134 if (SessionResponseCode == 207){
1136 ValidResponse = true;
1137 } else if (SessionResponseCode == 403){
1139 ValidResponse = true;
1140 } else if (SessionResponseCode >= 400){
1142 ValidResponse = true;
1145 ValidResponse = false;
1148 if (ValidResponse == false || AuthPassed == false){
1149 ServerResponse.RequestResult = COREQUEST_ERROR_SERVER;
1150 ServerResponse.EntityTag = "";
1151 ServerResponse.SessionCode = SessionResult;
1152 ServerResponse.ResultCode = SessionResponseCode;
1153 ServerResponse.ResultMessage = "";
1154 return ServerResponse;
1159 ServerResponse.RequestResult = COREQUEST_OK;
1160 ServerResponse.EntityTag = GetETagValue();
1161 ServerResponse.SessionCode = SessionResult;
1162 ServerResponse.ResultCode = SessionResponseCode;
1163 ServerResponse.ResultMessage = SessionErrorBuffer;
1165 return ServerResponse;
1169 COServerResponse CardDAV2::GetContact(std::string Location, std::string *ContactData){
1171 // Check if authentication was successful, otherwise don't do anything.
1173 COServerResponse ServerResponse;
1175 if (AuthPassed == false){
1176 ServerResponse.RequestResult = COREQUEST_ERROR_NOTCONNECTED;
1177 ServerResponse.EntityTag = "";
1178 ServerResponse.SessionCode = 0;
1179 ServerResponse.ResultCode = 0;
1180 ServerResponse.ResultMessage = "";
1181 return ServerResponse;
1184 ServerSSL ? SetupDefaultParametersSSL(true) : SetupDefaultParametersNonSSL(true);
1187 string ServerAddressURL = BuildURL(ServerPrefix + Location);
1188 curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddressURL.c_str());
1189 curl_easy_setopt(ConnectionSession, CURLOPT_CUSTOMREQUEST, "GET");
1191 if (TestMode == true){
1192 SessionResult = curl_easy_perform(ConnectionSession);
1194 SessionResult = curl_easy_perform(ConnectionSession);
1197 switch(SessionResult){
1200 SSLVerified = COSSL_VERIFIED;
1202 case CURLE_SSL_CACERT:
1203 case CURLE_SSL_CONNECT_ERROR:
1205 SSLVerified = COSSL_UNABLETOVERIFY;
1211 long SessionResponseCode = 0;
1213 curl_easy_getinfo(ConnectionSession, CURLINFO_RESPONSE_CODE, &SessionResponseCode);
1215 if (SessionResponseCode == 200){
1217 ValidResponse = true;
1218 } else if (SessionResponseCode == 403){
1220 ValidResponse = true;
1221 } else if (SessionResponseCode >= 400){
1223 ValidResponse = true;
1226 ValidResponse = false;
1229 if (ValidResponse == false && AuthPassed == false){
1230 ServerResponse.RequestResult = COREQUEST_ERROR_SERVER;
1231 ServerResponse.EntityTag = "";
1232 ServerResponse.SessionCode = SessionResult;
1233 ServerResponse.ResultCode = SessionResponseCode;
1234 ServerResponse.ResultMessage = "";
1235 return ServerResponse;
1240 ServerResponse.RequestResult = COREQUEST_OK;
1241 ServerResponse.EntityTag = "";
1242 ServerResponse.SessionCode = SessionResult;
1243 ServerResponse.ResultCode = SessionResponseCode;
1244 ServerResponse.ResultMessage = SessionErrorBuffer;
1246 (*ContactData) = PageData;
1248 return ServerResponse;
1252 COContactList CardDAV2::GetContactList(std::string SyncToken){
1254 COContactList ServerContactList;
1256 // Check if authentication was successful, otherwise don't do anything.
1258 if (AuthPassed == false){
1259 ServerContactList.ServerResponse.RequestResult = COREQUEST_ERROR_NOTCONNECTED;
1260 ServerContactList.ServerResponse.EntityTag = "";
1261 ServerContactList.ServerResponse.SessionCode = 0;
1262 ServerContactList.ServerResponse.ResultCode = 0;
1263 ServerContactList.ServerResponse.ResultMessage = "";
1264 return ServerContactList;
1267 ServerSSL ? SetupDefaultParametersSSL(true) : SetupDefaultParametersNonSSL(true);
1270 std::string SyncData;
1272 if (SyncToken.size() > 0){
1274 SyncData = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"
1275 "<D:sync-collection xmlns:D=\"DAV:\"\n"
1276 " xmlns:C=\"urn:ietf:params:xml:ns:carddav\">\n"
1278 SyncData.append(SyncToken);
1279 SyncData.append("</D:sync-token>\n"
1280 "<D:sync-level>1</D:sync-level>\n"
1284 "</D:sync-collection>");
1288 SyncData = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"
1289 "<D:sync-collection xmlns:D=\"DAV:\"\n"
1290 " xmlns:C=\"urn:ietf:params:xml:ns:carddav\">\n"
1291 "<D:sync-level>1</D:sync-level>\n"
1295 "</D:sync-collection>";
1299 string ServerAddressURL = BuildURL(ServerPrefix);
1301 curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddressURL.c_str());
1302 curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDS, SyncData.c_str());
1303 curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDSIZE, strlen(SyncData.c_str()));
1304 curl_easy_setopt(ConnectionSession, CURLOPT_CUSTOMREQUEST, "REPORT");
1306 HeaderList = curl_slist_append(HeaderList, "Content-Type: application/xml; charset=utf-8");
1307 HeaderList = curl_slist_append(HeaderList, "Depth: 1");
1309 curl_easy_setopt(ConnectionSession, CURLOPT_HTTPHEADER, HeaderList);
1311 if (TestMode == true){
1312 SessionResult = curl_easy_perform(ConnectionSession);
1314 SessionResult = curl_easy_perform(ConnectionSession);
1317 switch(SessionResult){
1320 SSLVerified = COSSL_VERIFIED;
1322 case CURLE_SSL_CACERT:
1323 case CURLE_SSL_CONNECT_ERROR:
1325 SSLVerified = COSSL_UNABLETOVERIFY;
1331 long SessionResponseCode = 0;
1333 curl_easy_getinfo(ConnectionSession, CURLINFO_RESPONSE_CODE, &SessionResponseCode);
1335 if (SessionResponseCode == 207){
1337 ValidResponse = true;
1338 } else if (SessionResponseCode == 403){
1340 ValidResponse = true;
1341 } else if (SessionResponseCode >= 400){
1343 ValidResponse = true;
1346 ValidResponse = false;
1349 if (ValidResponse == false || AuthPassed == false){
1350 ServerContactList.ServerResponse.RequestResult = COREQUEST_ERROR_SERVER;
1351 ServerContactList.ServerResponse.EntityTag = "";
1352 ServerContactList.ServerResponse.SessionCode = SessionResult;
1353 ServerContactList.ServerResponse.ResultCode = SessionResponseCode;
1354 ServerContactList.ServerResponse.ResultMessage = "";
1355 return ServerContactList;
1360 ProcessContactData(&ServerContactList);
1362 ServerContactList.ServerResponse.RequestResult = COREQUEST_OK;
1363 ServerContactList.ServerResponse.EntityTag = "";
1364 ServerContactList.ServerResponse.SessionCode = SessionResult;
1365 ServerContactList.ServerResponse.ResultCode = SessionResponseCode;
1366 ServerContactList.ServerResponse.ResultMessage = SessionErrorBuffer;
1368 return ServerContactList;
1372 bool CardDAV2::CanDoProcessing(){
1376 bool CardDAV2::CanDoSSL(){
1380 COSSLVerified CardDAV2::SSLVerify(){
1384 bool CardDAV2::AbleToLogin(){
1388 bool CardDAV2::HasValidResponse(){
1389 return ValidResponse;
1392 bool CardDAV2::IsSelfSigned(){
1393 return SSLSelfSigned;
1396 void CardDAV2::SetupDefaultParametersNonSSL(bool DoAuthentication){
1398 std::string ServerAddress = "";
1400 string ServerAddressURL = "http://" + ServerAddress + ":" + to_string(ServerPort) + "/";
1401 string UsernamePassword = ServerUser + ":" + ServerPass;
1403 PageDataObject.CardDAV2Object = this;
1404 PageDataObject.ConnectionSessionObject = ConnectionSession;
1405 PageDataObject.DataSetting = &PageData;
1406 PageDataObject.ServerUsingSSL = false;
1408 PageHeaderObject.CardDAV2Object = this;
1409 PageHeaderObject.ConnectionSessionObject = ConnectionSession;
1410 PageHeaderObject.DataSetting = &PageHeader;
1411 PageHeaderObject.ServerUsingSSL = false;
1413 curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddress.c_str());
1414 curl_easy_setopt(ConnectionSession, CURLOPT_NOPROGRESS, 1L);
1415 curl_easy_setopt(ConnectionSession, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST|CURLAUTH_BASIC);
1416 curl_easy_setopt(ConnectionSession, CURLOPT_TIMEOUT, 60);
1417 curl_easy_setopt(ConnectionSession, CURLOPT_FAILONERROR, true);
1418 curl_easy_setopt(ConnectionSession, CURLOPT_USERAGENT, XSDAB_USERAGENT);
1419 curl_easy_setopt(ConnectionSession, CURLOPT_WRITEFUNCTION, CardDAV2::WritebackFunc);
1420 curl_easy_setopt(ConnectionSession, CURLOPT_WRITEDATA, &PageDataObject);
1421 curl_easy_setopt(ConnectionSession, CURLOPT_WRITEHEADER, &PageHeaderObject);
1422 curl_easy_setopt(ConnectionSession, CURLOPT_NOSIGNAL, 1L);
1423 curl_easy_setopt(ConnectionSession, CURLOPT_CUSTOMREQUEST, "GET");
1424 curl_easy_setopt(ConnectionSession, CURLOPT_HTTPHEADER, nullptr);
1425 curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDS, nullptr);
1426 curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDSIZE, 0L);
1428 if (DoAuthentication == true){
1429 curl_easy_setopt(ConnectionSession, CURLOPT_USERPWD, UsernamePassword.c_str());
1431 curl_easy_setopt(ConnectionSession, CURLOPT_USERPWD, NULL);
1436 void CardDAV2::SetupDefaultParametersSSL(bool DoAuthentication){
1438 // Setup the default parameters.
1440 string ServerAddressURL = "https://" + ServerAddress + ":" + to_string(ServerPort) + "/";
1441 string UsernamePassword = ServerUser + ":" + ServerPass;
1443 PageDataObject.CardDAV2Object = this;
1444 PageDataObject.ConnectionSessionObject = ConnectionSession;
1445 PageDataObject.DataSetting = &PageData;
1446 PageDataObject.ServerUsingSSL = true;
1448 PageHeaderObject.CardDAV2Object = this;
1449 PageHeaderObject.ConnectionSessionObject = ConnectionSession;
1450 PageHeaderObject.DataSetting = &PageHeader;
1451 PageHeaderObject.ServerUsingSSL = true;
1453 curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddressURL.c_str());
1454 curl_easy_setopt(ConnectionSession, CURLOPT_NOPROGRESS, 1L);
1455 curl_easy_setopt(ConnectionSession, CURLOPT_CERTINFO, 1L);
1456 curl_easy_setopt(ConnectionSession, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST|CURLAUTH_BASIC);
1457 curl_easy_setopt(ConnectionSession, CURLOPT_TIMEOUT, 60);
1458 curl_easy_setopt(ConnectionSession, CURLOPT_FAILONERROR, 0L);
1459 curl_easy_setopt(ConnectionSession, CURLOPT_USERAGENT, XSDAB_USERAGENT);
1460 curl_easy_setopt(ConnectionSession, CURLOPT_WRITEFUNCTION, CardDAV2::WritebackFunc);
1461 curl_easy_setopt(ConnectionSession, CURLOPT_WRITEDATA, &PageDataObject);
1462 curl_easy_setopt(ConnectionSession, CURLOPT_WRITEHEADER, &PageHeaderObject);
1463 curl_easy_setopt(ConnectionSession, CURLOPT_ERRORBUFFER, SessionErrorBuffer);
1464 curl_easy_setopt(ConnectionSession, CURLOPT_CUSTOMREQUEST, "GET");
1465 curl_easy_setopt(ConnectionSession, CURLOPT_HTTPHEADER, nullptr);
1466 curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDS, nullptr);
1467 curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDSIZE, 0L);
1469 if (DoAuthentication == true){
1470 curl_easy_setopt(ConnectionSession, CURLOPT_USERPWD, UsernamePassword.c_str());
1472 curl_easy_setopt(ConnectionSession, CURLOPT_USERPWD, NULL);
1475 if (EnableSSLBypass == true){
1476 curl_easy_setopt(ConnectionSession, CURLOPT_SSL_VERIFYHOST, 0L);
1477 curl_easy_setopt(ConnectionSession, CURLOPT_SSL_VERIFYPEER, 0L);
1478 curl_easy_setopt(ConnectionSession, CURLOPT_SSL_VERIFYSTATUS, 0L);
1480 curl_easy_setopt(ConnectionSession, CURLOPT_SSL_VERIFYHOST, 2L);
1481 curl_easy_setopt(ConnectionSession, CURLOPT_SSL_VERIFYPEER, 1L);
1482 curl_easy_setopt(ConnectionSession, CURLOPT_SSL_VERIFYSTATUS, 1L);
1485 #if !defined(__APPLE__) || defined(__WIN32__)
1487 if (TestMode == false && ServerAccount.size() > 0){
1489 // Check if the server certificate file exists.
1491 string CertificateFilename = GetAccountDir(ServerAccount, true);
1493 if (wxFile::Exists(CertificateFilename)){
1495 curl_easy_setopt(ConnectionSession, CURLOPT_CAINFO, CertificateFilename.c_str());
1497 // Force CURLOPT_SSL_VERIFYSTATUS to 0.
1498 curl_easy_setopt(ConnectionSession, CURLOPT_SSL_VERIFYSTATUS, 0L);
1508 string CardDAV2::BuildURL(string URI){
1510 string ServerAddressURL;
1512 if (ServerSSL == true){
1513 ServerAddressURL = "https://" + ServerAddress + ":" + to_string(ServerPort) + URI;
1515 ServerAddressURL = "http://" + ServerAddress + ":" + to_string(ServerPort) + URI;
1518 return ServerAddressURL;
1522 string CardDAV2::GetErrorMessage(){
1524 ErrorMessage = SessionErrorBuffer;
1525 return ErrorMessage;
1529 void CardDAV2::ResetResults(){
1532 COSSLVerified SSLVerified = COSSL_NORESULT;
1533 ValidResponse = false;
1536 SSLSelfSigned = false;
1537 TaskCompleted = false;
1539 SessionErrorBuffer[0] = '\0';
1540 SessionResult = CURLE_OK;
1543 if (HeaderList != nullptr){
1544 curl_slist_free_all(HeaderList);
1545 HeaderList = nullptr;
1550 string CardDAV2::GetETagValue(){
1552 xmlDocPtr xmlCardDAVDoc;
1554 xmlCardDAVDoc = xmlReadMemory(PageData.c_str(), (int)PageData.size(), "noname.xml", NULL, 0);
1556 xmlNodePtr nodeLevel1;
1557 xmlNodePtr nodeLevel2;
1558 xmlNodePtr nodeLevel3;
1559 xmlNodePtr nodeLevel4;
1560 xmlNodePtr nodeLevel5;
1561 xmlNodePtr nodeLevel6;
1563 //std::map<wxString,wxString> xmlDataMap;
1565 std::string DataFilename;
1566 std::string ETagData;
1568 std::string xmlStringSafe;
1569 std::string ETagValue;
1571 // Tranverse through the catacombs of the response to get our ETag for the file.
1573 for (nodeLevel1 = xmlCardDAVDoc->children;
1575 nodeLevel1 = nodeLevel1->next)
1578 bool HREFFound = FALSE;
1579 bool ETagFound = FALSE;
1581 for (nodeLevel2 = nodeLevel1->children;
1583 nodeLevel2 = nodeLevel2->next)
1586 for (nodeLevel3 = nodeLevel2->children;
1588 nodeLevel3 = nodeLevel3->next)
1591 if (!xmlStrcmp(nodeLevel3->name, (const xmlChar *)"href") ||
1592 !xmlStrcmp(nodeLevel3->name, (const xmlChar *)"d:href") ||
1593 !xmlStrcmp(nodeLevel3->name, (const xmlChar *)"D:href")
1596 // Get the filename.
1598 for (nodeLevel4 = nodeLevel3->children;
1600 nodeLevel4 = nodeLevel4->next)
1603 if (!xmlStrcmp(nodeLevel4->name, (const xmlChar *)"text") ||
1604 !xmlStrcmp(nodeLevel4->name, (const xmlChar *)"d:text") ||
1605 !xmlStrcmp(nodeLevel4->name, (const xmlChar *)"D:text")
1608 DataFilename = wxString::FromUTF8((const char*)nodeLevel4->content);
1609 wxStringTokenizer wSTDFilename(DataFilename, wxT("/"));
1611 while (wSTDFilename.HasMoreTokens()){
1613 DataFilename = wSTDFilename.GetNextToken().ToStdString();
1627 for (nodeLevel4 = nodeLevel3->children;
1629 nodeLevel4 = nodeLevel4->next)
1632 for (nodeLevel5 = nodeLevel4->children;
1634 nodeLevel5 = nodeLevel5->next)
1637 if (!xmlStrcmp(nodeLevel5->name, (const xmlChar *)"getetag") ||
1638 !xmlStrcmp(nodeLevel5->name, (const xmlChar *)"d:getetag") ||
1639 !xmlStrcmp(nodeLevel5->name, (const xmlChar *)"D:getetag")
1642 for (nodeLevel6 = nodeLevel5->children;
1644 nodeLevel6 = nodeLevel6->next)
1647 // Strip the quotes from the ETag.
1649 ETagData = (const char*)nodeLevel6->content;
1650 if (ETagData[0] == '"' && ETagData[(ETagData.size() - 1)] == '"'){
1652 ETagData.erase(0, 1);
1653 ETagData.erase((ETagData.size() - 1));
1673 if (HREFFound == TRUE && ETagFound == TRUE){
1675 // Add to the map data.
1677 ETagValue = ETagData;
1688 xmlFreeDoc(xmlCardDAVDoc);
1694 string CardDAV2::GetETagHeader(){
1696 // Go through each of the lines looking for the
1701 bool FastForward = false;
1703 for (int HeaderSeek = 0; HeaderSeek < PageHeader.size(); HeaderSeek++){
1705 if (FastForward == true){
1707 if (PageHeader[HeaderSeek] == '\n'){
1708 FastForward = false;
1716 PageHeader.substr(HeaderSeek, 5) == "ETag:";
1719 catch (const out_of_range &oor){
1723 if (PageHeader.substr(HeaderSeek, 5) == "ETag:"){
1725 int CharacterSeek = 5;
1727 while ((HeaderSeek + CharacterSeek) < PageHeader.size()){
1729 if (PageHeader.substr((HeaderSeek + CharacterSeek), 2) == "\r\n"){
1733 HeaderValue += PageHeader.substr((HeaderSeek + CharacterSeek), 1);
1746 if (PageHeader[HeaderSeek] == '\n'){
1750 //HeaderName += PageHeader.substr(HeaderSeek, 1);
1754 // Check for quotation marks at the start and end and strip
1757 if (HeaderValue.size() >= 2){
1759 if (HeaderValue[0] == '"'){
1760 HeaderValue.erase((HeaderValue.size() - 1));
1761 HeaderValue.erase(0);
1770 vector<string> CardDAV2::GetDAVHeader(){
1772 // Go through each of the lines looking for the
1777 bool FastForward = false;
1778 vector<string> DAVHeaderList;
1780 for (int HeaderSeek = 0; HeaderSeek < PageHeader.size(); HeaderSeek++){
1782 if (FastForward == true){
1784 if (PageHeader[HeaderSeek] == '\n'){
1785 FastForward = false;
1793 PageHeader.substr(HeaderSeek, 4) == "DAV:";
1796 catch (const out_of_range &oor){
1800 if (PageHeader.substr(HeaderSeek, 4) == "DAV:"){
1802 int CharacterSeek = 5;
1804 while ((HeaderSeek + CharacterSeek) < PageHeader.size()){
1806 if (PageHeader.substr((HeaderSeek + CharacterSeek), 2) == "\r\n"){
1810 HeaderValue += PageHeader.substr((HeaderSeek + CharacterSeek), 1);
1823 if (PageHeader[HeaderSeek] == '\n'){
1827 //HeaderName += PageHeader.substr(HeaderSeek, 1);
1831 // Split the header data.
1833 std::string DAVHeaderValue;
1835 for (int HeaderSeek = 0; HeaderSeek < HeaderValue.size(); HeaderSeek++){
1837 if (HeaderValue.substr(HeaderSeek, 1) == ","){
1838 DAVHeaderList.push_back(DAVHeaderValue);
1839 DAVHeaderValue = "";
1844 DAVHeaderValue += HeaderValue[HeaderSeek];
1848 if (DAVHeaderValue.size() > 0){
1850 DAVHeaderList.push_back(DAVHeaderValue);
1854 return DAVHeaderList;
1858 void CardDAV2::ProcessContactData(COContactList *ContactList){
1860 xmlDocPtr xmlCardDAVDoc;
1861 xmlCardDAVDoc = xmlReadMemory(PageData.c_str(), (int)PageData.size(), "noname.xml", NULL, 0);
1863 xmlNodePtr MultiStatusNode;
1864 xmlNodePtr ResponseNode;
1865 xmlNodePtr ResponseDataNode;
1866 xmlNodePtr PropStatNode;
1867 xmlNodePtr ValueNode;
1868 xmlNodePtr ETagNode;
1869 xmlNodePtr StatusNode;
1871 std::string HREFValue;
1872 std::string ETagValue;
1873 std::string StatusValue;
1874 std::string SyncValue;
1876 // Go through the document!
1878 MultiStatusNode = xmlCardDAVDoc->children;
1880 if (MultiStatusNode == nullptr){
1884 bool SyncTokenFound = false;
1886 // Tranverse through the catacombs of the response to get our ETag for the file and
1887 // the server syncronisation token.
1889 for (ResponseNode = MultiStatusNode->children;
1890 ResponseNode != nullptr;
1891 ResponseNode = ResponseNode->next){
1893 // Check if tag is response or sync-token.
1895 if (!xmlStrcmp(ResponseNode->name, (const xmlChar *)"response") ||
1896 !xmlStrcmp(ResponseNode->name, (const xmlChar *)"d:response") ||
1897 !xmlStrcmp(ResponseNode->name, (const xmlChar *)"D:response")){
1899 COContactStatus ContactStatus = COCS_UNKNOWN;
1901 for (ResponseDataNode = ResponseNode->children;
1902 ResponseDataNode != nullptr;
1903 ResponseDataNode = ResponseDataNode->next){
1905 if (!xmlStrcmp(ResponseDataNode->name, (const xmlChar *)"href") ||
1906 !xmlStrcmp(ResponseDataNode->name, (const xmlChar *)"d:href") ||
1907 !xmlStrcmp(ResponseDataNode->name, (const xmlChar *)"D:href")){
1909 HREFValue = (const char*)ResponseDataNode->children->content;
1911 // Get the filename after the last forward slash.
1915 for (int HREFValueSeek = 0; HREFValueSeek < HREFValue.size(); HREFValueSeek++){
1917 if (HREFValue[HREFValueSeek] == '/'){
1919 LastSlash = HREFValueSeek;
1925 HREFValue = HREFValue.substr((LastSlash + 1));
1927 } else if (!xmlStrcmp(ResponseDataNode->name, (const xmlChar *)"propstat") ||
1928 !xmlStrcmp(ResponseDataNode->name, (const xmlChar *)"d:propstat") ||
1929 !xmlStrcmp(ResponseDataNode->name, (const xmlChar *)"D:propstat")){
1931 for (PropStatNode = ResponseDataNode->children;
1932 PropStatNode != nullptr;
1933 PropStatNode = PropStatNode->next){
1935 if (!xmlStrcmp(PropStatNode->name, (const xmlChar *)"prop") ||
1936 !xmlStrcmp(PropStatNode->name, (const xmlChar *)"d:prop") ||
1937 !xmlStrcmp(PropStatNode->name, (const xmlChar *)"D:prop")){
1939 for (ETagNode = PropStatNode->children;
1940 ETagNode != nullptr;
1941 ETagNode = ETagNode->next){
1943 if (!xmlStrcmp(ETagNode->name, (const xmlChar *)"getetag") ||
1944 !xmlStrcmp(ETagNode->name, (const xmlChar *)"getetag") ||
1945 !xmlStrcmp(ETagNode->name, (const xmlChar *)"getetag")){
1947 ETagValue = (const char*)ETagNode->children->content;
1949 if (ETagValue.size() > 2 && ETagValue.substr(0,1) == "\""){
1950 ETagValue.erase((ETagValue.size() - 1),1);
1951 ETagValue.erase(0,1);
1959 } else if (!xmlStrcmp(PropStatNode->name, (const xmlChar *)"status") ||
1960 !xmlStrcmp(PropStatNode->name, (const xmlChar *)"d:status") ||
1961 !xmlStrcmp(PropStatNode->name, (const xmlChar *)"D:status")){
1963 StatusValue = (const char*)PropStatNode->children->content;
1965 if (StatusValue == "HTTP/1.1 200 OK"){
1967 ContactStatus = COCS_UPDATED;
1969 } else if (StatusValue == "HTTP/1.1 404 Not Found"){
1971 ContactStatus = COCS_DELETED;
1975 ContactStatus = COCS_UNKNOWN;
1987 COContactData ContactInformation;
1989 ContactInformation.Location = HREFValue;
1990 ContactInformation.Data = ETagValue;
1991 ContactInformation.Status = ContactStatus;
1995 StatusValue.clear();
1997 ContactList->ListData.push_back(ContactInformation);
1999 } else if (!xmlStrcmp(ResponseNode->name, (const xmlChar *)"sync-token") ||
2000 !xmlStrcmp(ResponseNode->name, (const xmlChar *)"d:sync-token") ||
2001 !xmlStrcmp(ResponseNode->name, (const xmlChar *)"D:sync-token")){
2003 SyncValue = (const char*)ResponseNode->children->content;
2009 ContactList->SyncToken = SyncValue;
2011 xmlFreeDoc(xmlCardDAVDoc);