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 size_t CardDAV2::WritebackFunc(char *ptr, size_t size, size_t nmemb, void *stream){
27 return static_cast<CardDAV2*>(stream)->WritebackFuncImplementation(ptr, size, nmemb, stream);
31 size_t CardDAV2::WritebackFuncImplementation(char *ptr, size_t size, size_t nmemb, void *stream){
33 // Writeback function for the CardDAV object.
35 string *data = static_cast<string*>(stream);
38 // Get the SSL engine pointer and trust if required on certain operating systems.
42 #if defined(__APPLE__)
44 const struct curl_tlssessioninfo *TLSInfo;
46 CURL *Connection = GetConnectionObject();
47 TLSCode = curl_easy_getinfo(Connection, CURLINFO_TLS_SSL_PTR, &TLSInfo);
49 if (TLSInfo->internals != nullptr && TLSCode == CURLE_OK){
50 SSLCopyPeerTrust((SSLContext*)TLSInfo->internals, &SecTrustObject);
53 #elif defined(__WIN32__)
55 const struct curl_tlssessioninfo *TLSInfo;
57 TLSCode = curl_easy_getinfo(ConnectionSession, CURLINFO_TLS_SSL_PTR, &TLSInfo);
59 if (TLSInfo->internals != nullptr && TLSCode == CURLE_OK){
61 // Free the previous certificate data.
63 CertFreeCertificateContext(CertificateData);
65 PCtxtHandle SSLHandle = (PCtxtHandle)TLSInfo->internals;
66 SECURITY_STATUS GetData = QueryContextAttributes(SSLHandle, SECPKG_ATTR_REMOTE_CERT_CONTEXT, &CertificateData);
78 CardDAV2::~CardDAV2(){
80 curl_easy_cleanup(ConnectionSession);
81 ConnectionSession = nullptr;
83 if (HeaderList != nullptr){
84 curl_slist_free_all(HeaderList);
88 #if defined(__WIN32__)
90 CertFreeCertificateContext(CertificateData);
96 #if defined(__APPLE__)
98 #elif defined(__WIN32__)
100 PCCERT_CONTEXT CardDAV2::BuildSSLCollection(){
102 return CertificateData;
108 SSLCertCollectionString CardDAV2::BuildSSLCollection(){
110 // Build and return the SSL collection.
112 SSLCertCollectionString SSLCertInfo;
114 // Grab the certificate data.
117 struct curl_slist *certdata;
118 struct curl_certinfo *certinfo;
121 certptr.certdata = NULL;
123 curl_easy_getinfo(ConnectionSession, CURLINFO_CERTINFO, &certptr.certinfo);
125 std::string CertPropName;
126 std::string CertPropValue;
128 for (int i = 0; i < certptr.certinfo->num_of_certs; i++){
130 struct curl_slist *slist;
131 SSLCertDataString SSLCertDataInc;
133 for (slist = certptr.certinfo->certinfo[i]; slist; slist = slist->next){
135 // Using wxStringTokenizer from wxWidgets.
137 wxStringTokenizer CertDataInc(wxString::FromUTF8(slist->data), ":");
139 // Get first token as the property name.
141 CertPropName = CertDataInc.GetNextToken().ToStdString();
143 // Get remaining tokens as the property value.
145 while(CertDataInc.HasMoreTokens()){
147 CertPropValue.append(CertDataInc.GetNextToken());
151 SSLCertDataInc.CertData.insert(std::make_pair(CertPropName, CertPropValue));
152 CertPropName.clear();
153 CertPropValue.clear();
157 SSLCertInfo.SSLCollection.insert(std::make_pair(i, SSLCertDataInc));
165 void CardDAV2::BypassSSLVerification(bool EnableBypass){
166 EnableSSLBypass = EnableBypass;
167 SSLSelfSigned = EnableBypass;
172 void CardDAV2::SetupConnectionObject(){
173 ConnectionSession = curl_easy_init();
176 bool CardDAV2::IsTaskCompleted(){
180 COConnectResult CardDAV2::Connect(bool DoAuthentication){
182 ServerSSL ? SetupDefaultParametersSSL(DoAuthentication) : SetupDefaultParametersNonSSL(DoAuthentication);
185 COConnectResult ConnectResult = COCONNECT_UNITTESTFAIL;
186 string ServerAddressURL = BuildURL("/principals/");
188 curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddressURL.c_str());
190 if (TestMode == true){
191 SessionResult = curl_easy_perform(ConnectionSession);
193 SessionResult = curl_easy_perform(ConnectionSession);
196 switch(SessionResult){
198 case CURLE_HTTP_RETURNED_ERROR:
200 SSLVerified = COSSL_VERIFIED;
201 ConnectResult = COCONNECT_OK;
203 case CURLE_SSL_CACERT:
204 case CURLE_SSL_CONNECT_ERROR:
206 ConnectResult = COCONNECT_OK;
207 SSLVerified = COSSL_UNABLETOVERIFY;
210 ConnectResult = COCONNECT_INVALID;
214 // Check if an error occured before continuing.
216 // Check if authentication was successful.
218 long SessionResponseCode = 0;
220 curl_easy_getinfo(ConnectionSession, CURLINFO_RESPONSE_CODE, &SessionResponseCode);
222 if (DoAuthentication == true){
224 // Get the HTTP status code (Should be 200 and not 403).
225 // Return error otherwise.
227 if (SessionResponseCode == 200){
228 ConnectResult = COCONNECT_OK;
230 ValidResponse = true;
231 } else if (SessionResponseCode == 401){
232 ConnectResult = COCONNECT_AUTHFAIL;
234 ValidResponse = true;
235 } else if (SessionResponseCode >= 200) {
236 ConnectResult = COCONNECT_INVALID;
238 ValidResponse = true;
240 ConnectResult = COCONNECT_INVALID;
242 ValidResponse = false;
247 ValidResponse = true;
251 // Check the header to see if CardDAV is supported.
253 vector<string> DAVHeaderValues = GetDAVHeader();
255 for (vector<string>::iterator DAVHeaderValuesIter = DAVHeaderValues.begin();
256 DAVHeaderValuesIter != DAVHeaderValues.end(); DAVHeaderValuesIter++){
258 if ((*DAVHeaderValuesIter) == "addressbook"){
265 return ConnectResult;
269 COServerResponse CardDAV2::GetDefaultPrefix(string *ServerPrefix){
271 // Check if authentication was successful, otherwise don't do anything.
273 COServerResponse ServerResponse;
275 if (AuthPassed == false){
276 ServerResponse.RequestResult = COREQUEST_ERROR_NOTCONNECTED;
277 ServerResponse.EntityTag = "";
278 ServerResponse.SessionCode = 0;
279 ServerResponse.ResultCode = 0;
280 ServerResponse.ResultMessage = "";
281 return ServerResponse;
284 ServerSSL ? SetupDefaultParametersSSL(true) : SetupDefaultParametersNonSSL(true);
287 // Need to do three requests:
289 // 1. Get the current user principal URI.
290 // 2. Get the address book home URI.
291 // 3. Get the default address book URI.
293 // Setup the first query finding out where the principal URL is.
295 const char* CurrentUserPrincipalXMLQuery = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"
296 "<D:propfind xmlns:D=\"DAV:\">\n"
298 " <D:current-user-principal/>\n"
302 // Setup the second query finding out where the address book home URL is.
304 const char* AddressBookHomeXMLQuery = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"
305 "<D:propfind xmlns:D=\"DAV:\""
306 " xmlns:C=\"urn:ietf:params:xml:ns:carddav\">\n"
308 " <C:addressbook-home-set/>\n"
312 // Setup the third query finding out where the default address book URL is.
314 const char* DefaultAddressBookXMLQuery = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"
315 "<D:propfind xmlns:D=\"DAV:\""
316 " xmlns:C=\"urn:ietf:params:xml:ns:carddav\">\n"
318 " <C:default-addressbook-URL/>\n"
322 string ServerAddressURL = BuildURL("/principals/");
323 curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddressURL.c_str());
324 curl_easy_setopt(ConnectionSession, CURLOPT_CUSTOMREQUEST, "PROPFIND");
325 curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDS, CurrentUserPrincipalXMLQuery);
326 curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDSIZE, strlen(CurrentUserPrincipalXMLQuery));
328 if (TestMode == true){
329 SessionResult = curl_easy_perform(ConnectionSession);
334 switch(SessionResult){
337 SSLVerified = COSSL_VERIFIED;
339 case CURLE_SSL_CACERT:
340 case CURLE_SSL_CONNECT_ERROR:
342 SSLVerified = COSSL_UNABLETOVERIFY;
348 long SessionResponseCode = 0;
350 curl_easy_getinfo(ConnectionSession, CURLINFO_RESPONSE_CODE, &SessionResponseCode);
352 if (SessionResponseCode == 200 || SessionResponseCode == 207){
354 ValidResponse = true;
355 } else if (SessionResponseCode == 403){
357 ValidResponse = true;
358 } else if (SessionResponseCode >= 400) {
360 ValidResponse = true;
363 ValidResponse = false;
366 if (ValidResponse == false && AuthPassed == false){
367 ServerResponse.RequestResult = COREQUEST_ERROR_SERVER;
368 ServerResponse.EntityTag = "";
369 ServerResponse.SessionCode = SessionResult;
370 ServerResponse.ResultCode = SessionResponseCode;
371 ServerResponse.ResultMessage = "";
372 return ServerResponse;
375 // Process the first response.
377 string UserPrincipalURI = GetUserPrincipalURI();
379 // Cleanup and reset for the second connection.
381 ServerSSL ? SetupDefaultParametersSSL(true) : SetupDefaultParametersNonSSL(true);
384 ServerAddressURL = BuildURL(UserPrincipalURI);
385 curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddressURL.c_str());
386 curl_easy_setopt(ConnectionSession, CURLOPT_CUSTOMREQUEST, "PROPFIND");
387 curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDS, AddressBookHomeXMLQuery);
388 curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDSIZE, strlen(AddressBookHomeXMLQuery));
390 if (TestMode == true){
391 SessionResult = curl_easy_perform(ConnectionSession);
396 switch(SessionResult){
399 SSLVerified = COSSL_VERIFIED;
401 case CURLE_SSL_CACERT:
402 case CURLE_SSL_CONNECT_ERROR:
404 SSLVerified = COSSL_UNABLETOVERIFY;
410 SessionResponseCode = 0;
412 curl_easy_getinfo(ConnectionSession, CURLINFO_RESPONSE_CODE, &SessionResponseCode);
414 if (SessionResponseCode == 200 || SessionResponseCode == 207){
416 ValidResponse = true;
417 } else if (SessionResponseCode == 403){
419 ValidResponse = true;
420 } else if (SessionResponseCode >= 400) {
422 ValidResponse = true;
425 ValidResponse = false;
428 if (ValidResponse == false && AuthPassed == false){
429 ServerResponse.RequestResult = COREQUEST_ERROR_SERVER;
430 ServerResponse.EntityTag = "";
431 ServerResponse.SessionCode = SessionResult;
432 ServerResponse.ResultCode = SessionResponseCode;
433 ServerResponse.ResultMessage = "";
434 return ServerResponse;
437 // Process the second response.
439 string AddressBookHomeURI = GetAddressBookHomeURI();
441 // Cleanup and reset for the second connection.
443 ServerSSL ? SetupDefaultParametersSSL(true) : SetupDefaultParametersNonSSL(true);
446 ServerAddressURL = BuildURL(AddressBookHomeURI);
447 curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddressURL.c_str());
448 curl_easy_setopt(ConnectionSession, CURLOPT_CUSTOMREQUEST, "PROPFIND");
449 curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDS, DefaultAddressBookXMLQuery);
450 curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDSIZE, strlen(DefaultAddressBookXMLQuery));
452 if (TestMode == true){
453 SessionResult = curl_easy_perform(ConnectionSession);
458 switch(SessionResult){
461 SSLVerified = COSSL_VERIFIED;
463 case CURLE_SSL_CACERT:
464 case CURLE_SSL_CONNECT_ERROR:
466 SSLVerified = COSSL_UNABLETOVERIFY;
472 SessionResponseCode = 0;
474 curl_easy_getinfo(ConnectionSession, CURLINFO_RESPONSE_CODE, &SessionResponseCode);
476 if (SessionResponseCode == 200 || SessionResponseCode == 207){
478 ValidResponse = true;
479 } else if (SessionResponseCode == 403){
481 ValidResponse = true;
482 } else if (SessionResponseCode >= 200) {
484 ValidResponse = true;
487 ValidResponse = false;
490 if (ValidResponse == false || AuthPassed == false){
491 ServerResponse.RequestResult = COREQUEST_ERROR_SERVER;
492 ServerResponse.EntityTag = "";
493 ServerResponse.SessionCode = SessionResult;
494 ServerResponse.ResultCode = SessionResponseCode;
495 ServerResponse.ResultMessage = "";
496 return ServerResponse;
499 // Process the second response.
501 (*ServerPrefix) = GetDefaultAddressBookURI();
505 ServerResponse.RequestResult = COREQUEST_OK;
506 ServerResponse.EntityTag = "";
507 ServerResponse.SessionCode = SessionResult;
508 ServerResponse.ResultCode = SessionResponseCode;
509 ServerResponse.ResultMessage = SessionErrorBuffer;
510 return ServerResponse;
514 std::string CardDAV2::GetUserPrincipalURI(){
516 xmlDocPtr xmlCardDAVDoc;
517 xmlCardDAVDoc = xmlReadMemory(PageData.c_str(), (int)PageData.size(), "noname.xml", NULL, 0);
518 string UserPrincipalURI = "";
520 xmlNodePtr nodeLevel1;
521 xmlNodePtr nodeLevel2;
522 xmlNodePtr nodeLevel3;
523 xmlNodePtr nodeLevel4;
524 xmlNodePtr nodeLevel5;
525 xmlNodePtr nodeLevel6;
526 xmlNodePtr nodeLevel7;
528 for (nodeLevel1 = xmlCardDAVDoc->children;
530 nodeLevel1 = nodeLevel1->next)
533 for (nodeLevel2 = nodeLevel1->children;
535 nodeLevel2 = nodeLevel2->next)
539 for (nodeLevel3 = nodeLevel2->children;
541 nodeLevel3 = nodeLevel3->next)
544 for (nodeLevel4 = nodeLevel3->children;
546 nodeLevel4 = nodeLevel4->next)
549 for (nodeLevel5 = nodeLevel4->children;
551 nodeLevel5 = nodeLevel5->next)
554 for (nodeLevel6 = nodeLevel5->children;
556 nodeLevel6 = nodeLevel6->next)
559 if (!xmlStrcmp(nodeLevel6->name, (const xmlChar *)"href") ||
560 !xmlStrcmp(nodeLevel6->name, (const xmlChar *)"d:href") ||
561 !xmlStrcmp(nodeLevel6->name, (const xmlChar *)"D:href")
564 // Found the <href> part so extract the principal URL address.
566 for (nodeLevel7 = nodeLevel6->children;
568 nodeLevel7 = nodeLevel7->next)
571 UserPrincipalURI = ((const char*)nodeLevel7->content);
589 xmlFreeDoc(xmlCardDAVDoc);
591 return UserPrincipalURI;
595 std::string CardDAV2::GetAddressBookHomeURI(){
597 xmlDocPtr xmlCardDAVDoc;
598 xmlCardDAVDoc = xmlReadMemory(PageData.c_str(), (int)PageData.size(), "noname.xml", NULL, 0);
599 string AddressBookHomeURI = "";
601 xmlNodePtr nodeLevel1;
602 xmlNodePtr nodeLevel2;
603 xmlNodePtr nodeLevel3;
604 xmlNodePtr nodeLevel4;
605 xmlNodePtr nodeLevel5;
606 xmlNodePtr nodeLevel6;
607 xmlNodePtr nodeLevel7;
609 for (nodeLevel1 = xmlCardDAVDoc->children;
611 nodeLevel1 = nodeLevel1->next)
614 for (nodeLevel2 = nodeLevel1->children;
616 nodeLevel2 = nodeLevel2->next)
620 for (nodeLevel3 = nodeLevel2->children;
622 nodeLevel3 = nodeLevel3->next)
625 for (nodeLevel4 = nodeLevel3->children;
627 nodeLevel4 = nodeLevel4->next)
630 for (nodeLevel5 = nodeLevel4->children;
632 nodeLevel5 = nodeLevel5->next)
635 for (nodeLevel6 = nodeLevel5->children;
637 nodeLevel6 = nodeLevel6->next)
640 if (!xmlStrcmp(nodeLevel6->name, (const xmlChar *)"href") ||
641 !xmlStrcmp(nodeLevel6->name, (const xmlChar *)"d:href") ||
642 !xmlStrcmp(nodeLevel6->name, (const xmlChar *)"D:href")
645 // Found the <href> part so extract the principal URL address.
647 for (nodeLevel7 = nodeLevel6->children;
649 nodeLevel7 = nodeLevel7->next)
652 AddressBookHomeURI = ((const char*)nodeLevel7->content);
670 xmlFreeDoc(xmlCardDAVDoc);
672 return AddressBookHomeURI;
676 std::string CardDAV2::GetDefaultAddressBookURI(){
678 xmlDocPtr xmlCardDAVDoc;
679 xmlCardDAVDoc = xmlReadMemory(PageData.c_str(), (int)PageData.size(), "noname.xml", NULL, 0);
680 string DefaultAddressBookURI = "";
682 xmlNodePtr nodeLevel1;
683 xmlNodePtr nodeLevel2;
684 xmlNodePtr nodeLevel3;
685 xmlNodePtr nodeLevel4;
686 xmlNodePtr nodeLevel5;
687 xmlNodePtr nodeLevel6;
688 xmlNodePtr nodeLevel7;
690 for (nodeLevel1 = xmlCardDAVDoc->children;
692 nodeLevel1 = nodeLevel1->next)
695 for (nodeLevel2 = nodeLevel1->children;
697 nodeLevel2 = nodeLevel2->next)
701 for (nodeLevel3 = nodeLevel2->children;
703 nodeLevel3 = nodeLevel3->next)
706 for (nodeLevel4 = nodeLevel3->children;
708 nodeLevel4 = nodeLevel4->next)
711 for (nodeLevel5 = nodeLevel4->children;
713 nodeLevel5 = nodeLevel5->next)
716 for (nodeLevel6 = nodeLevel5->children;
718 nodeLevel6 = nodeLevel6->next)
721 if (!xmlStrcmp(nodeLevel6->name, (const xmlChar *)"href") ||
722 !xmlStrcmp(nodeLevel6->name, (const xmlChar *)"d:href") ||
723 !xmlStrcmp(nodeLevel6->name, (const xmlChar *)"D:href")
726 // Found the <href> part so extract the principal URL address.
728 for (nodeLevel7 = nodeLevel6->children;
730 nodeLevel7 = nodeLevel7->next)
733 DefaultAddressBookURI = ((const char*)nodeLevel7->content);
751 xmlFreeDoc(xmlCardDAVDoc);
753 return DefaultAddressBookURI;
757 COServerResponse CardDAV2::AddContact(std::string Location, std::string Data){
759 // Check if authentication was successful, otherwise don't do anything.
761 COServerResponse ServerResponse;
763 if (AuthPassed == false){
764 ServerResponse.RequestResult = COREQUEST_ERROR_NOTCONNECTED;
765 ServerResponse.EntityTag = "";
766 ServerResponse.SessionCode = 0;
767 ServerResponse.ResultCode = 0;
768 ServerResponse.ResultMessage = "";
769 return ServerResponse;
772 ServerSSL ? SetupDefaultParametersSSL(true) : SetupDefaultParametersNonSSL(true);
775 string ServerAddressURL = BuildURL(ServerPrefix + Location);
776 curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddressURL.c_str());
777 curl_easy_setopt(ConnectionSession, CURLOPT_CUSTOMREQUEST, "PUT");
778 curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDS, Data.c_str());
779 curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDSIZE, strlen(Data.c_str()));
781 HeaderList = curl_slist_append(HeaderList, "Content-Type: text/vcard; charset=utf-8");
783 curl_easy_setopt(ConnectionSession, CURLOPT_HTTPHEADER, HeaderList);
785 if (TestMode == true){
786 SessionResult = curl_easy_perform(ConnectionSession);
788 SessionResult = curl_easy_perform(ConnectionSession);
791 switch(SessionResult){
794 SSLVerified = COSSL_VERIFIED;
796 case CURLE_SSL_CACERT:
797 case CURLE_SSL_CONNECT_ERROR:
799 SSLVerified = COSSL_UNABLETOVERIFY;
805 long SessionResponseCode = 0;
807 curl_easy_getinfo(ConnectionSession, CURLINFO_RESPONSE_CODE, &SessionResponseCode);
809 if (SessionResponseCode == 200 || SessionResponseCode == 201 || SessionResponseCode == 204){
811 ValidResponse = true;
812 } else if (SessionResponseCode == 403){
814 ValidResponse = true;
815 } else if (SessionResponseCode >= 400){
817 ValidResponse = true;
820 ValidResponse = false;
823 if (ValidResponse == false || AuthPassed == false){
824 ServerResponse.RequestResult = COREQUEST_ERROR_SERVER;
825 ServerResponse.EntityTag = "";
826 ServerResponse.SessionCode = SessionResult;
827 ServerResponse.ResultCode = SessionResponseCode;
828 ServerResponse.ResultMessage = "";
829 return ServerResponse;
834 ServerResponse.RequestResult = COREQUEST_OK;
835 ServerResponse.EntityTag = "";
836 ServerResponse.SessionCode = SessionResult;
837 ServerResponse.ResultCode = SessionResponseCode;
838 ServerResponse.ResultMessage = SessionErrorBuffer;
839 return ServerResponse;
843 COServerResponse CardDAV2::EditContact(std::string Location, std::string Data){
845 // Check if authentication was successful, otherwise don't do anything.
847 COServerResponse ServerResponse;
849 if (AuthPassed == false){
850 ServerResponse.RequestResult = COREQUEST_ERROR_NOTCONNECTED;
851 ServerResponse.EntityTag = "";
852 ServerResponse.SessionCode = 0;
853 ServerResponse.ResultCode = 0;
854 ServerResponse.ResultMessage = "";
855 return ServerResponse;
858 ServerSSL ? SetupDefaultParametersSSL(true) : SetupDefaultParametersNonSSL(true);
861 string ServerAddressURL = BuildURL(ServerPrefix + Location);
862 curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddressURL.c_str());
863 curl_easy_setopt(ConnectionSession, CURLOPT_CUSTOMREQUEST, "PUT");
864 curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDS, Data.c_str());
865 curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDSIZE, strlen(Data.c_str()));
867 HeaderList = curl_slist_append(HeaderList, "Content-Type: text/vcard; charset=utf-8");
869 curl_easy_setopt(ConnectionSession, CURLOPT_HTTPHEADER, HeaderList);
871 if (TestMode == true){
872 SessionResult = curl_easy_perform(ConnectionSession);
874 SessionResult = curl_easy_perform(ConnectionSession);
877 switch(SessionResult){
880 SSLVerified = COSSL_VERIFIED;
882 case CURLE_SSL_CACERT:
883 case CURLE_SSL_CONNECT_ERROR:
885 SSLVerified = COSSL_UNABLETOVERIFY;
891 long SessionResponseCode = 0;
893 curl_easy_getinfo(ConnectionSession, CURLINFO_RESPONSE_CODE, &SessionResponseCode);
895 if (SessionResponseCode == 200 || SessionResponseCode == 201 || SessionResponseCode == 204){
897 ValidResponse = true;
898 } else if (SessionResponseCode == 403){
900 ValidResponse = true;
901 } else if (SessionResponseCode >= 400){
903 ValidResponse = true;
906 ValidResponse = false;
909 if (ValidResponse == false || AuthPassed == false){
910 ServerResponse.RequestResult = COREQUEST_ERROR_SERVER;
911 ServerResponse.EntityTag = "";
912 ServerResponse.SessionCode = SessionResult;
913 ServerResponse.ResultCode = SessionResponseCode;
914 ServerResponse.ResultMessage = "";
915 return ServerResponse;
920 ServerResponse.RequestResult = COREQUEST_OK;
921 ServerResponse.EntityTag = "";
922 ServerResponse.SessionCode = SessionResult;
923 ServerResponse.ResultCode = SessionResponseCode;
924 ServerResponse.ResultMessage = SessionErrorBuffer;
925 return ServerResponse;
929 COServerResponse CardDAV2::DeleteContact(std::string Location){
931 // Check if authentication was successful, otherwise don't do anything.
933 COServerResponse ServerResponse;
935 if (AuthPassed == false){
936 ServerResponse.RequestResult = COREQUEST_ERROR_NOTCONNECTED;
937 ServerResponse.EntityTag = "";
938 ServerResponse.SessionCode = 0;
939 ServerResponse.ResultCode = 0;
940 ServerResponse.ResultMessage = "";
941 return ServerResponse;
944 ServerSSL ? SetupDefaultParametersSSL(true) : SetupDefaultParametersNonSSL(true);
947 string ServerAddressURL = BuildURL(ServerPrefix + Location);
948 curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddressURL.c_str());
949 curl_easy_setopt(ConnectionSession, CURLOPT_CUSTOMREQUEST, "DELETE");
951 if (TestMode == true){
952 SessionResult = curl_easy_perform(ConnectionSession);
954 SessionResult = curl_easy_perform(ConnectionSession);
957 switch(SessionResult){
960 SSLVerified = COSSL_VERIFIED;
962 case CURLE_SSL_CACERT:
963 case CURLE_SSL_CONNECT_ERROR:
965 SSLVerified = COSSL_UNABLETOVERIFY;
971 long SessionResponseCode = 0;
973 curl_easy_getinfo(ConnectionSession, CURLINFO_RESPONSE_CODE, &SessionResponseCode);
975 if (SessionResponseCode == 200 || SessionResponseCode == 202 || SessionResponseCode == 204){
977 ValidResponse = true;
978 } else if (SessionResponseCode == 403){
980 ValidResponse = true;
981 } else if (SessionResponseCode >= 400){
983 ValidResponse = true;
986 ValidResponse = false;
989 if (ValidResponse == false || AuthPassed == false){
990 ServerResponse.RequestResult = COREQUEST_ERROR_SERVER;
991 ServerResponse.EntityTag = "";
992 ServerResponse.SessionCode = SessionResult;
993 ServerResponse.ResultCode = SessionResponseCode;
994 ServerResponse.ResultMessage = "";
995 return ServerResponse;
1000 ServerResponse.RequestResult = COREQUEST_OK;
1001 ServerResponse.EntityTag = "";
1002 ServerResponse.SessionCode = SessionResult;
1003 ServerResponse.ResultCode = SessionResponseCode;
1004 ServerResponse.ResultMessage = SessionErrorBuffer;
1005 return ServerResponse;
1009 COServerResponse CardDAV2::GetServerEntityTagValue(std::string Location){
1011 // Check if authentication was successful, otherwise don't do anything.
1013 COServerResponse ServerResponse;
1015 if (AuthPassed == false){
1016 ServerResponse.RequestResult = COREQUEST_ERROR_NOTCONNECTED;
1017 ServerResponse.EntityTag = "";
1018 ServerResponse.SessionCode = 0;
1019 ServerResponse.ResultCode = 0;
1020 ServerResponse.ResultMessage = "";
1021 return ServerResponse;
1024 ServerSSL ? SetupDefaultParametersSSL(true) : SetupDefaultParametersNonSSL(true);
1027 static const char* GetETagQuery =
1028 "<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
1029 "<C:addressbook-query xmlns:D=\"DAV:\""
1030 " xmlns:C=\"urn:ietf:params:xml:ns:carddav\">"
1031 "<D:prop><D:getetag/>"
1034 "</C:addressbook-query>";
1036 string ServerAddressURL = BuildURL(ServerPrefix + Location);
1037 curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddressURL.c_str());
1038 curl_easy_setopt(ConnectionSession, CURLOPT_CUSTOMREQUEST, "REPORT");
1039 curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDS, GetETagQuery);
1040 curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDSIZE, strlen(GetETagQuery));
1042 if (TestMode == true){
1043 SessionResult = curl_easy_perform(ConnectionSession);
1045 SessionResult = curl_easy_perform(ConnectionSession);
1048 switch(SessionResult){
1051 SSLVerified = COSSL_VERIFIED;
1053 case CURLE_SSL_CACERT:
1054 case CURLE_SSL_CONNECT_ERROR:
1056 SSLVerified = COSSL_UNABLETOVERIFY;
1062 long SessionResponseCode = 0;
1064 curl_easy_getinfo(ConnectionSession, CURLINFO_RESPONSE_CODE, &SessionResponseCode);
1066 if (SessionResponseCode == 207){
1068 ValidResponse = true;
1069 } else if (SessionResponseCode == 403){
1071 ValidResponse = true;
1072 } else if (SessionResponseCode >= 400){
1074 ValidResponse = true;
1077 ValidResponse = false;
1080 if (ValidResponse == false || AuthPassed == false){
1081 ServerResponse.RequestResult = COREQUEST_ERROR_SERVER;
1082 ServerResponse.EntityTag = "";
1083 ServerResponse.SessionCode = SessionResult;
1084 ServerResponse.ResultCode = SessionResponseCode;
1085 ServerResponse.ResultMessage = "";
1086 return ServerResponse;
1091 ServerResponse.RequestResult = COREQUEST_OK;
1092 ServerResponse.EntityTag = GetETagValue();
1093 ServerResponse.SessionCode = SessionResult;
1094 ServerResponse.ResultCode = SessionResponseCode;
1095 ServerResponse.ResultMessage = SessionErrorBuffer;
1097 return ServerResponse;
1101 COServerResponse CardDAV2::GetContact(std::string Location, std::string *ContactData){
1103 // Check if authentication was successful, otherwise don't do anything.
1105 COServerResponse ServerResponse;
1107 if (AuthPassed == false){
1108 ServerResponse.RequestResult = COREQUEST_ERROR_NOTCONNECTED;
1109 ServerResponse.EntityTag = "";
1110 ServerResponse.SessionCode = 0;
1111 ServerResponse.ResultCode = 0;
1112 ServerResponse.ResultMessage = "";
1113 return ServerResponse;
1116 ServerSSL ? SetupDefaultParametersSSL(true) : SetupDefaultParametersNonSSL(true);
1119 string ServerAddressURL = BuildURL(ServerPrefix + Location);
1120 curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddressURL.c_str());
1121 curl_easy_setopt(ConnectionSession, CURLOPT_CUSTOMREQUEST, "GET");
1123 if (TestMode == true){
1124 SessionResult = curl_easy_perform(ConnectionSession);
1126 SessionResult = curl_easy_perform(ConnectionSession);
1129 switch(SessionResult){
1132 SSLVerified = COSSL_VERIFIED;
1134 case CURLE_SSL_CACERT:
1135 case CURLE_SSL_CONNECT_ERROR:
1137 SSLVerified = COSSL_UNABLETOVERIFY;
1143 long SessionResponseCode = 0;
1145 curl_easy_getinfo(ConnectionSession, CURLINFO_RESPONSE_CODE, &SessionResponseCode);
1147 if (SessionResponseCode == 200){
1149 ValidResponse = true;
1150 } else if (SessionResponseCode == 403){
1152 ValidResponse = true;
1153 } else if (SessionResponseCode >= 400){
1155 ValidResponse = true;
1158 ValidResponse = false;
1161 if (ValidResponse == false && AuthPassed == false){
1162 ServerResponse.RequestResult = COREQUEST_ERROR_SERVER;
1163 ServerResponse.EntityTag = "";
1164 ServerResponse.SessionCode = SessionResult;
1165 ServerResponse.ResultCode = SessionResponseCode;
1166 ServerResponse.ResultMessage = "";
1167 return ServerResponse;
1172 ServerResponse.RequestResult = COREQUEST_OK;
1173 ServerResponse.EntityTag = "";
1174 ServerResponse.SessionCode = SessionResult;
1175 ServerResponse.ResultCode = SessionResponseCode;
1176 ServerResponse.ResultMessage = SessionErrorBuffer;
1178 (*ContactData) = PageData;
1180 return ServerResponse;
1184 COContactList CardDAV2::GetContactList(std::string SyncToken){
1186 COContactList ServerContactList;
1188 // Check if authentication was successful, otherwise don't do anything.
1190 if (AuthPassed == false){
1191 ServerContactList.ServerResponse.RequestResult = COREQUEST_ERROR_NOTCONNECTED;
1192 ServerContactList.ServerResponse.EntityTag = "";
1193 ServerContactList.ServerResponse.SessionCode = 0;
1194 ServerContactList.ServerResponse.ResultCode = 0;
1195 ServerContactList.ServerResponse.ResultMessage = "";
1196 return ServerContactList;
1199 ServerSSL ? SetupDefaultParametersSSL(true) : SetupDefaultParametersNonSSL(true);
1202 std::string SyncData;
1204 // TODO: Copy old code from CardDAV class as needed.
1206 if (SyncToken.size() > 0){
1208 SyncData = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"
1209 "<D:sync-collection xmlns:D=\"DAV:\"\n"
1210 " xmlns:C=\"urn:ietf:params:xml:ns:carddav\">\n"
1212 SyncData.append(SyncToken);
1213 SyncData.append("</D:sync-token>\n"
1214 "<D:sync-level>1</D:sync-level>\n"
1218 "</D:sync-collection>");
1222 SyncData = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"
1223 "<D:sync-collection xmlns:D=\"DAV:\"\n"
1224 " xmlns:C=\"urn:ietf:params:xml:ns:carddav\">\n"
1225 "<D:sync-level>1</D:sync-level>\n"
1229 "</D:sync-collection>";
1233 string ServerAddressURL = BuildURL(ServerPrefix);
1235 std::cout << SyncData << std::endl;
1237 curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddressURL.c_str());
1238 curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDS, SyncData.c_str());
1239 curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDSIZE, strlen(SyncData.c_str()));
1240 curl_easy_setopt(ConnectionSession, CURLOPT_CUSTOMREQUEST, "REPORT");
1242 HeaderList = curl_slist_append(HeaderList, "Content-Type: application/xml; charset=utf-8");
1243 HeaderList = curl_slist_append(HeaderList, "Depth: 1");
1245 curl_easy_setopt(ConnectionSession, CURLOPT_HTTPHEADER, HeaderList);
1247 if (TestMode == true){
1248 SessionResult = curl_easy_perform(ConnectionSession);
1250 SessionResult = curl_easy_perform(ConnectionSession);
1253 switch(SessionResult){
1256 SSLVerified = COSSL_VERIFIED;
1258 case CURLE_SSL_CACERT:
1259 case CURLE_SSL_CONNECT_ERROR:
1261 SSLVerified = COSSL_UNABLETOVERIFY;
1267 long SessionResponseCode = 0;
1269 curl_easy_getinfo(ConnectionSession, CURLINFO_RESPONSE_CODE, &SessionResponseCode);
1271 if (SessionResponseCode == 207){
1273 ValidResponse = true;
1274 } else if (SessionResponseCode == 403){
1276 ValidResponse = true;
1277 } else if (SessionResponseCode >= 400){
1279 ValidResponse = true;
1282 ValidResponse = false;
1285 if (ValidResponse == false || AuthPassed == false){
1286 ServerContactList.ServerResponse.RequestResult = COREQUEST_ERROR_SERVER;
1287 ServerContactList.ServerResponse.EntityTag = "";
1288 ServerContactList.ServerResponse.SessionCode = SessionResult;
1289 ServerContactList.ServerResponse.ResultCode = SessionResponseCode;
1290 ServerContactList.ServerResponse.ResultMessage = "";
1291 return ServerContactList;
1296 ProcessContactData(&ServerContactList);
1298 ServerContactList.ServerResponse.RequestResult = COREQUEST_OK;
1299 ServerContactList.ServerResponse.EntityTag = "";
1300 ServerContactList.ServerResponse.SessionCode = SessionResult;
1301 ServerContactList.ServerResponse.ResultCode = SessionResponseCode;
1302 ServerContactList.ServerResponse.ResultMessage = SessionErrorBuffer;
1304 return ServerContactList;
1308 bool CardDAV2::CanDoProcessing(){
1312 bool CardDAV2::CanDoSSL(){
1316 COSSLVerified CardDAV2::SSLVerify(){
1320 bool CardDAV2::AbleToLogin(){
1324 bool CardDAV2::HasValidResponse(){
1325 return ValidResponse;
1328 bool CardDAV2::IsSelfSigned(){
1329 return SSLSelfSigned;
1332 void CardDAV2::SetupDefaultParametersNonSSL(bool DoAuthentication){
1334 std::string ServerAddress = "";
1336 string ServerAddressURL = "http://" + ServerAddress + ":" + to_string(ServerPort) + "/";
1337 string UsernamePassword = ServerUser + ":" + ServerPass;
1339 curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddress.c_str());
1340 curl_easy_setopt(ConnectionSession, CURLOPT_NOPROGRESS, 1L);
1341 curl_easy_setopt(ConnectionSession, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
1342 curl_easy_setopt(ConnectionSession, CURLOPT_TIMEOUT, 60);
1343 curl_easy_setopt(ConnectionSession, CURLOPT_FAILONERROR, true);
1344 curl_easy_setopt(ConnectionSession, CURLOPT_USERAGENT, XSDAB_USERAGENT);
1345 curl_easy_setopt(ConnectionSession, CURLOPT_WRITEFUNCTION, CardDAV2::WritebackFunc);
1346 curl_easy_setopt(ConnectionSession, CURLOPT_WRITEDATA, &PageData);
1347 curl_easy_setopt(ConnectionSession, CURLOPT_WRITEHEADER, &PageHeader);
1348 curl_easy_setopt(ConnectionSession, CURLOPT_NOSIGNAL, 1);
1349 curl_easy_setopt(ConnectionSession, CURLOPT_CUSTOMREQUEST, "GET");
1350 curl_easy_setopt(ConnectionSession, CURLOPT_HTTPHEADER, nullptr);
1351 curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDS, nullptr);
1352 curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDSIZE, 0L);
1354 if (DoAuthentication == true){
1355 curl_easy_setopt(ConnectionSession, CURLOPT_USERPWD, UsernamePassword.c_str());
1357 curl_easy_setopt(ConnectionSession, CURLOPT_USERPWD, ":");
1362 void CardDAV2::SetupDefaultParametersSSL(bool DoAuthentication){
1364 // Setup the default parameters.
1366 string ServerAddressURL = "https://" + ServerAddress + ":" + to_string(ServerPort) + "/";
1367 string UsernamePassword = ServerUser + ":" + ServerPass;
1369 curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddressURL.c_str());
1370 curl_easy_setopt(ConnectionSession, CURLOPT_NOPROGRESS, 1L);
1371 curl_easy_setopt(ConnectionSession, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
1372 curl_easy_setopt(ConnectionSession, CURLOPT_TIMEOUT, 60);
1373 curl_easy_setopt(ConnectionSession, CURLOPT_FAILONERROR, true);
1374 curl_easy_setopt(ConnectionSession, CURLOPT_USERAGENT, XSDAB_USERAGENT);
1375 curl_easy_setopt(ConnectionSession, CURLOPT_WRITEFUNCTION, CardDAV2::WritebackFunc);
1376 curl_easy_setopt(ConnectionSession, CURLOPT_WRITEDATA, &PageData);
1377 curl_easy_setopt(ConnectionSession, CURLOPT_WRITEHEADER, &PageHeader);
1378 curl_easy_setopt(ConnectionSession, CURLOPT_ERRORBUFFER, SessionErrorBuffer);
1379 curl_easy_setopt(ConnectionSession, CURLOPT_NOSIGNAL, 1);
1380 curl_easy_setopt(ConnectionSession, CURLOPT_CERTINFO, 1);
1381 curl_easy_setopt(ConnectionSession, CURLOPT_VERBOSE, 1);
1382 curl_easy_setopt(ConnectionSession, CURLOPT_CUSTOMREQUEST, "GET");
1383 curl_easy_setopt(ConnectionSession, CURLOPT_HTTPHEADER, nullptr);
1384 curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDS, nullptr);
1385 curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDSIZE, 0L);
1387 if (DoAuthentication == true){
1388 curl_easy_setopt(ConnectionSession, CURLOPT_USERPWD, UsernamePassword.c_str());
1390 curl_easy_setopt(ConnectionSession, CURLOPT_USERPWD, ":");
1393 #if !defined(__WIN32__)
1395 if (EnableSSLBypass == true){
1396 curl_easy_setopt(ConnectionSession, CURLOPT_SSL_VERIFYHOST, 0);
1397 curl_easy_setopt(ConnectionSession, CURLOPT_SSL_VERIFYPEER, 0);
1399 curl_easy_setopt(ConnectionSession, CURLOPT_SSL_VERIFYHOST, 2);
1400 curl_easy_setopt(ConnectionSession, CURLOPT_SSL_VERIFYPEER, 1);
1405 if (TestMode == false && ServerAccount.size() > 0){
1407 // Check if the server certificate file exists.
1409 string CertificateFilename = GetAccountDir(ServerAccount, true);
1411 if (wxFile::Exists(CertificateFilename)){
1413 curl_easy_setopt(ConnectionSession, CURLOPT_CAINFO, CertificateFilename.c_str());
1421 string CardDAV2::BuildURL(string URI){
1423 string ServerAddressURL;
1425 if (SSLStatus == true){
1426 ServerAddressURL = "https://" + ServerAddress + ":" + to_string(ServerPort) + URI;
1428 ServerAddressURL = "https://" + ServerAddress + ":" + to_string(ServerPort) + URI;
1431 return ServerAddressURL;
1435 string CardDAV2::GetErrorMessage(){
1437 ErrorMessage = SessionErrorBuffer;
1438 return ErrorMessage;
1442 void CardDAV2::ResetResults(){
1445 COSSLVerified SSLVerified = COSSL_NORESULT;
1446 ValidResponse = false;
1449 SSLSelfSigned = false;
1450 TaskCompleted = false;
1452 SessionErrorBuffer[0] = '\0';
1455 if (HeaderList != nullptr){
1456 curl_slist_free_all(HeaderList);
1457 HeaderList = nullptr;
1462 string CardDAV2::GetETagValue(){
1464 xmlDocPtr xmlCardDAVDoc;
1466 xmlCardDAVDoc = xmlReadMemory(PageData.c_str(), (int)PageData.size(), "noname.xml", NULL, 0);
1468 xmlNodePtr nodeLevel1;
1469 xmlNodePtr nodeLevel2;
1470 xmlNodePtr nodeLevel3;
1471 xmlNodePtr nodeLevel4;
1472 xmlNodePtr nodeLevel5;
1473 xmlNodePtr nodeLevel6;
1475 //std::map<wxString,wxString> xmlDataMap;
1477 std::string DataFilename;
1478 std::string ETagData;
1480 std::string xmlStringSafe;
1481 std::string ETagValue;
1483 // Tranverse through the catacombs of the response to get our ETag for the file.
1485 for (nodeLevel1 = xmlCardDAVDoc->children;
1487 nodeLevel1 = nodeLevel1->next)
1490 bool HREFFound = FALSE;
1491 bool ETagFound = FALSE;
1493 for (nodeLevel2 = nodeLevel1->children;
1495 nodeLevel2 = nodeLevel2->next)
1498 for (nodeLevel3 = nodeLevel2->children;
1500 nodeLevel3 = nodeLevel3->next)
1503 if (!xmlStrcmp(nodeLevel3->name, (const xmlChar *)"href") ||
1504 !xmlStrcmp(nodeLevel3->name, (const xmlChar *)"d:href") ||
1505 !xmlStrcmp(nodeLevel3->name, (const xmlChar *)"D:href")
1508 // Get the filename.
1510 for (nodeLevel4 = nodeLevel3->children;
1512 nodeLevel4 = nodeLevel4->next)
1515 if (!xmlStrcmp(nodeLevel4->name, (const xmlChar *)"text") ||
1516 !xmlStrcmp(nodeLevel4->name, (const xmlChar *)"d:text") ||
1517 !xmlStrcmp(nodeLevel4->name, (const xmlChar *)"D:text")
1520 DataFilename = wxString::FromUTF8((const char*)nodeLevel4->content);
1521 wxStringTokenizer wSTDFilename(DataFilename, wxT("/"));
1523 while (wSTDFilename.HasMoreTokens()){
1525 DataFilename = wSTDFilename.GetNextToken().ToStdString();
1539 for (nodeLevel4 = nodeLevel3->children;
1541 nodeLevel4 = nodeLevel4->next)
1544 for (nodeLevel5 = nodeLevel4->children;
1546 nodeLevel5 = nodeLevel5->next)
1549 if (!xmlStrcmp(nodeLevel5->name, (const xmlChar *)"getetag") ||
1550 !xmlStrcmp(nodeLevel5->name, (const xmlChar *)"d:getetag") ||
1551 !xmlStrcmp(nodeLevel5->name, (const xmlChar *)"D:getetag")
1554 for (nodeLevel6 = nodeLevel5->children;
1556 nodeLevel6 = nodeLevel6->next)
1559 // Strip the quotes from the ETag.
1561 ETagData = (const char*)nodeLevel6->content;
1562 if (ETagData[0] == '"' && ETagData[(ETagData.size() - 1)] == '"'){
1564 ETagData.erase(0, 1);
1565 ETagData.erase((ETagData.size() - 1));
1585 if (HREFFound == TRUE && ETagFound == TRUE){
1587 // Add to the map data.
1589 ETagValue = ETagData;
1600 xmlFreeDoc(xmlCardDAVDoc);
1606 string CardDAV2::GetETagHeader(){
1608 // Go through each of the lines looking for the
1613 bool FastForward = false;
1615 for (int HeaderSeek = 0; HeaderSeek < PageHeader.size(); HeaderSeek++){
1617 if (FastForward == true){
1619 if (PageHeader[HeaderSeek] == '\n'){
1620 FastForward = false;
1628 PageHeader.substr(HeaderSeek, 5) == "ETag:";
1631 catch (const out_of_range &oor){
1635 if (PageHeader.substr(HeaderSeek, 5) == "ETag:"){
1637 int CharacterSeek = 5;
1639 while ((HeaderSeek + CharacterSeek) < PageHeader.size()){
1641 if (PageHeader.substr((HeaderSeek + CharacterSeek), 2) == "\r\n"){
1645 HeaderValue += PageHeader.substr((HeaderSeek + CharacterSeek), 1);
1658 if (PageHeader[HeaderSeek] == '\n'){
1662 //HeaderName += PageHeader.substr(HeaderSeek, 1);
1666 // Check for quotation marks at the start and end and strip
1669 if (HeaderValue.size() >= 2){
1671 if (HeaderValue[0] == '"'){
1672 HeaderValue.erase((HeaderValue.size() - 1));
1673 HeaderValue.erase(0);
1682 vector<string> CardDAV2::GetDAVHeader(){
1684 // Go through each of the lines looking for the
1689 bool FastForward = false;
1690 vector<string> DAVHeaderList;
1692 for (int HeaderSeek = 0; HeaderSeek < PageHeader.size(); HeaderSeek++){
1694 if (FastForward == true){
1696 if (PageHeader[HeaderSeek] == '\n'){
1697 FastForward = false;
1705 PageHeader.substr(HeaderSeek, 4) == "DAV:";
1708 catch (const out_of_range &oor){
1712 if (PageHeader.substr(HeaderSeek, 4) == "DAV:"){
1714 int CharacterSeek = 5;
1716 while ((HeaderSeek + CharacterSeek) < PageHeader.size()){
1718 if (PageHeader.substr((HeaderSeek + CharacterSeek), 2) == "\r\n"){
1722 HeaderValue += PageHeader.substr((HeaderSeek + CharacterSeek), 1);
1735 if (PageHeader[HeaderSeek] == '\n'){
1739 //HeaderName += PageHeader.substr(HeaderSeek, 1);
1743 // Split the header data.
1745 std::string DAVHeaderValue;
1747 for (int HeaderSeek = 0; HeaderSeek < HeaderValue.size(); HeaderSeek++){
1749 if (HeaderValue.substr(HeaderSeek, 1) == ","){
1750 DAVHeaderList.push_back(DAVHeaderValue);
1751 DAVHeaderValue = "";
1756 DAVHeaderValue += HeaderValue[HeaderSeek];
1760 if (DAVHeaderValue.size() > 0){
1762 DAVHeaderList.push_back(DAVHeaderValue);
1766 return DAVHeaderList;
1770 void CardDAV2::ProcessContactData(COContactList *ContactList){
1772 xmlDocPtr xmlCardDAVDoc;
1773 xmlCardDAVDoc = xmlReadMemory(PageData.c_str(), (int)PageData.size(), "noname.xml", NULL, 0);
1775 xmlNodePtr MultiStatusNode;
1776 xmlNodePtr ResponseNode;
1777 xmlNodePtr ResponseDataNode;
1778 xmlNodePtr PropStatNode;
1779 xmlNodePtr ValueNode;
1780 xmlNodePtr ETagNode;
1781 xmlNodePtr StatusNode;
1783 std::string HREFValue;
1784 std::string ETagValue;
1785 std::string StatusValue;
1786 std::string SyncValue;
1788 // Go through the document!
1790 MultiStatusNode = xmlCardDAVDoc->children;
1792 if (MultiStatusNode == nullptr){
1796 bool SyncTokenFound = false;
1798 // Tranverse through the catacombs of the response to get our ETag for the file and
1799 // the server syncronisation token.
1801 for (ResponseNode = MultiStatusNode->children;
1802 ResponseNode != nullptr;
1803 ResponseNode = ResponseNode->next){
1805 // Check if tag is response or sync-token.
1807 if (!xmlStrcmp(ResponseNode->name, (const xmlChar *)"response") ||
1808 !xmlStrcmp(ResponseNode->name, (const xmlChar *)"d:response") ||
1809 !xmlStrcmp(ResponseNode->name, (const xmlChar *)"D:response")){
1811 COContactStatus ContactStatus = COCS_UNKNOWN;
1813 for (ResponseDataNode = ResponseNode->children;
1814 ResponseDataNode != nullptr;
1815 ResponseDataNode = ResponseDataNode->next){
1817 if (!xmlStrcmp(ResponseDataNode->name, (const xmlChar *)"href") ||
1818 !xmlStrcmp(ResponseDataNode->name, (const xmlChar *)"d:href") ||
1819 !xmlStrcmp(ResponseDataNode->name, (const xmlChar *)"D:href")){
1821 HREFValue = (const char*)ResponseDataNode->children->content;
1823 // Get the filename after the last forward slash.
1827 for (int HREFValueSeek = 0; HREFValueSeek < HREFValue.size(); HREFValueSeek++){
1829 if (HREFValue[HREFValueSeek] == '/'){
1831 LastSlash = HREFValueSeek;
1837 HREFValue = HREFValue.substr((LastSlash + 1));
1839 } else if (!xmlStrcmp(ResponseDataNode->name, (const xmlChar *)"propstat") ||
1840 !xmlStrcmp(ResponseDataNode->name, (const xmlChar *)"d:propstat") ||
1841 !xmlStrcmp(ResponseDataNode->name, (const xmlChar *)"D:propstat")){
1843 for (PropStatNode = ResponseDataNode->children;
1844 PropStatNode != nullptr;
1845 PropStatNode = PropStatNode->next){
1847 if (!xmlStrcmp(PropStatNode->name, (const xmlChar *)"prop") ||
1848 !xmlStrcmp(PropStatNode->name, (const xmlChar *)"d:prop") ||
1849 !xmlStrcmp(PropStatNode->name, (const xmlChar *)"D:prop")){
1851 for (ETagNode = PropStatNode->children;
1852 ETagNode != nullptr;
1853 ETagNode = ETagNode->next){
1855 if (!xmlStrcmp(ETagNode->name, (const xmlChar *)"getetag") ||
1856 !xmlStrcmp(ETagNode->name, (const xmlChar *)"getetag") ||
1857 !xmlStrcmp(ETagNode->name, (const xmlChar *)"getetag")){
1859 ETagValue = (const char*)ETagNode->children->content;
1861 if (ETagValue.size() > 2 && ETagValue.substr(0,1) == "\""){
1862 ETagValue.erase((ETagValue.size() - 1),1);
1863 ETagValue.erase(0,1);
1871 } else if (!xmlStrcmp(PropStatNode->name, (const xmlChar *)"status") ||
1872 !xmlStrcmp(PropStatNode->name, (const xmlChar *)"d:status") ||
1873 !xmlStrcmp(PropStatNode->name, (const xmlChar *)"D:status")){
1875 StatusValue = (const char*)PropStatNode->children->content;
1877 if (StatusValue == "HTTP/1.1 200 OK"){
1879 ContactStatus = COCS_UPDATED;
1881 } else if (StatusValue == "HTTP/1.1 404 Not Found"){
1883 ContactStatus = COCS_DELETED;
1887 ContactStatus = COCS_UNKNOWN;
1899 COContactData ContactInformation;
1901 ContactInformation.Location = HREFValue;
1902 ContactInformation.Data = ETagValue;
1903 ContactInformation.Status = ContactStatus;
1907 StatusValue.clear();
1909 ContactList->ListData.push_back(ContactInformation);
1911 } else if (!xmlStrcmp(ResponseNode->name, (const xmlChar *)"sync-token") ||
1912 !xmlStrcmp(ResponseNode->name, (const xmlChar *)"d:sync-token") ||
1913 !xmlStrcmp(ResponseNode->name, (const xmlChar *)"D:sync-token")){
1915 SyncValue = (const char*)ResponseNode->children->content;
1921 ContactList->SyncToken = SyncValue;
1923 xmlFreeDoc(xmlCardDAVDoc);