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/>
25 CardDAV2::CardDAV2(string ServerAddress, int ServerPort, string ServerUser, string ServerPass, bool ServerSSL){
27 this->ServerAddress = ServerAddress;
28 this->ServerPort = ServerPort;
29 this->ServerUser = ServerUser;
30 this->ServerPass = ServerPass;
31 this->ServerSSL = ServerSSL;
34 this->SetupConnectionObject();
38 CardDAV2::CardDAV2(string ServerAddress, int ServerPort, string ServerUser, string ServerPass, bool ServerSSL, string ServerPrefix, string ServerAccount){
40 this->ServerAddress = ServerAddress;
41 this->ServerPort = ServerPort;
42 this->ServerUser = ServerUser;
43 this->ServerPass = ServerPass;
44 this->ServerSSL = ServerSSL;
45 this->ServerPrefix = ServerPrefix;
46 this->ServerAccount = ServerAccount;
50 this->SetupConnectionObject();
54 size_t CardDAV2::WritebackFunc(char *ptr, size_t size, size_t nmemb, void *stream){
56 return static_cast<CardDAV2PassObject*>(stream)->CardDAV2Object->WritebackFuncImplementation(ptr, size, nmemb, stream);
60 size_t CardDAV2::WritebackFuncImplementation(char *ptr, size_t size, size_t nmemb, void *stream){
62 // Writeback function for the CardDAV object.
64 CardDAV2PassObject *data = static_cast<CardDAV2PassObject*>(stream);
65 data->DataSetting->append(ptr);
67 // Get the SSL engine pointer and trust if required on certain operating systems.
69 if (data->ServerUsingSSL == true) {
71 #if defined(__APPLE__)
73 const struct curl_tlssessioninfo *TLSInfo;
75 CURL *Connection = GetConnectionObject();
76 TLSCode = curl_easy_getinfo(Connection, CURLINFO_TLS_SSL_PTR, &TLSInfo);
78 if (TLSInfo->internals != nullptr && TLSCode == CURLE_OK) {
79 SSLCopyPeerTrust((SSLContext*)TLSInfo->internals, &SecTrustObject);
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 #elif defined(__WIN32__)
141 PCCERT_CONTEXT CardDAV2::BuildSSLCollection(){
143 return CertificateData;
149 SSLCertCollectionString CardDAV2::BuildSSLCollection(){
151 // Build and return the SSL collection.
153 SSLCertCollectionString SSLCertInfo;
155 // Grab the certificate data.
158 struct curl_slist *certdata;
159 struct curl_certinfo *certinfo;
162 certptr.certdata = NULL;
164 curl_easy_getinfo(ConnectionSession, CURLINFO_CERTINFO, &certptr.certinfo);
166 std::string CertPropName;
167 std::string CertPropValue;
169 for (int i = 0; i < certptr.certinfo->num_of_certs; i++){
171 struct curl_slist *slist;
172 SSLCertDataString SSLCertDataInc;
174 for (slist = certptr.certinfo->certinfo[i]; slist; slist = slist->next){
176 // Using wxStringTokenizer from wxWidgets.
178 wxStringTokenizer CertDataInc(wxString::FromUTF8(slist->data), ":");
180 // Get first token as the property name.
182 CertPropName = CertDataInc.GetNextToken().ToStdString();
184 // Get remaining tokens as the property value.
186 while(CertDataInc.HasMoreTokens()){
188 CertPropValue.append(CertDataInc.GetNextToken());
192 SSLCertDataInc.CertData.insert(std::make_pair(CertPropName, CertPropValue));
193 CertPropName.clear();
194 CertPropValue.clear();
198 SSLCertInfo.SSLCollection.insert(std::make_pair(i, SSLCertDataInc));
208 void CardDAV2::BypassSSLVerification(bool EnableBypass) {
209 EnableSSLBypass = EnableBypass;
210 SSLSelfSigned = EnableBypass;
213 void CardDAV2::SetupConnectionObject(){
214 ConnectionSession = curl_easy_init();
217 bool CardDAV2::IsTaskCompleted(){
221 COConnectResult CardDAV2::Connect(bool DoAuthentication){
223 ServerSSL ? SetupDefaultParametersSSL(DoAuthentication) : SetupDefaultParametersNonSSL(DoAuthentication);
226 COConnectResult ConnectResult = COCONNECT_UNITTESTFAIL;
227 string ServerAddressURL = BuildURL("/principals/");
229 curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddressURL.c_str());
231 if (TestMode == true){
232 SessionResult = curl_easy_perform(ConnectionSession);
234 SessionResult = curl_easy_perform(ConnectionSession);
237 switch(SessionResult){
239 case CURLE_HTTP_RETURNED_ERROR:
241 SSLVerified = COSSL_VERIFIED;
242 ConnectResult = COCONNECT_OK;
244 case CURLE_SSL_CACERT:
245 case CURLE_SSL_CONNECT_ERROR:
247 ConnectResult = COCONNECT_OK;
248 SSLVerified = COSSL_UNABLETOVERIFY;
251 ConnectResult = COCONNECT_INVALID;
255 // Set the certificate data (if required).
257 #if defined(__WIN32__)
261 CertificateData = PageHeaderObject.SSLContext;
267 // Check if an error occured before continuing.
269 // Check if authentication was successful.
271 long SessionResponseCode = 0;
273 curl_easy_getinfo(ConnectionSession, CURLINFO_RESPONSE_CODE, &SessionResponseCode);
275 if (DoAuthentication == true){
277 // Get the HTTP status code (Should be 200 and not 403).
278 // Return error otherwise.
280 if (SessionResponseCode == 200){
281 ConnectResult = COCONNECT_OK;
283 ValidResponse = true;
284 } else if (SessionResponseCode == 401){
285 ConnectResult = COCONNECT_AUTHFAIL;
287 ValidResponse = true;
288 } else if (SessionResponseCode >= 200) {
289 ConnectResult = COCONNECT_INVALID;
291 ValidResponse = true;
293 ConnectResult = COCONNECT_INVALID;
295 ValidResponse = false;
300 ValidResponse = true;
304 // Check the header to see if CardDAV is supported.
306 vector<string> DAVHeaderValues = GetDAVHeader();
308 for (vector<string>::iterator DAVHeaderValuesIter = DAVHeaderValues.begin();
309 DAVHeaderValuesIter != DAVHeaderValues.end(); DAVHeaderValuesIter++){
311 if ((*DAVHeaderValuesIter) == "addressbook"){
318 return ConnectResult;
322 COServerResponse CardDAV2::GetDefaultPrefix(string *ServerPrefix){
324 // Check if authentication was successful, otherwise don't do anything.
326 COServerResponse ServerResponse;
328 if (AuthPassed == false){
329 ServerResponse.RequestResult = COREQUEST_ERROR_NOTCONNECTED;
330 ServerResponse.EntityTag = "";
331 ServerResponse.SessionCode = 0;
332 ServerResponse.ResultCode = 0;
333 ServerResponse.ResultMessage = "";
334 return ServerResponse;
337 ServerSSL ? SetupDefaultParametersSSL(true) : SetupDefaultParametersNonSSL(true);
340 // Need to do three requests:
342 // 1. Get the current user principal URI.
343 // 2. Get the address book home URI.
344 // 3. Get the default address book URI.
346 // Setup the first query finding out where the principal URL is.
348 const char* CurrentUserPrincipalXMLQuery = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"
349 "<D:propfind xmlns:D=\"DAV:\">\n"
351 " <D:current-user-principal/>\n"
355 // Setup the second query finding out where the address book home URL is.
357 const char* AddressBookHomeXMLQuery = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"
358 "<D:propfind xmlns:D=\"DAV:\""
359 " xmlns:C=\"urn:ietf:params:xml:ns:carddav\">\n"
361 " <C:addressbook-home-set/>\n"
365 // Setup the third query finding out where the default address book URL is.
367 const char* DefaultAddressBookXMLQuery = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"
368 "<D:propfind xmlns:D=\"DAV:\""
369 " xmlns:C=\"urn:ietf:params:xml:ns:carddav\">\n"
371 " <C:default-addressbook-URL/>\n"
375 string ServerAddressURL = BuildURL("/principals/");
376 curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddressURL.c_str());
377 curl_easy_setopt(ConnectionSession, CURLOPT_CUSTOMREQUEST, "PROPFIND");
378 curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDS, CurrentUserPrincipalXMLQuery);
379 curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDSIZE, strlen(CurrentUserPrincipalXMLQuery));
381 if (TestMode == true){
382 SessionResult = curl_easy_perform(ConnectionSession);
387 switch(SessionResult){
390 SSLVerified = COSSL_VERIFIED;
392 case CURLE_SSL_CACERT:
393 case CURLE_SSL_CONNECT_ERROR:
395 SSLVerified = COSSL_UNABLETOVERIFY;
401 long SessionResponseCode = 0;
403 curl_easy_getinfo(ConnectionSession, CURLINFO_RESPONSE_CODE, &SessionResponseCode);
405 if (SessionResponseCode == 200 || SessionResponseCode == 207){
407 ValidResponse = true;
408 } else if (SessionResponseCode == 403){
410 ValidResponse = true;
411 } else if (SessionResponseCode >= 400) {
413 ValidResponse = true;
416 ValidResponse = false;
419 if (ValidResponse == false && AuthPassed == false){
420 ServerResponse.RequestResult = COREQUEST_ERROR_SERVER;
421 ServerResponse.EntityTag = "";
422 ServerResponse.SessionCode = SessionResult;
423 ServerResponse.ResultCode = SessionResponseCode;
424 ServerResponse.ResultMessage = "";
425 return ServerResponse;
428 // Process the first response.
430 string UserPrincipalURI = GetUserPrincipalURI();
432 // Cleanup and reset for the second connection.
434 ServerSSL ? SetupDefaultParametersSSL(true) : SetupDefaultParametersNonSSL(true);
437 ServerAddressURL = BuildURL(UserPrincipalURI);
438 curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddressURL.c_str());
439 curl_easy_setopt(ConnectionSession, CURLOPT_CUSTOMREQUEST, "PROPFIND");
440 curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDS, AddressBookHomeXMLQuery);
441 curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDSIZE, strlen(AddressBookHomeXMLQuery));
443 if (TestMode == true){
444 SessionResult = curl_easy_perform(ConnectionSession);
449 switch(SessionResult){
452 SSLVerified = COSSL_VERIFIED;
454 case CURLE_SSL_CACERT:
455 case CURLE_SSL_CONNECT_ERROR:
457 SSLVerified = COSSL_UNABLETOVERIFY;
463 SessionResponseCode = 0;
465 curl_easy_getinfo(ConnectionSession, CURLINFO_RESPONSE_CODE, &SessionResponseCode);
467 if (SessionResponseCode == 200 || SessionResponseCode == 207){
469 ValidResponse = true;
470 } else if (SessionResponseCode == 403){
472 ValidResponse = true;
473 } else if (SessionResponseCode >= 400) {
475 ValidResponse = true;
478 ValidResponse = false;
481 if (ValidResponse == false && AuthPassed == false){
482 ServerResponse.RequestResult = COREQUEST_ERROR_SERVER;
483 ServerResponse.EntityTag = "";
484 ServerResponse.SessionCode = SessionResult;
485 ServerResponse.ResultCode = SessionResponseCode;
486 ServerResponse.ResultMessage = "";
487 return ServerResponse;
490 // Process the second response.
492 string AddressBookHomeURI = GetAddressBookHomeURI();
494 // Cleanup and reset for the second connection.
496 ServerSSL ? SetupDefaultParametersSSL(true) : SetupDefaultParametersNonSSL(true);
499 ServerAddressURL = BuildURL(AddressBookHomeURI);
500 curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddressURL.c_str());
501 curl_easy_setopt(ConnectionSession, CURLOPT_CUSTOMREQUEST, "PROPFIND");
502 curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDS, DefaultAddressBookXMLQuery);
503 curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDSIZE, strlen(DefaultAddressBookXMLQuery));
505 if (TestMode == true){
506 SessionResult = curl_easy_perform(ConnectionSession);
511 switch(SessionResult){
514 SSLVerified = COSSL_VERIFIED;
516 case CURLE_SSL_CACERT:
517 case CURLE_SSL_CONNECT_ERROR:
519 SSLVerified = COSSL_UNABLETOVERIFY;
525 SessionResponseCode = 0;
527 curl_easy_getinfo(ConnectionSession, CURLINFO_RESPONSE_CODE, &SessionResponseCode);
529 if (SessionResponseCode == 200 || SessionResponseCode == 207){
531 ValidResponse = true;
532 } else if (SessionResponseCode == 403){
534 ValidResponse = true;
535 } else if (SessionResponseCode >= 200) {
537 ValidResponse = true;
540 ValidResponse = false;
543 if (ValidResponse == false || AuthPassed == false){
544 ServerResponse.RequestResult = COREQUEST_ERROR_SERVER;
545 ServerResponse.EntityTag = "";
546 ServerResponse.SessionCode = SessionResult;
547 ServerResponse.ResultCode = SessionResponseCode;
548 ServerResponse.ResultMessage = "";
549 return ServerResponse;
552 // Process the second response.
554 (*ServerPrefix) = GetDefaultAddressBookURI();
558 ServerResponse.RequestResult = COREQUEST_OK;
559 ServerResponse.EntityTag = "";
560 ServerResponse.SessionCode = SessionResult;
561 ServerResponse.ResultCode = SessionResponseCode;
562 ServerResponse.ResultMessage = SessionErrorBuffer;
563 return ServerResponse;
567 std::string CardDAV2::GetUserPrincipalURI(){
569 xmlDocPtr xmlCardDAVDoc;
570 xmlCardDAVDoc = xmlReadMemory(PageData.c_str(), (int)PageData.size(), "noname.xml", NULL, 0);
571 string UserPrincipalURI = "";
573 xmlNodePtr nodeLevel1;
574 xmlNodePtr nodeLevel2;
575 xmlNodePtr nodeLevel3;
576 xmlNodePtr nodeLevel4;
577 xmlNodePtr nodeLevel5;
578 xmlNodePtr nodeLevel6;
579 xmlNodePtr nodeLevel7;
581 for (nodeLevel1 = xmlCardDAVDoc->children;
583 nodeLevel1 = nodeLevel1->next)
586 for (nodeLevel2 = nodeLevel1->children;
588 nodeLevel2 = nodeLevel2->next)
592 for (nodeLevel3 = nodeLevel2->children;
594 nodeLevel3 = nodeLevel3->next)
597 for (nodeLevel4 = nodeLevel3->children;
599 nodeLevel4 = nodeLevel4->next)
602 for (nodeLevel5 = nodeLevel4->children;
604 nodeLevel5 = nodeLevel5->next)
607 for (nodeLevel6 = nodeLevel5->children;
609 nodeLevel6 = nodeLevel6->next)
612 if (!xmlStrcmp(nodeLevel6->name, (const xmlChar *)"href") ||
613 !xmlStrcmp(nodeLevel6->name, (const xmlChar *)"d:href") ||
614 !xmlStrcmp(nodeLevel6->name, (const xmlChar *)"D:href")
617 // Found the <href> part so extract the principal URL address.
619 for (nodeLevel7 = nodeLevel6->children;
621 nodeLevel7 = nodeLevel7->next)
624 UserPrincipalURI = ((const char*)nodeLevel7->content);
642 xmlFreeDoc(xmlCardDAVDoc);
644 return UserPrincipalURI;
648 std::string CardDAV2::GetAddressBookHomeURI(){
650 xmlDocPtr xmlCardDAVDoc;
651 xmlCardDAVDoc = xmlReadMemory(PageData.c_str(), (int)PageData.size(), "noname.xml", NULL, 0);
652 string AddressBookHomeURI = "";
654 xmlNodePtr nodeLevel1;
655 xmlNodePtr nodeLevel2;
656 xmlNodePtr nodeLevel3;
657 xmlNodePtr nodeLevel4;
658 xmlNodePtr nodeLevel5;
659 xmlNodePtr nodeLevel6;
660 xmlNodePtr nodeLevel7;
662 for (nodeLevel1 = xmlCardDAVDoc->children;
664 nodeLevel1 = nodeLevel1->next)
667 for (nodeLevel2 = nodeLevel1->children;
669 nodeLevel2 = nodeLevel2->next)
673 for (nodeLevel3 = nodeLevel2->children;
675 nodeLevel3 = nodeLevel3->next)
678 for (nodeLevel4 = nodeLevel3->children;
680 nodeLevel4 = nodeLevel4->next)
683 for (nodeLevel5 = nodeLevel4->children;
685 nodeLevel5 = nodeLevel5->next)
688 for (nodeLevel6 = nodeLevel5->children;
690 nodeLevel6 = nodeLevel6->next)
693 if (!xmlStrcmp(nodeLevel6->name, (const xmlChar *)"href") ||
694 !xmlStrcmp(nodeLevel6->name, (const xmlChar *)"d:href") ||
695 !xmlStrcmp(nodeLevel6->name, (const xmlChar *)"D:href")
698 // Found the <href> part so extract the principal URL address.
700 for (nodeLevel7 = nodeLevel6->children;
702 nodeLevel7 = nodeLevel7->next)
705 AddressBookHomeURI = ((const char*)nodeLevel7->content);
723 xmlFreeDoc(xmlCardDAVDoc);
725 return AddressBookHomeURI;
729 std::string CardDAV2::GetDefaultAddressBookURI(){
731 xmlDocPtr xmlCardDAVDoc;
732 xmlCardDAVDoc = xmlReadMemory(PageData.c_str(), (int)PageData.size(), "noname.xml", NULL, 0);
733 string DefaultAddressBookURI = "";
735 xmlNodePtr nodeLevel1;
736 xmlNodePtr nodeLevel2;
737 xmlNodePtr nodeLevel3;
738 xmlNodePtr nodeLevel4;
739 xmlNodePtr nodeLevel5;
740 xmlNodePtr nodeLevel6;
741 xmlNodePtr nodeLevel7;
743 for (nodeLevel1 = xmlCardDAVDoc->children;
745 nodeLevel1 = nodeLevel1->next)
748 for (nodeLevel2 = nodeLevel1->children;
750 nodeLevel2 = nodeLevel2->next)
754 for (nodeLevel3 = nodeLevel2->children;
756 nodeLevel3 = nodeLevel3->next)
759 for (nodeLevel4 = nodeLevel3->children;
761 nodeLevel4 = nodeLevel4->next)
764 for (nodeLevel5 = nodeLevel4->children;
766 nodeLevel5 = nodeLevel5->next)
769 for (nodeLevel6 = nodeLevel5->children;
771 nodeLevel6 = nodeLevel6->next)
774 if (!xmlStrcmp(nodeLevel6->name, (const xmlChar *)"href") ||
775 !xmlStrcmp(nodeLevel6->name, (const xmlChar *)"d:href") ||
776 !xmlStrcmp(nodeLevel6->name, (const xmlChar *)"D:href")
779 // Found the <href> part so extract the principal URL address.
781 for (nodeLevel7 = nodeLevel6->children;
783 nodeLevel7 = nodeLevel7->next)
786 DefaultAddressBookURI = ((const char*)nodeLevel7->content);
804 xmlFreeDoc(xmlCardDAVDoc);
806 return DefaultAddressBookURI;
810 COServerResponse CardDAV2::AddContact(std::string Location, std::string Data){
812 // Check if authentication was successful, otherwise don't do anything.
814 COServerResponse ServerResponse;
816 if (AuthPassed == false){
817 ServerResponse.RequestResult = COREQUEST_ERROR_NOTCONNECTED;
818 ServerResponse.EntityTag = "";
819 ServerResponse.SessionCode = 0;
820 ServerResponse.ResultCode = 0;
821 ServerResponse.ResultMessage = "";
822 return ServerResponse;
825 ServerSSL ? SetupDefaultParametersSSL(true) : SetupDefaultParametersNonSSL(true);
828 string ServerAddressURL = BuildURL(ServerPrefix + Location);
829 curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddressURL.c_str());
830 curl_easy_setopt(ConnectionSession, CURLOPT_CUSTOMREQUEST, "PUT");
831 curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDS, Data.c_str());
832 curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDSIZE, strlen(Data.c_str()));
834 HeaderList = curl_slist_append(HeaderList, "Content-Type: text/vcard; charset=utf-8");
836 curl_easy_setopt(ConnectionSession, CURLOPT_HTTPHEADER, HeaderList);
838 if (TestMode == true){
839 SessionResult = curl_easy_perform(ConnectionSession);
841 SessionResult = curl_easy_perform(ConnectionSession);
844 switch(SessionResult){
847 SSLVerified = COSSL_VERIFIED;
849 case CURLE_SSL_CACERT:
850 case CURLE_SSL_CONNECT_ERROR:
852 SSLVerified = COSSL_UNABLETOVERIFY;
858 long SessionResponseCode = 0;
860 curl_easy_getinfo(ConnectionSession, CURLINFO_RESPONSE_CODE, &SessionResponseCode);
862 if (SessionResponseCode == 200 || SessionResponseCode == 201 || SessionResponseCode == 204){
864 ValidResponse = true;
865 } else if (SessionResponseCode == 403){
867 ValidResponse = true;
868 } else if (SessionResponseCode >= 400){
870 ValidResponse = true;
873 ValidResponse = false;
876 if (ValidResponse == false || AuthPassed == false){
877 ServerResponse.RequestResult = COREQUEST_ERROR_SERVER;
878 ServerResponse.EntityTag = "";
879 ServerResponse.SessionCode = SessionResult;
880 ServerResponse.ResultCode = SessionResponseCode;
881 ServerResponse.ResultMessage = "";
882 return ServerResponse;
887 ServerResponse.RequestResult = COREQUEST_OK;
888 ServerResponse.EntityTag = "";
889 ServerResponse.SessionCode = SessionResult;
890 ServerResponse.ResultCode = SessionResponseCode;
891 ServerResponse.ResultMessage = SessionErrorBuffer;
892 return ServerResponse;
896 COServerResponse CardDAV2::EditContact(std::string Location, std::string Data){
898 // Check if authentication was successful, otherwise don't do anything.
900 COServerResponse ServerResponse;
902 if (AuthPassed == false){
903 ServerResponse.RequestResult = COREQUEST_ERROR_NOTCONNECTED;
904 ServerResponse.EntityTag = "";
905 ServerResponse.SessionCode = 0;
906 ServerResponse.ResultCode = 0;
907 ServerResponse.ResultMessage = "";
908 return ServerResponse;
911 ServerSSL ? SetupDefaultParametersSSL(true) : SetupDefaultParametersNonSSL(true);
914 string ServerAddressURL = BuildURL(ServerPrefix + Location);
915 curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddressURL.c_str());
916 curl_easy_setopt(ConnectionSession, CURLOPT_CUSTOMREQUEST, "PUT");
917 curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDS, Data.c_str());
918 curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDSIZE, strlen(Data.c_str()));
920 HeaderList = curl_slist_append(HeaderList, "Content-Type: text/vcard; charset=utf-8");
922 curl_easy_setopt(ConnectionSession, CURLOPT_HTTPHEADER, HeaderList);
924 if (TestMode == true){
925 SessionResult = curl_easy_perform(ConnectionSession);
927 SessionResult = curl_easy_perform(ConnectionSession);
930 switch(SessionResult){
933 SSLVerified = COSSL_VERIFIED;
935 case CURLE_SSL_CACERT:
936 case CURLE_SSL_CONNECT_ERROR:
938 SSLVerified = COSSL_UNABLETOVERIFY;
944 long SessionResponseCode = 0;
946 curl_easy_getinfo(ConnectionSession, CURLINFO_RESPONSE_CODE, &SessionResponseCode);
948 if (SessionResponseCode == 200 || SessionResponseCode == 201 || SessionResponseCode == 204){
950 ValidResponse = true;
951 } else if (SessionResponseCode == 403){
953 ValidResponse = true;
954 } else if (SessionResponseCode >= 400){
956 ValidResponse = true;
959 ValidResponse = false;
962 if (ValidResponse == false || AuthPassed == false){
963 ServerResponse.RequestResult = COREQUEST_ERROR_SERVER;
964 ServerResponse.EntityTag = "";
965 ServerResponse.SessionCode = SessionResult;
966 ServerResponse.ResultCode = SessionResponseCode;
967 ServerResponse.ResultMessage = "";
968 return ServerResponse;
973 ServerResponse.RequestResult = COREQUEST_OK;
974 ServerResponse.EntityTag = "";
975 ServerResponse.SessionCode = SessionResult;
976 ServerResponse.ResultCode = SessionResponseCode;
977 ServerResponse.ResultMessage = SessionErrorBuffer;
978 return ServerResponse;
982 COServerResponse CardDAV2::DeleteContact(std::string Location){
984 // Check if authentication was successful, otherwise don't do anything.
986 COServerResponse ServerResponse;
988 if (AuthPassed == false){
989 ServerResponse.RequestResult = COREQUEST_ERROR_NOTCONNECTED;
990 ServerResponse.EntityTag = "";
991 ServerResponse.SessionCode = 0;
992 ServerResponse.ResultCode = 0;
993 ServerResponse.ResultMessage = "";
994 return ServerResponse;
997 ServerSSL ? SetupDefaultParametersSSL(true) : SetupDefaultParametersNonSSL(true);
1000 string ServerAddressURL = BuildURL(ServerPrefix + Location);
1001 curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddressURL.c_str());
1002 curl_easy_setopt(ConnectionSession, CURLOPT_CUSTOMREQUEST, "DELETE");
1004 if (TestMode == true){
1005 SessionResult = curl_easy_perform(ConnectionSession);
1007 SessionResult = curl_easy_perform(ConnectionSession);
1010 switch(SessionResult){
1013 SSLVerified = COSSL_VERIFIED;
1015 case CURLE_SSL_CACERT:
1016 case CURLE_SSL_CONNECT_ERROR:
1018 SSLVerified = COSSL_UNABLETOVERIFY;
1024 long SessionResponseCode = 0;
1026 curl_easy_getinfo(ConnectionSession, CURLINFO_RESPONSE_CODE, &SessionResponseCode);
1028 if (SessionResponseCode == 200 || SessionResponseCode == 202 || SessionResponseCode == 204){
1030 ValidResponse = true;
1031 } else if (SessionResponseCode == 403){
1033 ValidResponse = true;
1034 } else if (SessionResponseCode >= 400){
1036 ValidResponse = true;
1039 ValidResponse = false;
1042 if (ValidResponse == false || AuthPassed == false){
1043 ServerResponse.RequestResult = COREQUEST_ERROR_SERVER;
1044 ServerResponse.EntityTag = "";
1045 ServerResponse.SessionCode = SessionResult;
1046 ServerResponse.ResultCode = SessionResponseCode;
1047 ServerResponse.ResultMessage = "";
1048 return ServerResponse;
1053 ServerResponse.RequestResult = COREQUEST_OK;
1054 ServerResponse.EntityTag = "";
1055 ServerResponse.SessionCode = SessionResult;
1056 ServerResponse.ResultCode = SessionResponseCode;
1057 ServerResponse.ResultMessage = SessionErrorBuffer;
1058 return ServerResponse;
1062 COServerResponse CardDAV2::GetServerEntityTagValue(std::string Location){
1064 // Check if authentication was successful, otherwise don't do anything.
1066 COServerResponse ServerResponse;
1068 if (AuthPassed == false){
1069 ServerResponse.RequestResult = COREQUEST_ERROR_NOTCONNECTED;
1070 ServerResponse.EntityTag = "";
1071 ServerResponse.SessionCode = 0;
1072 ServerResponse.ResultCode = 0;
1073 ServerResponse.ResultMessage = "";
1074 return ServerResponse;
1077 ServerSSL ? SetupDefaultParametersSSL(true) : SetupDefaultParametersNonSSL(true);
1080 static const char* GetETagQuery =
1081 "<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
1082 "<C:addressbook-query xmlns:D=\"DAV:\""
1083 " xmlns:C=\"urn:ietf:params:xml:ns:carddav\">"
1084 "<D:prop><D:getetag/>"
1087 "</C:addressbook-query>";
1089 string ServerAddressURL = BuildURL(ServerPrefix + Location);
1090 curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddressURL.c_str());
1091 curl_easy_setopt(ConnectionSession, CURLOPT_CUSTOMREQUEST, "REPORT");
1092 curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDS, GetETagQuery);
1093 curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDSIZE, strlen(GetETagQuery));
1095 if (TestMode == true){
1096 SessionResult = curl_easy_perform(ConnectionSession);
1098 SessionResult = curl_easy_perform(ConnectionSession);
1101 switch(SessionResult){
1104 SSLVerified = COSSL_VERIFIED;
1106 case CURLE_SSL_CACERT:
1107 case CURLE_SSL_CONNECT_ERROR:
1109 SSLVerified = COSSL_UNABLETOVERIFY;
1115 long SessionResponseCode = 0;
1117 curl_easy_getinfo(ConnectionSession, CURLINFO_RESPONSE_CODE, &SessionResponseCode);
1119 if (SessionResponseCode == 207){
1121 ValidResponse = true;
1122 } else if (SessionResponseCode == 403){
1124 ValidResponse = true;
1125 } else if (SessionResponseCode >= 400){
1127 ValidResponse = true;
1130 ValidResponse = false;
1133 if (ValidResponse == false || AuthPassed == false){
1134 ServerResponse.RequestResult = COREQUEST_ERROR_SERVER;
1135 ServerResponse.EntityTag = "";
1136 ServerResponse.SessionCode = SessionResult;
1137 ServerResponse.ResultCode = SessionResponseCode;
1138 ServerResponse.ResultMessage = "";
1139 return ServerResponse;
1144 ServerResponse.RequestResult = COREQUEST_OK;
1145 ServerResponse.EntityTag = GetETagValue();
1146 ServerResponse.SessionCode = SessionResult;
1147 ServerResponse.ResultCode = SessionResponseCode;
1148 ServerResponse.ResultMessage = SessionErrorBuffer;
1150 return ServerResponse;
1154 COServerResponse CardDAV2::GetContact(std::string Location, std::string *ContactData){
1156 // Check if authentication was successful, otherwise don't do anything.
1158 COServerResponse ServerResponse;
1160 if (AuthPassed == false){
1161 ServerResponse.RequestResult = COREQUEST_ERROR_NOTCONNECTED;
1162 ServerResponse.EntityTag = "";
1163 ServerResponse.SessionCode = 0;
1164 ServerResponse.ResultCode = 0;
1165 ServerResponse.ResultMessage = "";
1166 return ServerResponse;
1169 ServerSSL ? SetupDefaultParametersSSL(true) : SetupDefaultParametersNonSSL(true);
1172 string ServerAddressURL = BuildURL(ServerPrefix + Location);
1173 curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddressURL.c_str());
1174 curl_easy_setopt(ConnectionSession, CURLOPT_CUSTOMREQUEST, "GET");
1176 if (TestMode == true){
1177 SessionResult = curl_easy_perform(ConnectionSession);
1179 SessionResult = curl_easy_perform(ConnectionSession);
1182 switch(SessionResult){
1185 SSLVerified = COSSL_VERIFIED;
1187 case CURLE_SSL_CACERT:
1188 case CURLE_SSL_CONNECT_ERROR:
1190 SSLVerified = COSSL_UNABLETOVERIFY;
1196 long SessionResponseCode = 0;
1198 curl_easy_getinfo(ConnectionSession, CURLINFO_RESPONSE_CODE, &SessionResponseCode);
1200 if (SessionResponseCode == 200){
1202 ValidResponse = true;
1203 } else if (SessionResponseCode == 403){
1205 ValidResponse = true;
1206 } else if (SessionResponseCode >= 400){
1208 ValidResponse = true;
1211 ValidResponse = false;
1214 if (ValidResponse == false && AuthPassed == false){
1215 ServerResponse.RequestResult = COREQUEST_ERROR_SERVER;
1216 ServerResponse.EntityTag = "";
1217 ServerResponse.SessionCode = SessionResult;
1218 ServerResponse.ResultCode = SessionResponseCode;
1219 ServerResponse.ResultMessage = "";
1220 return ServerResponse;
1225 ServerResponse.RequestResult = COREQUEST_OK;
1226 ServerResponse.EntityTag = "";
1227 ServerResponse.SessionCode = SessionResult;
1228 ServerResponse.ResultCode = SessionResponseCode;
1229 ServerResponse.ResultMessage = SessionErrorBuffer;
1231 (*ContactData) = PageData;
1233 return ServerResponse;
1237 COContactList CardDAV2::GetContactList(std::string SyncToken){
1239 COContactList ServerContactList;
1241 // Check if authentication was successful, otherwise don't do anything.
1243 if (AuthPassed == false){
1244 ServerContactList.ServerResponse.RequestResult = COREQUEST_ERROR_NOTCONNECTED;
1245 ServerContactList.ServerResponse.EntityTag = "";
1246 ServerContactList.ServerResponse.SessionCode = 0;
1247 ServerContactList.ServerResponse.ResultCode = 0;
1248 ServerContactList.ServerResponse.ResultMessage = "";
1249 return ServerContactList;
1252 ServerSSL ? SetupDefaultParametersSSL(true) : SetupDefaultParametersNonSSL(true);
1255 std::string SyncData;
1257 // TODO: Copy old code from CardDAV class as needed.
1259 if (SyncToken.size() > 0){
1261 SyncData = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"
1262 "<D:sync-collection xmlns:D=\"DAV:\"\n"
1263 " xmlns:C=\"urn:ietf:params:xml:ns:carddav\">\n"
1265 SyncData.append(SyncToken);
1266 SyncData.append("</D:sync-token>\n"
1267 "<D:sync-level>1</D:sync-level>\n"
1271 "</D:sync-collection>");
1275 SyncData = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"
1276 "<D:sync-collection xmlns:D=\"DAV:\"\n"
1277 " xmlns:C=\"urn:ietf:params:xml:ns:carddav\">\n"
1278 "<D:sync-level>1</D:sync-level>\n"
1282 "</D:sync-collection>";
1286 string ServerAddressURL = BuildURL(ServerPrefix);
1288 std::cout << SyncData << std::endl;
1290 curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddressURL.c_str());
1291 curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDS, SyncData.c_str());
1292 curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDSIZE, strlen(SyncData.c_str()));
1293 curl_easy_setopt(ConnectionSession, CURLOPT_CUSTOMREQUEST, "REPORT");
1295 HeaderList = curl_slist_append(HeaderList, "Content-Type: application/xml; charset=utf-8");
1296 HeaderList = curl_slist_append(HeaderList, "Depth: 1");
1298 curl_easy_setopt(ConnectionSession, CURLOPT_HTTPHEADER, HeaderList);
1300 if (TestMode == true){
1301 SessionResult = curl_easy_perform(ConnectionSession);
1303 SessionResult = curl_easy_perform(ConnectionSession);
1306 switch(SessionResult){
1309 SSLVerified = COSSL_VERIFIED;
1311 case CURLE_SSL_CACERT:
1312 case CURLE_SSL_CONNECT_ERROR:
1314 SSLVerified = COSSL_UNABLETOVERIFY;
1320 long SessionResponseCode = 0;
1322 curl_easy_getinfo(ConnectionSession, CURLINFO_RESPONSE_CODE, &SessionResponseCode);
1324 if (SessionResponseCode == 207){
1326 ValidResponse = true;
1327 } else if (SessionResponseCode == 403){
1329 ValidResponse = true;
1330 } else if (SessionResponseCode >= 400){
1332 ValidResponse = true;
1335 ValidResponse = false;
1338 if (ValidResponse == false || AuthPassed == false){
1339 ServerContactList.ServerResponse.RequestResult = COREQUEST_ERROR_SERVER;
1340 ServerContactList.ServerResponse.EntityTag = "";
1341 ServerContactList.ServerResponse.SessionCode = SessionResult;
1342 ServerContactList.ServerResponse.ResultCode = SessionResponseCode;
1343 ServerContactList.ServerResponse.ResultMessage = "";
1344 return ServerContactList;
1349 ProcessContactData(&ServerContactList);
1351 ServerContactList.ServerResponse.RequestResult = COREQUEST_OK;
1352 ServerContactList.ServerResponse.EntityTag = "";
1353 ServerContactList.ServerResponse.SessionCode = SessionResult;
1354 ServerContactList.ServerResponse.ResultCode = SessionResponseCode;
1355 ServerContactList.ServerResponse.ResultMessage = SessionErrorBuffer;
1357 return ServerContactList;
1361 bool CardDAV2::CanDoProcessing(){
1365 bool CardDAV2::CanDoSSL(){
1369 COSSLVerified CardDAV2::SSLVerify(){
1373 bool CardDAV2::AbleToLogin(){
1377 bool CardDAV2::HasValidResponse(){
1378 return ValidResponse;
1381 bool CardDAV2::IsSelfSigned(){
1382 return SSLSelfSigned;
1385 void CardDAV2::SetupDefaultParametersNonSSL(bool DoAuthentication){
1387 std::string ServerAddress = "";
1389 string ServerAddressURL = "http://" + ServerAddress + ":" + to_string(ServerPort) + "/";
1390 string UsernamePassword = ServerUser + ":" + ServerPass;
1392 PageDataObject.CardDAV2Object = this;
1393 PageDataObject.ConnectionSessionObject = ConnectionSession;
1394 PageDataObject.DataSetting = &PageData;
1395 PageDataObject.ServerUsingSSL = false;
1397 PageHeaderObject.CardDAV2Object = this;
1398 PageHeaderObject.ConnectionSessionObject = ConnectionSession;
1399 PageHeaderObject.DataSetting = &PageHeader;
1400 PageHeaderObject.ServerUsingSSL = false;
1402 curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddress.c_str());
1403 curl_easy_setopt(ConnectionSession, CURLOPT_NOPROGRESS, 1L);
1404 curl_easy_setopt(ConnectionSession, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST|CURLAUTH_BASIC);
1405 curl_easy_setopt(ConnectionSession, CURLOPT_TIMEOUT, 60);
1406 curl_easy_setopt(ConnectionSession, CURLOPT_FAILONERROR, true);
1407 curl_easy_setopt(ConnectionSession, CURLOPT_USERAGENT, XSDAB_USERAGENT);
1408 curl_easy_setopt(ConnectionSession, CURLOPT_WRITEFUNCTION, CardDAV2::WritebackFunc);
1409 curl_easy_setopt(ConnectionSession, CURLOPT_WRITEDATA, &PageDataObject);
1410 curl_easy_setopt(ConnectionSession, CURLOPT_WRITEHEADER, &PageHeaderObject);
1411 curl_easy_setopt(ConnectionSession, CURLOPT_NOSIGNAL, 1);
1412 curl_easy_setopt(ConnectionSession, CURLOPT_CUSTOMREQUEST, "GET");
1413 curl_easy_setopt(ConnectionSession, CURLOPT_HTTPHEADER, nullptr);
1414 curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDS, nullptr);
1415 curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDSIZE, 0L);
1417 if (DoAuthentication == true){
1418 curl_easy_setopt(ConnectionSession, CURLOPT_USERPWD, UsernamePassword.c_str());
1420 curl_easy_setopt(ConnectionSession, CURLOPT_USERPWD, NULL);
1425 void CardDAV2::SetupDefaultParametersSSL(bool DoAuthentication){
1427 // Setup the default parameters.
1429 string ServerAddressURL = "https://" + ServerAddress + ":" + to_string(ServerPort) + "/";
1430 string UsernamePassword = ServerUser + ":" + ServerPass;
1432 PageDataObject.CardDAV2Object = this;
1433 PageDataObject.ConnectionSessionObject = ConnectionSession;
1434 PageDataObject.DataSetting = &PageData;
1435 PageDataObject.ServerUsingSSL = true;
1437 PageHeaderObject.CardDAV2Object = this;
1438 PageHeaderObject.ConnectionSessionObject = ConnectionSession;
1439 PageHeaderObject.DataSetting = &PageHeader;
1440 PageHeaderObject.ServerUsingSSL = true;
1442 curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddressURL.c_str());
1443 curl_easy_setopt(ConnectionSession, CURLOPT_NOPROGRESS, 1L);
1444 curl_easy_setopt(ConnectionSession, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST|CURLAUTH_BASIC);
1445 curl_easy_setopt(ConnectionSession, CURLOPT_TIMEOUT, 60);
1446 curl_easy_setopt(ConnectionSession, CURLOPT_FAILONERROR, true);
1447 curl_easy_setopt(ConnectionSession, CURLOPT_USERAGENT, XSDAB_USERAGENT);
1448 curl_easy_setopt(ConnectionSession, CURLOPT_WRITEFUNCTION, CardDAV2::WritebackFunc);
1449 curl_easy_setopt(ConnectionSession, CURLOPT_WRITEDATA, &PageDataObject);
1450 curl_easy_setopt(ConnectionSession, CURLOPT_WRITEHEADER, &PageHeaderObject);
1451 curl_easy_setopt(ConnectionSession, CURLOPT_ERRORBUFFER, SessionErrorBuffer);
1452 curl_easy_setopt(ConnectionSession, CURLOPT_NOSIGNAL, 1);
1453 curl_easy_setopt(ConnectionSession, CURLOPT_CERTINFO, 1);
1454 curl_easy_setopt(ConnectionSession, CURLOPT_VERBOSE, 1);
1455 curl_easy_setopt(ConnectionSession, CURLOPT_CUSTOMREQUEST, "GET");
1456 curl_easy_setopt(ConnectionSession, CURLOPT_HTTPHEADER, nullptr);
1457 curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDS, nullptr);
1458 curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDSIZE, 0L);
1460 if (DoAuthentication == true){
1461 curl_easy_setopt(ConnectionSession, CURLOPT_USERPWD, UsernamePassword.c_str());
1463 curl_easy_setopt(ConnectionSession, CURLOPT_USERPWD, NULL);
1466 #if !defined(__APPLE__)
1468 if (EnableSSLBypass == true){
1469 curl_easy_setopt(ConnectionSession, CURLOPT_SSL_VERIFYHOST, 0);
1470 curl_easy_setopt(ConnectionSession, CURLOPT_SSL_VERIFYPEER, 0);
1472 curl_easy_setopt(ConnectionSession, CURLOPT_SSL_VERIFYHOST, 2);
1473 curl_easy_setopt(ConnectionSession, CURLOPT_SSL_VERIFYPEER, 1);
1478 if (TestMode == false && ServerAccount.size() > 0){
1480 // Check if the server certificate file exists.
1482 string CertificateFilename = GetAccountDir(ServerAccount, true);
1484 if (wxFile::Exists(CertificateFilename)){
1486 curl_easy_setopt(ConnectionSession, CURLOPT_CAINFO, CertificateFilename.c_str());
1494 string CardDAV2::BuildURL(string URI){
1496 string ServerAddressURL;
1498 if (SSLStatus == true){
1499 ServerAddressURL = "https://" + ServerAddress + ":" + to_string(ServerPort) + URI;
1501 ServerAddressURL = "https://" + ServerAddress + ":" + to_string(ServerPort) + URI;
1504 return ServerAddressURL;
1508 string CardDAV2::GetErrorMessage(){
1510 ErrorMessage = SessionErrorBuffer;
1511 return ErrorMessage;
1515 void CardDAV2::ResetResults(){
1518 COSSLVerified SSLVerified = COSSL_NORESULT;
1519 ValidResponse = false;
1522 SSLSelfSigned = false;
1523 TaskCompleted = false;
1525 SessionErrorBuffer[0] = '\0';
1526 SessionResult = CURLE_OK;
1529 if (HeaderList != nullptr){
1530 curl_slist_free_all(HeaderList);
1531 HeaderList = nullptr;
1536 string CardDAV2::GetETagValue(){
1538 xmlDocPtr xmlCardDAVDoc;
1540 xmlCardDAVDoc = xmlReadMemory(PageData.c_str(), (int)PageData.size(), "noname.xml", NULL, 0);
1542 xmlNodePtr nodeLevel1;
1543 xmlNodePtr nodeLevel2;
1544 xmlNodePtr nodeLevel3;
1545 xmlNodePtr nodeLevel4;
1546 xmlNodePtr nodeLevel5;
1547 xmlNodePtr nodeLevel6;
1549 //std::map<wxString,wxString> xmlDataMap;
1551 std::string DataFilename;
1552 std::string ETagData;
1554 std::string xmlStringSafe;
1555 std::string ETagValue;
1557 // Tranverse through the catacombs of the response to get our ETag for the file.
1559 for (nodeLevel1 = xmlCardDAVDoc->children;
1561 nodeLevel1 = nodeLevel1->next)
1564 bool HREFFound = FALSE;
1565 bool ETagFound = FALSE;
1567 for (nodeLevel2 = nodeLevel1->children;
1569 nodeLevel2 = nodeLevel2->next)
1572 for (nodeLevel3 = nodeLevel2->children;
1574 nodeLevel3 = nodeLevel3->next)
1577 if (!xmlStrcmp(nodeLevel3->name, (const xmlChar *)"href") ||
1578 !xmlStrcmp(nodeLevel3->name, (const xmlChar *)"d:href") ||
1579 !xmlStrcmp(nodeLevel3->name, (const xmlChar *)"D:href")
1582 // Get the filename.
1584 for (nodeLevel4 = nodeLevel3->children;
1586 nodeLevel4 = nodeLevel4->next)
1589 if (!xmlStrcmp(nodeLevel4->name, (const xmlChar *)"text") ||
1590 !xmlStrcmp(nodeLevel4->name, (const xmlChar *)"d:text") ||
1591 !xmlStrcmp(nodeLevel4->name, (const xmlChar *)"D:text")
1594 DataFilename = wxString::FromUTF8((const char*)nodeLevel4->content);
1595 wxStringTokenizer wSTDFilename(DataFilename, wxT("/"));
1597 while (wSTDFilename.HasMoreTokens()){
1599 DataFilename = wSTDFilename.GetNextToken().ToStdString();
1613 for (nodeLevel4 = nodeLevel3->children;
1615 nodeLevel4 = nodeLevel4->next)
1618 for (nodeLevel5 = nodeLevel4->children;
1620 nodeLevel5 = nodeLevel5->next)
1623 if (!xmlStrcmp(nodeLevel5->name, (const xmlChar *)"getetag") ||
1624 !xmlStrcmp(nodeLevel5->name, (const xmlChar *)"d:getetag") ||
1625 !xmlStrcmp(nodeLevel5->name, (const xmlChar *)"D:getetag")
1628 for (nodeLevel6 = nodeLevel5->children;
1630 nodeLevel6 = nodeLevel6->next)
1633 // Strip the quotes from the ETag.
1635 ETagData = (const char*)nodeLevel6->content;
1636 if (ETagData[0] == '"' && ETagData[(ETagData.size() - 1)] == '"'){
1638 ETagData.erase(0, 1);
1639 ETagData.erase((ETagData.size() - 1));
1659 if (HREFFound == TRUE && ETagFound == TRUE){
1661 // Add to the map data.
1663 ETagValue = ETagData;
1674 xmlFreeDoc(xmlCardDAVDoc);
1680 string CardDAV2::GetETagHeader(){
1682 // Go through each of the lines looking for the
1687 bool FastForward = false;
1689 for (int HeaderSeek = 0; HeaderSeek < PageHeader.size(); HeaderSeek++){
1691 if (FastForward == true){
1693 if (PageHeader[HeaderSeek] == '\n'){
1694 FastForward = false;
1702 PageHeader.substr(HeaderSeek, 5) == "ETag:";
1705 catch (const out_of_range &oor){
1709 if (PageHeader.substr(HeaderSeek, 5) == "ETag:"){
1711 int CharacterSeek = 5;
1713 while ((HeaderSeek + CharacterSeek) < PageHeader.size()){
1715 if (PageHeader.substr((HeaderSeek + CharacterSeek), 2) == "\r\n"){
1719 HeaderValue += PageHeader.substr((HeaderSeek + CharacterSeek), 1);
1732 if (PageHeader[HeaderSeek] == '\n'){
1736 //HeaderName += PageHeader.substr(HeaderSeek, 1);
1740 // Check for quotation marks at the start and end and strip
1743 if (HeaderValue.size() >= 2){
1745 if (HeaderValue[0] == '"'){
1746 HeaderValue.erase((HeaderValue.size() - 1));
1747 HeaderValue.erase(0);
1756 vector<string> CardDAV2::GetDAVHeader(){
1758 // Go through each of the lines looking for the
1763 bool FastForward = false;
1764 vector<string> DAVHeaderList;
1766 for (int HeaderSeek = 0; HeaderSeek < PageHeader.size(); HeaderSeek++){
1768 if (FastForward == true){
1770 if (PageHeader[HeaderSeek] == '\n'){
1771 FastForward = false;
1779 PageHeader.substr(HeaderSeek, 4) == "DAV:";
1782 catch (const out_of_range &oor){
1786 if (PageHeader.substr(HeaderSeek, 4) == "DAV:"){
1788 int CharacterSeek = 5;
1790 while ((HeaderSeek + CharacterSeek) < PageHeader.size()){
1792 if (PageHeader.substr((HeaderSeek + CharacterSeek), 2) == "\r\n"){
1796 HeaderValue += PageHeader.substr((HeaderSeek + CharacterSeek), 1);
1809 if (PageHeader[HeaderSeek] == '\n'){
1813 //HeaderName += PageHeader.substr(HeaderSeek, 1);
1817 // Split the header data.
1819 std::string DAVHeaderValue;
1821 for (int HeaderSeek = 0; HeaderSeek < HeaderValue.size(); HeaderSeek++){
1823 if (HeaderValue.substr(HeaderSeek, 1) == ","){
1824 DAVHeaderList.push_back(DAVHeaderValue);
1825 DAVHeaderValue = "";
1830 DAVHeaderValue += HeaderValue[HeaderSeek];
1834 if (DAVHeaderValue.size() > 0){
1836 DAVHeaderList.push_back(DAVHeaderValue);
1840 return DAVHeaderList;
1844 void CardDAV2::ProcessContactData(COContactList *ContactList){
1846 xmlDocPtr xmlCardDAVDoc;
1847 xmlCardDAVDoc = xmlReadMemory(PageData.c_str(), (int)PageData.size(), "noname.xml", NULL, 0);
1849 xmlNodePtr MultiStatusNode;
1850 xmlNodePtr ResponseNode;
1851 xmlNodePtr ResponseDataNode;
1852 xmlNodePtr PropStatNode;
1853 xmlNodePtr ValueNode;
1854 xmlNodePtr ETagNode;
1855 xmlNodePtr StatusNode;
1857 std::string HREFValue;
1858 std::string ETagValue;
1859 std::string StatusValue;
1860 std::string SyncValue;
1862 // Go through the document!
1864 MultiStatusNode = xmlCardDAVDoc->children;
1866 if (MultiStatusNode == nullptr){
1870 bool SyncTokenFound = false;
1872 // Tranverse through the catacombs of the response to get our ETag for the file and
1873 // the server syncronisation token.
1875 for (ResponseNode = MultiStatusNode->children;
1876 ResponseNode != nullptr;
1877 ResponseNode = ResponseNode->next){
1879 // Check if tag is response or sync-token.
1881 if (!xmlStrcmp(ResponseNode->name, (const xmlChar *)"response") ||
1882 !xmlStrcmp(ResponseNode->name, (const xmlChar *)"d:response") ||
1883 !xmlStrcmp(ResponseNode->name, (const xmlChar *)"D:response")){
1885 COContactStatus ContactStatus = COCS_UNKNOWN;
1887 for (ResponseDataNode = ResponseNode->children;
1888 ResponseDataNode != nullptr;
1889 ResponseDataNode = ResponseDataNode->next){
1891 if (!xmlStrcmp(ResponseDataNode->name, (const xmlChar *)"href") ||
1892 !xmlStrcmp(ResponseDataNode->name, (const xmlChar *)"d:href") ||
1893 !xmlStrcmp(ResponseDataNode->name, (const xmlChar *)"D:href")){
1895 HREFValue = (const char*)ResponseDataNode->children->content;
1897 // Get the filename after the last forward slash.
1901 for (int HREFValueSeek = 0; HREFValueSeek < HREFValue.size(); HREFValueSeek++){
1903 if (HREFValue[HREFValueSeek] == '/'){
1905 LastSlash = HREFValueSeek;
1911 HREFValue = HREFValue.substr((LastSlash + 1));
1913 } else if (!xmlStrcmp(ResponseDataNode->name, (const xmlChar *)"propstat") ||
1914 !xmlStrcmp(ResponseDataNode->name, (const xmlChar *)"d:propstat") ||
1915 !xmlStrcmp(ResponseDataNode->name, (const xmlChar *)"D:propstat")){
1917 for (PropStatNode = ResponseDataNode->children;
1918 PropStatNode != nullptr;
1919 PropStatNode = PropStatNode->next){
1921 if (!xmlStrcmp(PropStatNode->name, (const xmlChar *)"prop") ||
1922 !xmlStrcmp(PropStatNode->name, (const xmlChar *)"d:prop") ||
1923 !xmlStrcmp(PropStatNode->name, (const xmlChar *)"D:prop")){
1925 for (ETagNode = PropStatNode->children;
1926 ETagNode != nullptr;
1927 ETagNode = ETagNode->next){
1929 if (!xmlStrcmp(ETagNode->name, (const xmlChar *)"getetag") ||
1930 !xmlStrcmp(ETagNode->name, (const xmlChar *)"getetag") ||
1931 !xmlStrcmp(ETagNode->name, (const xmlChar *)"getetag")){
1933 ETagValue = (const char*)ETagNode->children->content;
1935 if (ETagValue.size() > 2 && ETagValue.substr(0,1) == "\""){
1936 ETagValue.erase((ETagValue.size() - 1),1);
1937 ETagValue.erase(0,1);
1945 } else if (!xmlStrcmp(PropStatNode->name, (const xmlChar *)"status") ||
1946 !xmlStrcmp(PropStatNode->name, (const xmlChar *)"d:status") ||
1947 !xmlStrcmp(PropStatNode->name, (const xmlChar *)"D:status")){
1949 StatusValue = (const char*)PropStatNode->children->content;
1951 if (StatusValue == "HTTP/1.1 200 OK"){
1953 ContactStatus = COCS_UPDATED;
1955 } else if (StatusValue == "HTTP/1.1 404 Not Found"){
1957 ContactStatus = COCS_DELETED;
1961 ContactStatus = COCS_UNKNOWN;
1973 COContactData ContactInformation;
1975 ContactInformation.Location = HREFValue;
1976 ContactInformation.Data = ETagValue;
1977 ContactInformation.Status = ContactStatus;
1981 StatusValue.clear();
1983 ContactList->ListData.push_back(ContactInformation);
1985 } else if (!xmlStrcmp(ResponseNode->name, (const xmlChar *)"sync-token") ||
1986 !xmlStrcmp(ResponseNode->name, (const xmlChar *)"d:sync-token") ||
1987 !xmlStrcmp(ResponseNode->name, (const xmlChar *)"D:sync-token")){
1989 SyncValue = (const char*)ResponseNode->children->content;
1995 ContactList->SyncToken = SyncValue;
1997 xmlFreeDoc(xmlCardDAVDoc);