Home | News | Projects | Releases
Bugs | RFE | Repositories | Help
CardDAV2: Fixed issue with displaying SSL certificate
[xestiaab/.git] / source / carddav2 / carddav2.cpp
1 // CardDAV2.cpp - CardDAV v2 class
2 //
3 // (c) 2012-2016 Xestia Software Development.
4 //
5 // This file is part of Xestia Address Book.
6 //
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.
10 //
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.
15 //
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/> 
19 #include "carddav2.h"
21 using namespace std;
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;
31         TestMode = true;
32         this->SetupConnectionObject();
34 }
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;
47         TestMode = false;
48         this->SetupConnectionObject();
50 }
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);
55         
56 }
58 size_t CardDAV2::WritebackFuncImplementation(char *ptr, size_t size, size_t nmemb, void *stream){
59         
60         // Writeback function for the CardDAV object.
61                 
62         CardDAV2PassObject *data = static_cast<CardDAV2PassObject*>(stream);
63         data->DataSetting->append(ptr);
64         
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;
72                 CURLcode TLSCode;
73                 TLSCode = curl_easy_getinfo(data->ConnectionSessionObject, CURLINFO_TLS_SSL_PTR, &TLSInfo);
75                 SecTrustRef CertificateData;
76                 
77                 if (TLSInfo->internals != nullptr && TLSCode == CURLE_OK) {
78                         SSLCopyPeerTrust((SSLContext*)TLSInfo->internals, &CertificateData);
79                         data->SSLContext = CertificateData;
80                 }
82 #elif defined(__WIN32__)
84                 const struct curl_tlssessioninfo *TLSInfo;
85                 CURLcode TLSCode;
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;
101                 }
103 #endif
105         }
107         return size * nmemb;
111 void CardDAV2::SetCertificateData() {
115 CardDAV2::~CardDAV2(){
116         
117         curl_easy_cleanup(ConnectionSession);
118         ConnectionSession = nullptr;
119         
120         if (HeaderList != nullptr){
121                 curl_slist_free_all(HeaderList);
122                 HeaderList = nullptr;
123         }
125 #if defined(__WIN32__)
127         if (CertificateData != nullptr) {
129                 CertFreeCertificateContext(CertificateData);
131         }
133 #endif
134         
137 #if defined(__APPLE__)
139 SecTrustRef CardDAV2::BuildSSLCollection(){
140         
141         return CertificateData;
142         
145 #elif defined(__WIN32__)
147 PCCERT_CONTEXT CardDAV2::BuildSSLCollection(){
149         return CertificateData;
153 #else
155 SSLCertCollectionString CardDAV2::BuildSSLCollection(){
157         // Build and return the SSL collection.
158         
159         cout << "Build SSL Collection!" << endl;
160         
161         SSLCertCollectionString SSLCertInfo;
163         // Grab the certificate data.
165         union {
166                 struct curl_slist *certdata;
167                 struct curl_certinfo *certinfo;
168         } certptr;
170         certptr.certdata = NULL;
171         
172         CURLcode result = curl_easy_getinfo(ConnectionSession, CURLINFO_CERTINFO, &certptr.certinfo);
174         cout << certptr.certinfo->num_of_certs << endl;
175         
176         std::string CertPropName;
177         std::string CertPropValue;
178         
179         for (int i = 0; i < certptr.certinfo->num_of_certs; i++){
180                 
181                 struct curl_slist *slist;
182                 SSLCertDataString SSLCertDataInc;
183                 
184                 for (slist = certptr.certinfo->certinfo[i]; slist; slist = slist->next){
185                         
186                         // Using wxStringTokenizer from wxWidgets.
187                         
188                         wxStringTokenizer CertDataInc(wxString::FromUTF8(slist->data), ":");
189                         
190                         // Get first token as the property name.
191                         
192                         CertPropName = CertDataInc.GetNextToken().ToStdString();
193                         
194                         // Get remaining tokens as the property value.
195                         
196                         while(CertDataInc.HasMoreTokens()){
197                         
198                                 CertPropValue.append(CertDataInc.GetNextToken());
199                         
200                         }
201                         
202                         SSLCertDataInc.CertData.insert(std::make_pair(CertPropName, CertPropValue));
203                         CertPropName.clear();
204                         CertPropValue.clear();
205                         
206                 }
207         
208                 SSLCertInfo.SSLCollection.insert(std::make_pair(i, SSLCertDataInc));
209         
210         }
211         
212         return SSLCertInfo;
216 #endif
218 void CardDAV2::BypassSSLVerification(bool EnableBypass) {
219         EnableSSLBypass = EnableBypass;
220         SSLSelfSigned = EnableBypass;
223 void CardDAV2::SetupConnectionObject(){
224         ConnectionSession = curl_easy_init();
227 bool CardDAV2::IsTaskCompleted(){
228         return false;
231 COConnectResult CardDAV2::Connect(bool DoAuthentication){
232         
233         ServerSSL ? SetupDefaultParametersSSL(DoAuthentication) : SetupDefaultParametersNonSSL(DoAuthentication);
234         ResetResults();
235         
236         COConnectResult ConnectResult = COCONNECT_UNITTESTFAIL;
237         string ServerAddressURL = BuildURL("/principals/");
238         
239         curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddressURL.c_str());
240         
241         if (TestMode == true){
242                 SessionResult = curl_easy_perform(ConnectionSession);
243         } else {
244                 SessionResult = curl_easy_perform(ConnectionSession);           
245         }
246         
247         switch(SessionResult){
248                 case CURLE_OK:
249                 case CURLE_HTTP_RETURNED_ERROR:
250                         SSLStatus = true;
251                         SSLVerified = COSSL_VERIFIED;
252                         ConnectResult = COCONNECT_OK;
253                         break;
254                 case CURLE_SSL_CACERT:
255                 case CURLE_SSL_CONNECT_ERROR:
256                         SSLStatus = true;
257                         ConnectResult = COCONNECT_OK;
258                         SSLVerified = COSSL_UNABLETOVERIFY;
259                         break;
260                 default:
261                         ConnectResult = COCONNECT_INVALID;
262                         break;
263         };
264         
265         // Set the certificate data (if required).
267 #if defined(__APPLE__)
268         
269         if (ServerSSL) {
270                 
271                 CertificateData = PageHeaderObject.SSLContext;
272                 
273         }
274         
275 #elif defined(__WIN32__)
277         if (ServerSSL) {
279                 CertificateData = PageHeaderObject.SSLContext;
281         }
283 #endif
285         // Check if an error occured before continuing.
286         
287         // Check if authentication was successful.
288         
289         long SessionResponseCode = 0;
290         
291         curl_easy_getinfo(ConnectionSession, CURLINFO_RESPONSE_CODE, &SessionResponseCode);
292         
293         if (DoAuthentication == true){
294                 
295                 // Get the HTTP status code (Should be 200 and not 403).
296                 // Return error otherwise.
297                 
298                 if (SessionResponseCode == 200){
299                         ConnectResult = COCONNECT_OK;
300                         AuthPassed = true;
301                         ValidResponse = true;
302                 } else if (SessionResponseCode == 401){
303                         ConnectResult = COCONNECT_AUTHFAIL;
304                         AuthPassed = false;
305                         ValidResponse = true;
306                 } else if (SessionResponseCode >= 200) {
307                         ConnectResult = COCONNECT_INVALID;
308                         AuthPassed = false;
309                         ValidResponse = true;
310                 } else {
311                         ConnectResult = COCONNECT_INVALID;
312                         AuthPassed = false;
313                         ValidResponse = false;                  
314                 }
315                 
316         } else {
317                 
318                 ValidResponse = true;
319                 
320         }
321         
322         // Check the header to see if CardDAV is supported.
323         
324         vector<string> DAVHeaderValues = GetDAVHeader();
325         
326         for (vector<string>::iterator DAVHeaderValuesIter = DAVHeaderValues.begin();
327                 DAVHeaderValuesIter != DAVHeaderValues.end(); DAVHeaderValuesIter++){
328                 
329                 if ((*DAVHeaderValuesIter) == "addressbook"){
330                         CanProcess = true;
331                         break;
332                 }
333                         
334         }
335         
336         return ConnectResult;
337         
340 COServerResponse CardDAV2::GetDefaultPrefix(string *ServerPrefix){
342         // Check if authentication was successful, otherwise don't do anything.
344         COServerResponse ServerResponse;
345         
346         if (AuthPassed == false){
347                 ServerResponse.RequestResult = COREQUEST_ERROR_NOTCONNECTED;
348                 ServerResponse.EntityTag = "";
349                 ServerResponse.SessionCode = 0;
350                 ServerResponse.ResultCode = 0;
351                 ServerResponse.ResultMessage = "";
352                 return ServerResponse;
353         }
355         ServerSSL ? SetupDefaultParametersSSL(true) : SetupDefaultParametersNonSSL(true);
356         ResetResults();
357         
358         // Need to do three requests:
359         
360         // 1. Get the current user principal URI.
361         // 2. Get the address book home URI.
362         // 3. Get the default address book URI.
363         
364         // Setup the first query finding out where the principal URL is.
365         
366         const char* CurrentUserPrincipalXMLQuery = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"
367                 "<D:propfind xmlns:D=\"DAV:\">\n"
368                 " <D:prop>"
369                 "  <D:current-user-principal/>\n"
370                 " </D:prop>"
371                 "</D:propfind>";
373         // Setup the second query finding out where the address book home URL is.
374         
375         const char* AddressBookHomeXMLQuery = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"
376         "<D:propfind xmlns:D=\"DAV:\""
377         "  xmlns:C=\"urn:ietf:params:xml:ns:carddav\">\n"
378         "  <D:prop>\n"
379         "    <C:addressbook-home-set/>\n"
380         "  </D:prop>\n"
381         "</D:propfind>";
382         
383         // Setup the third query finding out where the default address book URL is.
384         
385         const char* DefaultAddressBookXMLQuery = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"
386         "<D:propfind xmlns:D=\"DAV:\""
387         "  xmlns:C=\"urn:ietf:params:xml:ns:carddav\">\n"
388         "  <D:prop>\n"
389         "    <C:default-addressbook-URL/>\n"    
390         "  </D:prop>\n"
391         "</D:propfind>";
392         
393         string ServerAddressURL = BuildURL("/principals/");
394         curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddressURL.c_str());
395         curl_easy_setopt(ConnectionSession, CURLOPT_CUSTOMREQUEST, "PROPFIND");
396         curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDS, CurrentUserPrincipalXMLQuery);
397         curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDSIZE, strlen(CurrentUserPrincipalXMLQuery));
398         
399         if (TestMode == true){
400                 SessionResult = curl_easy_perform(ConnectionSession);
401         } else {
402                 
403         }
404         
405         switch(SessionResult){
406                 case CURLE_OK:
407                         SSLStatus = true;
408                         SSLVerified = COSSL_VERIFIED;
409                         break;
410                 case CURLE_SSL_CACERT:
411                 case CURLE_SSL_CONNECT_ERROR:
412                         SSLStatus = true;
413                         SSLVerified = COSSL_UNABLETOVERIFY;
414                         break;
415                 default:
416                         break;
417         };
418         
419         long SessionResponseCode = 0;
420         
421         curl_easy_getinfo(ConnectionSession, CURLINFO_RESPONSE_CODE, &SessionResponseCode);
422         
423         if (SessionResponseCode == 200 || SessionResponseCode == 207){
424                 AuthPassed = true;
425                 ValidResponse = true;
426         } else if (SessionResponseCode == 403){
427                 AuthPassed = false;
428                 ValidResponse = true;
429         } else if (SessionResponseCode >= 400) {
430                 AuthPassed = false;
431                 ValidResponse = true;
432         } else {
433                 AuthPassed = false;
434                 ValidResponse = false;                  
435         }
436         
437         if (ValidResponse == false && AuthPassed == false){
438                 ServerResponse.RequestResult = COREQUEST_ERROR_SERVER;
439                 ServerResponse.EntityTag = "";
440                 ServerResponse.SessionCode = SessionResult;
441                 ServerResponse.ResultCode = SessionResponseCode;
442                 ServerResponse.ResultMessage = "";
443                 return ServerResponse;
444         }
445         
446         // Process the first response.
447         
448         string UserPrincipalURI = GetUserPrincipalURI();
449         
450         // Cleanup and reset for the second connection.
451         
452         ServerSSL ? SetupDefaultParametersSSL(true) : SetupDefaultParametersNonSSL(true);
453         ResetResults();
455         ServerAddressURL = BuildURL(UserPrincipalURI);
456         curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddressURL.c_str());
457         curl_easy_setopt(ConnectionSession, CURLOPT_CUSTOMREQUEST, "PROPFIND");
458         curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDS, AddressBookHomeXMLQuery);
459         curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDSIZE, strlen(AddressBookHomeXMLQuery));
460         
461         if (TestMode == true){
462                 SessionResult = curl_easy_perform(ConnectionSession);
463         } else {
464                 
465         }
466         
467         switch(SessionResult){
468                 case CURLE_OK:
469                         SSLStatus = true;
470                         SSLVerified = COSSL_VERIFIED;
471                         break;
472                 case CURLE_SSL_CACERT:
473                 case CURLE_SSL_CONNECT_ERROR:
474                         SSLStatus = true;
475                         SSLVerified = COSSL_UNABLETOVERIFY;
476                         break;
477                 default:
478                         break;
479         };
480         
481         SessionResponseCode = 0;
482         
483         curl_easy_getinfo(ConnectionSession, CURLINFO_RESPONSE_CODE, &SessionResponseCode);
484         
485         if (SessionResponseCode == 200 || SessionResponseCode == 207){
486                 AuthPassed = true;
487                 ValidResponse = true;
488         } else if (SessionResponseCode == 403){
489                 AuthPassed = false;
490                 ValidResponse = true;
491         } else if (SessionResponseCode >= 400) {
492                 AuthPassed = false;
493                 ValidResponse = true;
494         } else {
495                 AuthPassed = false;
496                 ValidResponse = false;                  
497         }
498         
499         if (ValidResponse == false && AuthPassed == false){
500                 ServerResponse.RequestResult = COREQUEST_ERROR_SERVER;
501                 ServerResponse.EntityTag = "";
502                 ServerResponse.SessionCode = SessionResult;
503                 ServerResponse.ResultCode = SessionResponseCode;
504                 ServerResponse.ResultMessage = "";
505                 return ServerResponse;
506         }
507         
508         // Process the second response.
509         
510         string AddressBookHomeURI = GetAddressBookHomeURI();
511         
512         // Cleanup and reset for the second connection.
513         
514         ServerSSL ? SetupDefaultParametersSSL(true) : SetupDefaultParametersNonSSL(true);
515         ResetResults();
516         
517         ServerAddressURL = BuildURL(AddressBookHomeURI);
518         curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddressURL.c_str());
519         curl_easy_setopt(ConnectionSession, CURLOPT_CUSTOMREQUEST, "PROPFIND");
520         curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDS, DefaultAddressBookXMLQuery);
521         curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDSIZE, strlen(DefaultAddressBookXMLQuery));
522         
523         if (TestMode == true){
524                 SessionResult = curl_easy_perform(ConnectionSession);
525         } else {
526                 
527         }
528         
529         switch(SessionResult){
530                 case CURLE_OK:
531                         SSLStatus = true;
532                         SSLVerified = COSSL_VERIFIED;
533                         break;
534                 case CURLE_SSL_CACERT:
535                 case CURLE_SSL_CONNECT_ERROR:
536                         SSLStatus = true;
537                         SSLVerified = COSSL_UNABLETOVERIFY;
538                         break;
539                 default:
540                         break;
541         };
542         
543         SessionResponseCode = 0;
544         
545         curl_easy_getinfo(ConnectionSession, CURLINFO_RESPONSE_CODE, &SessionResponseCode);
546         
547         if (SessionResponseCode == 200 || SessionResponseCode == 207){
548                 AuthPassed = true;
549                 ValidResponse = true;
550         } else if (SessionResponseCode == 403){
551                 AuthPassed = false;
552                 ValidResponse = true;
553         } else if (SessionResponseCode >= 200) {
554                 AuthPassed = false;
555                 ValidResponse = true;
556         } else {
557                 AuthPassed = false;
558                 ValidResponse = false;                  
559         }
560         
561         if (ValidResponse == false || AuthPassed == false){
562                 ServerResponse.RequestResult = COREQUEST_ERROR_SERVER;
563                 ServerResponse.EntityTag = "";
564                 ServerResponse.SessionCode = SessionResult;
565                 ServerResponse.ResultCode = SessionResponseCode;
566                 ServerResponse.ResultMessage = "";
567                 return ServerResponse;
568         }
569         
570         // Process the second response.
571         
572         (*ServerPrefix) = GetDefaultAddressBookURI();
573         
574         CanProcess = true;
575         
576         ServerResponse.RequestResult = COREQUEST_OK;
577         ServerResponse.EntityTag = "";
578         ServerResponse.SessionCode = SessionResult;
579         ServerResponse.ResultCode = SessionResponseCode;
580         ServerResponse.ResultMessage = SessionErrorBuffer;
581         return ServerResponse;
582         
585 std::string CardDAV2::GetUserPrincipalURI(){
586         
587         xmlDocPtr xmlCardDAVDoc;
588         xmlCardDAVDoc = xmlReadMemory(PageData.c_str(), (int)PageData.size(), "noname.xml", NULL, 0);
589         string UserPrincipalURI = "";
590         
591         xmlNodePtr nodeLevel1;
592         xmlNodePtr nodeLevel2;
593         xmlNodePtr nodeLevel3;
594         xmlNodePtr nodeLevel4;
595         xmlNodePtr nodeLevel5;
596         xmlNodePtr nodeLevel6;
597         xmlNodePtr nodeLevel7;
598                 
599         for (nodeLevel1 = xmlCardDAVDoc->children;
600                 nodeLevel1 != NULL;
601                 nodeLevel1 = nodeLevel1->next)
602         {
604                 for (nodeLevel2 = nodeLevel1->children;
605                         nodeLevel2 != NULL;
606                         nodeLevel2 = nodeLevel2->next)
607                 {
610                         for (nodeLevel3 = nodeLevel2->children;
611                         nodeLevel3 != NULL;
612                         nodeLevel3 = nodeLevel3->next)
613                         {
614                         
615                                 for (nodeLevel4 = nodeLevel3->children;
616                                 nodeLevel4 != NULL;
617                                 nodeLevel4 = nodeLevel4->next)
618                                 {
619                         
620                                         for (nodeLevel5 = nodeLevel4->children;
621                                         nodeLevel5 != NULL;
622                                         nodeLevel5 = nodeLevel5->next)
623                                         {
624                         
625                                                 for (nodeLevel6 = nodeLevel5->children;
626                                                 nodeLevel6 != NULL;
627                                                 nodeLevel6 = nodeLevel6->next)
628                                                 {
629                         
630                                                         if (!xmlStrcmp(nodeLevel6->name, (const xmlChar *)"href") ||
631                                                         !xmlStrcmp(nodeLevel6->name, (const xmlChar *)"d:href") ||
632                                                         !xmlStrcmp(nodeLevel6->name, (const xmlChar *)"D:href")
633                                                         ){
634                         
635                                                                 // Found the <href> part so extract the principal URL address.
636                                                                 
637                                                                 for (nodeLevel7 = nodeLevel6->children;
638                                                                 nodeLevel7 != NULL;
639                                                                 nodeLevel7 = nodeLevel7->next)
640                                                                 {
641                                                                 
642                                                                         UserPrincipalURI = ((const char*)nodeLevel7->content);
644                                                                 }
645                         
646                                                         }
647                         
648                                                 }
649                         
650                                         }
651                         
652                                 }
653                         
654                         }
655                 
656                 }
657                 
658         }
659         
660         xmlFreeDoc(xmlCardDAVDoc);
661         
662         return UserPrincipalURI;
663         
666 std::string CardDAV2::GetAddressBookHomeURI(){
667         
668         xmlDocPtr xmlCardDAVDoc;
669         xmlCardDAVDoc = xmlReadMemory(PageData.c_str(), (int)PageData.size(), "noname.xml", NULL, 0);
670         string AddressBookHomeURI = "";
671         
672         xmlNodePtr nodeLevel1;
673         xmlNodePtr nodeLevel2;
674         xmlNodePtr nodeLevel3;
675         xmlNodePtr nodeLevel4;
676         xmlNodePtr nodeLevel5;
677         xmlNodePtr nodeLevel6;
678         xmlNodePtr nodeLevel7;
679                 
680         for (nodeLevel1 = xmlCardDAVDoc->children;
681                 nodeLevel1 != NULL;
682                 nodeLevel1 = nodeLevel1->next)
683         {
685                 for (nodeLevel2 = nodeLevel1->children;
686                         nodeLevel2 != NULL;
687                         nodeLevel2 = nodeLevel2->next)
688                 {
691                         for (nodeLevel3 = nodeLevel2->children;
692                         nodeLevel3 != NULL;
693                         nodeLevel3 = nodeLevel3->next)
694                         {
695                         
696                                 for (nodeLevel4 = nodeLevel3->children;
697                                 nodeLevel4 != NULL;
698                                 nodeLevel4 = nodeLevel4->next)
699                                 {
700                         
701                                         for (nodeLevel5 = nodeLevel4->children;
702                                         nodeLevel5 != NULL;
703                                         nodeLevel5 = nodeLevel5->next)
704                                         {
705                         
706                                                 for (nodeLevel6 = nodeLevel5->children;
707                                                 nodeLevel6 != NULL;
708                                                 nodeLevel6 = nodeLevel6->next)
709                                                 {
710                         
711                                                         if (!xmlStrcmp(nodeLevel6->name, (const xmlChar *)"href") ||
712                                                         !xmlStrcmp(nodeLevel6->name, (const xmlChar *)"d:href") ||
713                                                         !xmlStrcmp(nodeLevel6->name, (const xmlChar *)"D:href")
714                                                         ){
715                         
716                                                                 // Found the <href> part so extract the principal URL address.
717                                                                 
718                                                                 for (nodeLevel7 = nodeLevel6->children;
719                                                                 nodeLevel7 != NULL;
720                                                                 nodeLevel7 = nodeLevel7->next)
721                                                                 {
722                                                                 
723                                                                         AddressBookHomeURI = ((const char*)nodeLevel7->content);
725                                                                 }
726                         
727                                                         }
728                         
729                                                 }
730                         
731                                         }
732                         
733                                 }
734                         
735                         }
736                 
737                 }
738                 
739         }
740         
741         xmlFreeDoc(xmlCardDAVDoc);
742         
743         return AddressBookHomeURI;
744         
747 std::string CardDAV2::GetDefaultAddressBookURI(){
748         
749         xmlDocPtr xmlCardDAVDoc;
750         xmlCardDAVDoc = xmlReadMemory(PageData.c_str(), (int)PageData.size(), "noname.xml", NULL, 0);
751         string DefaultAddressBookURI = "";
752         
753         xmlNodePtr nodeLevel1;
754         xmlNodePtr nodeLevel2;
755         xmlNodePtr nodeLevel3;
756         xmlNodePtr nodeLevel4;
757         xmlNodePtr nodeLevel5;
758         xmlNodePtr nodeLevel6;
759         xmlNodePtr nodeLevel7;
760                 
761         for (nodeLevel1 = xmlCardDAVDoc->children;
762                 nodeLevel1 != NULL;
763                 nodeLevel1 = nodeLevel1->next)
764         {
766                 for (nodeLevel2 = nodeLevel1->children;
767                         nodeLevel2 != NULL;
768                         nodeLevel2 = nodeLevel2->next)
769                 {
772                         for (nodeLevel3 = nodeLevel2->children;
773                         nodeLevel3 != NULL;
774                         nodeLevel3 = nodeLevel3->next)
775                         {
776                         
777                                 for (nodeLevel4 = nodeLevel3->children;
778                                 nodeLevel4 != NULL;
779                                 nodeLevel4 = nodeLevel4->next)
780                                 {
781                         
782                                         for (nodeLevel5 = nodeLevel4->children;
783                                         nodeLevel5 != NULL;
784                                         nodeLevel5 = nodeLevel5->next)
785                                         {
786                         
787                                                 for (nodeLevel6 = nodeLevel5->children;
788                                                 nodeLevel6 != NULL;
789                                                 nodeLevel6 = nodeLevel6->next)
790                                                 {
791                         
792                                                         if (!xmlStrcmp(nodeLevel6->name, (const xmlChar *)"href") ||
793                                                         !xmlStrcmp(nodeLevel6->name, (const xmlChar *)"d:href") ||
794                                                         !xmlStrcmp(nodeLevel6->name, (const xmlChar *)"D:href")
795                                                         ){
796                         
797                                                                 // Found the <href> part so extract the principal URL address.
798                                                                 
799                                                                 for (nodeLevel7 = nodeLevel6->children;
800                                                                 nodeLevel7 != NULL;
801                                                                 nodeLevel7 = nodeLevel7->next)
802                                                                 {
803                                                                 
804                                                                         DefaultAddressBookURI = ((const char*)nodeLevel7->content);
806                                                                 }
807                         
808                                                         }
809                         
810                                                 }
811                         
812                                         }
813                         
814                                 }
815                         
816                         }
817                 
818                 }
819                 
820         }
821         
822         xmlFreeDoc(xmlCardDAVDoc);
823         
824         return DefaultAddressBookURI;
825         
828 COServerResponse CardDAV2::AddContact(std::string Location, std::string Data){
829         
830         // Check if authentication was successful, otherwise don't do anything.
832         COServerResponse ServerResponse;
833         
834         if (AuthPassed == false){
835                 ServerResponse.RequestResult = COREQUEST_ERROR_NOTCONNECTED;
836                 ServerResponse.EntityTag = "";
837                 ServerResponse.SessionCode = 0;
838                 ServerResponse.ResultCode = 0;
839                 ServerResponse.ResultMessage = "";
840                 return ServerResponse;
841         }
843         ServerSSL ? SetupDefaultParametersSSL(true) : SetupDefaultParametersNonSSL(true);
844         ResetResults();
845         
846         string ServerAddressURL = BuildURL(ServerPrefix + Location);
847         curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddressURL.c_str());
848         curl_easy_setopt(ConnectionSession, CURLOPT_CUSTOMREQUEST, "PUT");
849         curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDS, Data.c_str());
850         curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDSIZE, strlen(Data.c_str()));
851         
852         HeaderList = curl_slist_append(HeaderList, "Content-Type: text/vcard; charset=utf-8");
854         curl_easy_setopt(ConnectionSession, CURLOPT_HTTPHEADER, HeaderList);
855         
856         if (TestMode == true){
857                 SessionResult = curl_easy_perform(ConnectionSession);
858         } else {
859                 SessionResult = curl_easy_perform(ConnectionSession);
860         }
861         
862         switch(SessionResult){
863                 case CURLE_OK:
864                         SSLStatus = true;
865                         SSLVerified = COSSL_VERIFIED;
866                         break;
867                 case CURLE_SSL_CACERT:
868                 case CURLE_SSL_CONNECT_ERROR:
869                         SSLStatus = true;
870                         SSLVerified = COSSL_UNABLETOVERIFY;
871                         break;
872                 default:
873                         break;
874         };
875         
876         long SessionResponseCode = 0;
877         
878         curl_easy_getinfo(ConnectionSession, CURLINFO_RESPONSE_CODE, &SessionResponseCode);
879         
880         if (SessionResponseCode == 200 || SessionResponseCode == 201 || SessionResponseCode == 204){
881                 AuthPassed = true;
882                 ValidResponse = true;
883         } else if (SessionResponseCode == 403){
884                 AuthPassed = false;
885                 ValidResponse = true;
886         } else if (SessionResponseCode >= 400){
887                 AuthPassed = false;
888                 ValidResponse = true;
889         } else {
890                 AuthPassed = false;
891                 ValidResponse = false;                  
892         }
893         
894         if (ValidResponse == false || AuthPassed == false){
895                 ServerResponse.RequestResult = COREQUEST_ERROR_SERVER;
896                 ServerResponse.EntityTag = "";
897                 ServerResponse.SessionCode = SessionResult;
898                 ServerResponse.ResultCode = SessionResponseCode;
899                 ServerResponse.ResultMessage = "";
900                 return ServerResponse;
901         }
902         
903         CanProcess = true;
904         
905         ServerResponse.RequestResult = COREQUEST_OK;
906         ServerResponse.EntityTag = "";
907         ServerResponse.SessionCode = SessionResult;
908         ServerResponse.ResultCode = SessionResponseCode;
909         ServerResponse.ResultMessage = SessionErrorBuffer;
910         return ServerResponse;
911         
914 COServerResponse CardDAV2::EditContact(std::string Location, std::string Data){
916         // Check if authentication was successful, otherwise don't do anything.
918         COServerResponse ServerResponse;
919         
920         if (AuthPassed == false){
921                 ServerResponse.RequestResult = COREQUEST_ERROR_NOTCONNECTED;
922                 ServerResponse.EntityTag = "";
923                 ServerResponse.SessionCode = 0;
924                 ServerResponse.ResultCode = 0;
925                 ServerResponse.ResultMessage = "";
926                 return ServerResponse;
927         }
929         ServerSSL ? SetupDefaultParametersSSL(true) : SetupDefaultParametersNonSSL(true);
930         ResetResults();
931         
932         string ServerAddressURL = BuildURL(ServerPrefix + Location);
933         curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddressURL.c_str());
934         curl_easy_setopt(ConnectionSession, CURLOPT_CUSTOMREQUEST, "PUT");
935         curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDS, Data.c_str());
936         curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDSIZE, strlen(Data.c_str()));
937         
938         HeaderList = curl_slist_append(HeaderList, "Content-Type: text/vcard; charset=utf-8");
940         curl_easy_setopt(ConnectionSession, CURLOPT_HTTPHEADER, HeaderList);
941         
942         if (TestMode == true){
943                 SessionResult = curl_easy_perform(ConnectionSession);
944         } else {
945                 SessionResult = curl_easy_perform(ConnectionSession);
946         }
947         
948         switch(SessionResult){
949                 case CURLE_OK:
950                         SSLStatus = true;
951                         SSLVerified = COSSL_VERIFIED;
952                         break;
953                 case CURLE_SSL_CACERT:
954                 case CURLE_SSL_CONNECT_ERROR:
955                         SSLStatus = true;
956                         SSLVerified = COSSL_UNABLETOVERIFY;
957                         break;
958                 default:
959                         break;
960         };
961         
962         long SessionResponseCode = 0;
963         
964         curl_easy_getinfo(ConnectionSession, CURLINFO_RESPONSE_CODE, &SessionResponseCode);
965         
966         if (SessionResponseCode == 200 || SessionResponseCode == 201 || SessionResponseCode == 204){
967                 AuthPassed = true;
968                 ValidResponse = true;
969         } else if (SessionResponseCode == 403){
970                 AuthPassed = false;
971                 ValidResponse = true;
972         } else if (SessionResponseCode >= 400){
973                 AuthPassed = false;
974                 ValidResponse = true;
975         } else {
976                 AuthPassed = false;
977                 ValidResponse = false;                  
978         }
979         
980         if (ValidResponse == false || AuthPassed == false){
981                 ServerResponse.RequestResult = COREQUEST_ERROR_SERVER;
982                 ServerResponse.EntityTag = "";
983                 ServerResponse.SessionCode = SessionResult;
984                 ServerResponse.ResultCode = SessionResponseCode;
985                 ServerResponse.ResultMessage = "";
986                 return ServerResponse;
987         }
988         
989         CanProcess = true;
990         
991         ServerResponse.RequestResult = COREQUEST_OK;
992         ServerResponse.EntityTag = "";
993         ServerResponse.SessionCode = SessionResult;
994         ServerResponse.ResultCode = SessionResponseCode;
995         ServerResponse.ResultMessage = SessionErrorBuffer;
996         return ServerResponse;
997         
1000 COServerResponse CardDAV2::DeleteContact(std::string Location){
1001         
1002         // Check if authentication was successful, otherwise don't do anything.
1004         COServerResponse ServerResponse;
1005         
1006         if (AuthPassed == false){
1007                 ServerResponse.RequestResult = COREQUEST_ERROR_NOTCONNECTED;
1008                 ServerResponse.EntityTag = "";
1009                 ServerResponse.SessionCode = 0;
1010                 ServerResponse.ResultCode = 0;
1011                 ServerResponse.ResultMessage = "";
1012                 return ServerResponse;
1013         }
1015         ServerSSL ? SetupDefaultParametersSSL(true) : SetupDefaultParametersNonSSL(true);
1016         ResetResults();
1017         
1018         string ServerAddressURL = BuildURL(ServerPrefix + Location);
1019         curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddressURL.c_str());
1020         curl_easy_setopt(ConnectionSession, CURLOPT_CUSTOMREQUEST, "DELETE");
1021         
1022         if (TestMode == true){
1023                 SessionResult = curl_easy_perform(ConnectionSession);
1024         } else {
1025                 SessionResult = curl_easy_perform(ConnectionSession);
1026         }
1027         
1028         switch(SessionResult){
1029                 case CURLE_OK:
1030                         SSLStatus = true;
1031                         SSLVerified = COSSL_VERIFIED;
1032                         break;
1033                 case CURLE_SSL_CACERT:
1034                 case CURLE_SSL_CONNECT_ERROR:
1035                         SSLStatus = true;
1036                         SSLVerified = COSSL_UNABLETOVERIFY;
1037                         break;
1038                 default:
1039                         break;
1040         };
1041         
1042         long SessionResponseCode = 0;
1043         
1044         curl_easy_getinfo(ConnectionSession, CURLINFO_RESPONSE_CODE, &SessionResponseCode);
1045         
1046         if (SessionResponseCode == 200 || SessionResponseCode == 202 || SessionResponseCode == 204){
1047                 AuthPassed = true;
1048                 ValidResponse = true;
1049         } else if (SessionResponseCode == 403){
1050                 AuthPassed = false;
1051                 ValidResponse = true;
1052         } else if (SessionResponseCode >= 400){
1053                 AuthPassed = false;
1054                 ValidResponse = true;
1055         } else {
1056                 AuthPassed = false;
1057                 ValidResponse = false;                  
1058         }
1059         
1060         if (ValidResponse == false || AuthPassed == false){
1061                 ServerResponse.RequestResult = COREQUEST_ERROR_SERVER;
1062                 ServerResponse.EntityTag = "";
1063                 ServerResponse.SessionCode = SessionResult;
1064                 ServerResponse.ResultCode = SessionResponseCode;
1065                 ServerResponse.ResultMessage = "";
1066                 return ServerResponse;
1067         }
1068         
1069         CanProcess = true;
1070         
1071         ServerResponse.RequestResult = COREQUEST_OK;
1072         ServerResponse.EntityTag = "";
1073         ServerResponse.SessionCode = SessionResult;
1074         ServerResponse.ResultCode = SessionResponseCode;
1075         ServerResponse.ResultMessage = SessionErrorBuffer;
1076         return ServerResponse;
1077         
1080 COServerResponse CardDAV2::GetServerEntityTagValue(std::string Location){
1081         
1082         // Check if authentication was successful, otherwise don't do anything.
1084         COServerResponse ServerResponse;
1085         
1086         if (AuthPassed == false){
1087                 ServerResponse.RequestResult = COREQUEST_ERROR_NOTCONNECTED;
1088                 ServerResponse.EntityTag = "";
1089                 ServerResponse.SessionCode = 0;
1090                 ServerResponse.ResultCode = 0;
1091                 ServerResponse.ResultMessage = "";
1092                 return ServerResponse;
1093         }
1095         ServerSSL ? SetupDefaultParametersSSL(true) : SetupDefaultParametersNonSSL(true);
1096         ResetResults();
1097         
1098         static const char* GetETagQuery =
1099         "<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
1100         "<C:addressbook-query xmlns:D=\"DAV:\""
1101         "       xmlns:C=\"urn:ietf:params:xml:ns:carddav\">"
1102         "<D:prop><D:getetag/>"
1103         "</D:prop>"
1104         "<C:filter/>"
1105         "</C:addressbook-query>";
1106         
1107         string ServerAddressURL = BuildURL(ServerPrefix + Location);
1108         curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddressURL.c_str());
1109         curl_easy_setopt(ConnectionSession, CURLOPT_CUSTOMREQUEST, "REPORT");
1110         curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDS, GetETagQuery);
1111         curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDSIZE, strlen(GetETagQuery));
1112         
1113         if (TestMode == true){
1114                 SessionResult = curl_easy_perform(ConnectionSession);
1115         } else {
1116                 SessionResult = curl_easy_perform(ConnectionSession);
1117         }
1118         
1119         switch(SessionResult){
1120                 case CURLE_OK:
1121                         SSLStatus = true;
1122                         SSLVerified = COSSL_VERIFIED;
1123                         break;
1124                 case CURLE_SSL_CACERT:
1125                 case CURLE_SSL_CONNECT_ERROR:
1126                         SSLStatus = true;
1127                         SSLVerified = COSSL_UNABLETOVERIFY;
1128                         break;
1129                 default:
1130                         break;
1131         };
1132         
1133         long SessionResponseCode = 0;
1134         
1135         curl_easy_getinfo(ConnectionSession, CURLINFO_RESPONSE_CODE, &SessionResponseCode);
1136         
1137         if (SessionResponseCode == 207){
1138                 AuthPassed = true;
1139                 ValidResponse = true;
1140         } else if (SessionResponseCode == 403){
1141                 AuthPassed = false;
1142                 ValidResponse = true;
1143         } else if (SessionResponseCode >= 400){
1144                 AuthPassed = false;
1145                 ValidResponse = true;
1146         } else {
1147                 AuthPassed = false;
1148                 ValidResponse = false;                  
1149         }
1150         
1151         if (ValidResponse == false || AuthPassed == false){
1152                 ServerResponse.RequestResult = COREQUEST_ERROR_SERVER;
1153                 ServerResponse.EntityTag = "";
1154                 ServerResponse.SessionCode = SessionResult;
1155                 ServerResponse.ResultCode = SessionResponseCode;
1156                 ServerResponse.ResultMessage = "";
1157                 return ServerResponse;
1158         }
1159         
1160         CanProcess = true;
1161         
1162         ServerResponse.RequestResult = COREQUEST_OK;
1163         ServerResponse.EntityTag = GetETagValue();
1164         ServerResponse.SessionCode = SessionResult;
1165         ServerResponse.ResultCode = SessionResponseCode;
1166         ServerResponse.ResultMessage = SessionErrorBuffer;
1167         
1168         return ServerResponse;
1169         
1172 COServerResponse CardDAV2::GetContact(std::string Location, std::string *ContactData){
1173         
1174         // Check if authentication was successful, otherwise don't do anything.
1176         COServerResponse ServerResponse;
1177         
1178         if (AuthPassed == false){
1179                 ServerResponse.RequestResult = COREQUEST_ERROR_NOTCONNECTED;
1180                 ServerResponse.EntityTag = "";
1181                 ServerResponse.SessionCode = 0;
1182                 ServerResponse.ResultCode = 0;
1183                 ServerResponse.ResultMessage = "";
1184                 return ServerResponse;
1185         }
1187         ServerSSL ? SetupDefaultParametersSSL(true) : SetupDefaultParametersNonSSL(true);
1188         ResetResults();
1189         
1190         string ServerAddressURL = BuildURL(ServerPrefix + Location);
1191         curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddressURL.c_str());
1192         curl_easy_setopt(ConnectionSession, CURLOPT_CUSTOMREQUEST, "GET");
1193         
1194         if (TestMode == true){
1195                 SessionResult = curl_easy_perform(ConnectionSession);
1196         } else {
1197                 SessionResult = curl_easy_perform(ConnectionSession);
1198         }
1199         
1200         switch(SessionResult){
1201                 case CURLE_OK:
1202                         SSLStatus = true;
1203                         SSLVerified = COSSL_VERIFIED;
1204                         break;
1205                 case CURLE_SSL_CACERT:
1206                 case CURLE_SSL_CONNECT_ERROR:
1207                         SSLStatus = true;
1208                         SSLVerified = COSSL_UNABLETOVERIFY;
1209                         break;
1210                 default:
1211                         break;
1212         };
1213         
1214         long SessionResponseCode = 0;
1215         
1216         curl_easy_getinfo(ConnectionSession, CURLINFO_RESPONSE_CODE, &SessionResponseCode);
1217         
1218         if (SessionResponseCode == 200){
1219                 AuthPassed = true;
1220                 ValidResponse = true;
1221         } else if (SessionResponseCode == 403){
1222                 AuthPassed = false;
1223                 ValidResponse = true;
1224         } else if (SessionResponseCode >= 400){
1225                 AuthPassed = false;
1226                 ValidResponse = true;
1227         } else {
1228                 AuthPassed = false;
1229                 ValidResponse = false;                  
1230         }
1231         
1232         if (ValidResponse == false && AuthPassed == false){
1233                 ServerResponse.RequestResult = COREQUEST_ERROR_SERVER;
1234                 ServerResponse.EntityTag = "";
1235                 ServerResponse.SessionCode = SessionResult;
1236                 ServerResponse.ResultCode = SessionResponseCode;
1237                 ServerResponse.ResultMessage = "";
1238                 return ServerResponse;
1239         }
1240         
1241         CanProcess = true;
1242         
1243         ServerResponse.RequestResult = COREQUEST_OK;
1244         ServerResponse.EntityTag = "";
1245         ServerResponse.SessionCode = SessionResult;
1246         ServerResponse.ResultCode = SessionResponseCode;
1247         ServerResponse.ResultMessage = SessionErrorBuffer;
1248         
1249         (*ContactData) = PageData;
1250         
1251         return ServerResponse;
1252         
1255 COContactList CardDAV2::GetContactList(std::string SyncToken){
1256         
1257         COContactList ServerContactList;
1258         
1259         // Check if authentication was successful, otherwise don't do anything.
1260         
1261         if (AuthPassed == false){
1262                 ServerContactList.ServerResponse.RequestResult = COREQUEST_ERROR_NOTCONNECTED;
1263                 ServerContactList.ServerResponse.EntityTag = "";
1264                 ServerContactList.ServerResponse.SessionCode = 0;
1265                 ServerContactList.ServerResponse.ResultCode = 0;
1266                 ServerContactList.ServerResponse.ResultMessage = "";
1267                 return ServerContactList;
1268         }
1270         ServerSSL ? SetupDefaultParametersSSL(true) : SetupDefaultParametersNonSSL(true);
1271         ResetResults();
1272         
1273         std::string SyncData;
1274         
1275         // TODO: Copy old code from CardDAV class as needed.
1276         
1277         if (SyncToken.size() > 0){
1278                 
1279                 SyncData = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"
1280                 "<D:sync-collection xmlns:D=\"DAV:\"\n"
1281                 " xmlns:C=\"urn:ietf:params:xml:ns:carddav\">\n"
1282                 "<D:sync-token>";
1283                 SyncData.append(SyncToken);
1284                 SyncData.append("</D:sync-token>\n"
1285                 "<D:sync-level>1</D:sync-level>\n"
1286                 "<D:prop>\n"
1287                 "       <D:getetag/>\n"
1288                 "</D:prop>\n"
1289                 "</D:sync-collection>");
1290         
1291         } else {
1292                 
1293                 SyncData = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"
1294                 "<D:sync-collection xmlns:D=\"DAV:\"\n"
1295                 " xmlns:C=\"urn:ietf:params:xml:ns:carddav\">\n"
1296                 "<D:sync-level>1</D:sync-level>\n"
1297                 "<D:prop>\n"
1298                 "       <D:getetag/>\n"
1299                 "</D:prop>\n"
1300                 "</D:sync-collection>";
1302         }
1303         
1304         string ServerAddressURL = BuildURL(ServerPrefix);
1305         
1306         curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddressURL.c_str());
1307         curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDS, SyncData.c_str());
1308         curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDSIZE, strlen(SyncData.c_str()));
1309         curl_easy_setopt(ConnectionSession, CURLOPT_CUSTOMREQUEST, "REPORT");
1310         
1311         HeaderList = curl_slist_append(HeaderList, "Content-Type: application/xml; charset=utf-8");
1312         HeaderList = curl_slist_append(HeaderList, "Depth: 1");
1314         curl_easy_setopt(ConnectionSession, CURLOPT_HTTPHEADER, HeaderList);
1315         
1316         if (TestMode == true){
1317                 SessionResult = curl_easy_perform(ConnectionSession);
1318         } else {
1319                 SessionResult = curl_easy_perform(ConnectionSession);
1320         }
1321         
1322         switch(SessionResult){
1323                 case CURLE_OK:
1324                         SSLStatus = true;
1325                         SSLVerified = COSSL_VERIFIED;
1326                         break;
1327                 case CURLE_SSL_CACERT:
1328                 case CURLE_SSL_CONNECT_ERROR:
1329                         SSLStatus = true;
1330                         SSLVerified = COSSL_UNABLETOVERIFY;
1331                         break;
1332                 default:
1333                         break;
1334         };
1335         
1336         long SessionResponseCode = 0;
1337         
1338         curl_easy_getinfo(ConnectionSession, CURLINFO_RESPONSE_CODE, &SessionResponseCode);
1339         
1340         if (SessionResponseCode == 207){
1341                 AuthPassed = true;
1342                 ValidResponse = true;
1343         } else if (SessionResponseCode == 403){
1344                 AuthPassed = false;
1345                 ValidResponse = true;
1346         } else if (SessionResponseCode >= 400){
1347                 AuthPassed = false;
1348                 ValidResponse = true;
1349         } else {
1350                 AuthPassed = false;
1351                 ValidResponse = false;                  
1352         }
1353         
1354         if (ValidResponse == false || AuthPassed == false){
1355                 ServerContactList.ServerResponse.RequestResult = COREQUEST_ERROR_SERVER;
1356                 ServerContactList.ServerResponse.EntityTag = "";
1357                 ServerContactList.ServerResponse.SessionCode = SessionResult;
1358                 ServerContactList.ServerResponse.ResultCode = SessionResponseCode;
1359                 ServerContactList.ServerResponse.ResultMessage = "";
1360                 return ServerContactList;
1361         }
1362         
1363         CanProcess = true;
1364         
1365         ProcessContactData(&ServerContactList);
1366         
1367         ServerContactList.ServerResponse.RequestResult = COREQUEST_OK;
1368         ServerContactList.ServerResponse.EntityTag = "";
1369         ServerContactList.ServerResponse.SessionCode = SessionResult;
1370         ServerContactList.ServerResponse.ResultCode = SessionResponseCode;
1371         ServerContactList.ServerResponse.ResultMessage = SessionErrorBuffer;
1372         
1373         return ServerContactList;
1374         
1376         
1377 bool CardDAV2::CanDoProcessing(){
1378         return CanProcess;
1381 bool CardDAV2::CanDoSSL(){
1382         return SSLStatus;
1385 COSSLVerified CardDAV2::SSLVerify(){
1386         return SSLVerified;
1389 bool CardDAV2::AbleToLogin(){
1390         return AuthPassed;
1393 bool CardDAV2::HasValidResponse(){
1394         return ValidResponse;
1397 bool CardDAV2::IsSelfSigned(){
1398         return SSLSelfSigned;
1401 void CardDAV2::SetupDefaultParametersNonSSL(bool DoAuthentication){
1402         
1403         std::string ServerAddress = "";
1405         string ServerAddressURL = "http://" + ServerAddress + ":" + to_string(ServerPort) + "/";
1406         string UsernamePassword = ServerUser + ":" + ServerPass;
1408         PageDataObject.CardDAV2Object = this;
1409         PageDataObject.ConnectionSessionObject = ConnectionSession;
1410         PageDataObject.DataSetting = &PageData;
1411         PageDataObject.ServerUsingSSL = false;
1413         PageHeaderObject.CardDAV2Object = this;
1414         PageHeaderObject.ConnectionSessionObject = ConnectionSession;
1415         PageHeaderObject.DataSetting = &PageHeader;
1416         PageHeaderObject.ServerUsingSSL = false;
1417         
1418         curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddress.c_str());
1419         curl_easy_setopt(ConnectionSession, CURLOPT_NOPROGRESS, 1L);
1420         curl_easy_setopt(ConnectionSession, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST|CURLAUTH_BASIC);
1421         curl_easy_setopt(ConnectionSession, CURLOPT_TIMEOUT, 60);
1422         curl_easy_setopt(ConnectionSession, CURLOPT_FAILONERROR, true);
1423         curl_easy_setopt(ConnectionSession, CURLOPT_USERAGENT, XSDAB_USERAGENT);
1424         curl_easy_setopt(ConnectionSession, CURLOPT_WRITEFUNCTION, CardDAV2::WritebackFunc);
1425         curl_easy_setopt(ConnectionSession, CURLOPT_WRITEDATA, &PageDataObject);
1426         curl_easy_setopt(ConnectionSession, CURLOPT_WRITEHEADER, &PageHeaderObject);
1427         curl_easy_setopt(ConnectionSession, CURLOPT_NOSIGNAL, 1L);
1428         curl_easy_setopt(ConnectionSession, CURLOPT_CUSTOMREQUEST, "GET");
1429         curl_easy_setopt(ConnectionSession, CURLOPT_HTTPHEADER, nullptr);
1430         curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDS, nullptr);
1431         curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDSIZE, 0L);
1433         if (DoAuthentication == true){
1434                 curl_easy_setopt(ConnectionSession, CURLOPT_USERPWD, UsernamePassword.c_str());
1435         } else {
1436                 curl_easy_setopt(ConnectionSession, CURLOPT_USERPWD, NULL);             
1437         }
1438         
1441 void CardDAV2::SetupDefaultParametersSSL(bool DoAuthentication){
1442         
1443         // Setup the default parameters.
1444         
1445         string ServerAddressURL = "https://" + ServerAddress + ":" + to_string(ServerPort) + "/";
1446         string UsernamePassword = ServerUser + ":" + ServerPass;
1448         PageDataObject.CardDAV2Object = this;
1449         PageDataObject.ConnectionSessionObject = ConnectionSession;
1450         PageDataObject.DataSetting = &PageData;
1451         PageDataObject.ServerUsingSSL = true;
1453         PageHeaderObject.CardDAV2Object = this;
1454         PageHeaderObject.ConnectionSessionObject = ConnectionSession;
1455         PageHeaderObject.DataSetting = &PageHeader;
1456         PageHeaderObject.ServerUsingSSL = true;
1457         
1458         curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddressURL.c_str());
1459         curl_easy_setopt(ConnectionSession, CURLOPT_NOPROGRESS, 1L);
1460         curl_easy_setopt(ConnectionSession, CURLOPT_CERTINFO, 1L);
1461         curl_easy_setopt(ConnectionSession, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST|CURLAUTH_BASIC);
1462         curl_easy_setopt(ConnectionSession, CURLOPT_TIMEOUT, 60);
1463         curl_easy_setopt(ConnectionSession, CURLOPT_FAILONERROR, 0L);
1464         curl_easy_setopt(ConnectionSession, CURLOPT_USERAGENT, XSDAB_USERAGENT);
1465         curl_easy_setopt(ConnectionSession, CURLOPT_WRITEFUNCTION, CardDAV2::WritebackFunc);
1466         curl_easy_setopt(ConnectionSession, CURLOPT_WRITEDATA, &PageDataObject);
1467         curl_easy_setopt(ConnectionSession, CURLOPT_WRITEHEADER, &PageHeaderObject);
1468         curl_easy_setopt(ConnectionSession, CURLOPT_ERRORBUFFER, SessionErrorBuffer);
1469         curl_easy_setopt(ConnectionSession, CURLOPT_CUSTOMREQUEST, "GET");
1470         curl_easy_setopt(ConnectionSession, CURLOPT_HTTPHEADER, nullptr);
1471         curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDS, nullptr);
1472         curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDSIZE, 0L);
1474         if (DoAuthentication == true){
1475                 curl_easy_setopt(ConnectionSession, CURLOPT_USERPWD, UsernamePassword.c_str());
1476         } else {
1477                 curl_easy_setopt(ConnectionSession, CURLOPT_USERPWD, NULL);             
1478         }
1479         
1480         if (EnableSSLBypass == true){
1481                 curl_easy_setopt(ConnectionSession, CURLOPT_SSL_VERIFYHOST, 0L);
1482                 curl_easy_setopt(ConnectionSession, CURLOPT_SSL_VERIFYPEER, 0L);
1483                 curl_easy_setopt(ConnectionSession, CURLOPT_SSL_VERIFYSTATUS, 0L);
1484         } else {
1485                 curl_easy_setopt(ConnectionSession, CURLOPT_SSL_VERIFYHOST, 2L);
1486                 curl_easy_setopt(ConnectionSession, CURLOPT_SSL_VERIFYPEER, 1L);
1487                 curl_easy_setopt(ConnectionSession, CURLOPT_SSL_VERIFYSTATUS, 1L);
1488         }
1489         
1490 #if !defined(__APPLE__) || defined(__WIN32__)
1491         
1492         if (TestMode == false && ServerAccount.size() > 0){
1493                 
1494                 // Check if the server certificate file exists.
1495                 
1496                 string CertificateFilename = GetAccountDir(ServerAccount, true);
1497                 
1498                 if (wxFile::Exists(CertificateFilename)){
1499                         
1500                         curl_easy_setopt(ConnectionSession, CURLOPT_CAINFO, CertificateFilename.c_str());
1501                         
1502                 }
1503                 
1504         }
1506 #endif
1507         
1510 string CardDAV2::BuildURL(string URI){
1511         
1512         string ServerAddressURL;
1513         
1514         if (ServerSSL == true){
1515                 ServerAddressURL = "https://" + ServerAddress + ":" + to_string(ServerPort) + URI;      
1516         } else {
1517                 ServerAddressURL = "http://" + ServerAddress + ":" + to_string(ServerPort) + URI;
1518         }
1519         
1520         return ServerAddressURL;
1521         
1524 string CardDAV2::GetErrorMessage(){
1525         
1526         ErrorMessage = SessionErrorBuffer;      
1527         return ErrorMessage;
1528         
1531 void CardDAV2::ResetResults(){
1532         
1533         SSLStatus = false;
1534         COSSLVerified SSLVerified = COSSL_NORESULT;
1535         ValidResponse = false;
1536         AuthPassed = false;
1537         CanProcess = false;
1538         SSLSelfSigned = false;
1539         TaskCompleted = false;
1540         ErrorMessage = "";
1541         SessionErrorBuffer[0] = '\0';
1542         SessionResult = CURLE_OK;
1543         PageData = "";
1544         PageHeader = "";
1545         if (HeaderList != nullptr){
1546                 curl_slist_free_all(HeaderList);
1547                 HeaderList = nullptr;
1548         }
1549         
1552 string CardDAV2::GetETagValue(){
1553         
1554         xmlDocPtr xmlCardDAVDoc;
1556         xmlCardDAVDoc = xmlReadMemory(PageData.c_str(), (int)PageData.size(), "noname.xml", NULL, 0);
1558         xmlNodePtr nodeLevel1;
1559         xmlNodePtr nodeLevel2;
1560         xmlNodePtr nodeLevel3;
1561         xmlNodePtr nodeLevel4;
1562         xmlNodePtr nodeLevel5;
1563         xmlNodePtr nodeLevel6;
1565         //std::map<wxString,wxString> xmlDataMap;
1567         std::string DataFilename;
1568         std::string ETagData;
1570         std::string xmlStringSafe;
1571         std::string ETagValue;
1573         // Tranverse through the catacombs of the response to get our ETag for the file.
1575         for (nodeLevel1 = xmlCardDAVDoc->children;
1576                 nodeLevel1 != NULL;
1577                 nodeLevel1 = nodeLevel1->next)
1578         {
1580                 bool HREFFound = FALSE;
1581                 bool ETagFound = FALSE;
1583                 for (nodeLevel2 = nodeLevel1->children;
1584                         nodeLevel2 != NULL;
1585                         nodeLevel2 = nodeLevel2->next)
1586                 {
1588                         for (nodeLevel3 = nodeLevel2->children;
1589                         nodeLevel3 != NULL;
1590                         nodeLevel3 = nodeLevel3->next)
1591                         {
1593                                 if (!xmlStrcmp(nodeLevel3->name, (const xmlChar *)"href") ||
1594                                 !xmlStrcmp(nodeLevel3->name, (const xmlChar *)"d:href") ||
1595                                 !xmlStrcmp(nodeLevel3->name, (const xmlChar *)"D:href")
1596                                 ){
1598                                         // Get the filename.
1599                                         
1600                                         for (nodeLevel4 = nodeLevel3->children;
1601                                         nodeLevel4 != NULL;
1602                                         nodeLevel4 = nodeLevel4->next)
1603                                         {
1604                                         
1605                                                 if (!xmlStrcmp(nodeLevel4->name, (const xmlChar *)"text") ||
1606                                                 !xmlStrcmp(nodeLevel4->name, (const xmlChar *)"d:text") ||
1607                                                 !xmlStrcmp(nodeLevel4->name, (const xmlChar *)"D:text")
1608                                                 ){
1610                                                         DataFilename = wxString::FromUTF8((const char*)nodeLevel4->content);
1611                                                         wxStringTokenizer wSTDFilename(DataFilename, wxT("/"));
1612                                                 
1613                                                         while (wSTDFilename.HasMoreTokens()){
1614                                                         
1615                                                                 DataFilename = wSTDFilename.GetNextToken().ToStdString();
1616                                                         
1617                                                         }
1618                                                         
1619                                                         HREFFound = TRUE;
1620                                                 
1621                                                 }
1622                                                 
1623         
1624                                         
1625                                         }
1627                                 } else {
1629                                         for (nodeLevel4 = nodeLevel3->children;
1630                                         nodeLevel4 != NULL;
1631                                         nodeLevel4 = nodeLevel4->next)
1632                                         {
1633                                                         
1634                                                         for (nodeLevel5 = nodeLevel4->children;
1635                                                         nodeLevel5 != NULL;
1636                                                         nodeLevel5 = nodeLevel5->next)
1637                                                         {
1639                                                                 if (!xmlStrcmp(nodeLevel5->name, (const xmlChar *)"getetag") ||
1640                                                                 !xmlStrcmp(nodeLevel5->name, (const xmlChar *)"d:getetag") ||
1641                                                                 !xmlStrcmp(nodeLevel5->name, (const xmlChar *)"D:getetag")
1642                                                                 ){
1644                                                                         for (nodeLevel6 = nodeLevel5->children;
1645                                                                         nodeLevel6 != NULL;
1646                                                                         nodeLevel6 = nodeLevel6->next)
1647                                                                         {
1648                                                         
1649                                                                                 // Strip the quotes from the ETag.
1650                                                         
1651                                                                                 ETagData = (const char*)nodeLevel6->content;
1652                                                                                 if (ETagData[0] == '"' && ETagData[(ETagData.size() - 1)] == '"'){
1653                                                         
1654                                                                                         ETagData.erase(0, 1);
1655                                                                                         ETagData.erase((ETagData.size() - 1));
1656                                                         
1657                                                                                 }
1658                                                                         
1659                                                                                 ETagFound = TRUE;
1661                                                                         }
1662                                                                         
1663                                                                 }
1665                                                         }       
1667                                         }
1669                                 }
1671                         }
1673                 }
1674                 
1675                 if (HREFFound == TRUE && ETagFound == TRUE){
1676                                 
1677                         // Add to the map data.
1678                                 
1679                         ETagValue = ETagData;
1680                         
1681                         HREFFound = FALSE;
1682                         ETagFound = FALSE;
1683                         break;
1684                                 
1685                 }
1688         }
1690         xmlFreeDoc(xmlCardDAVDoc);
1691         
1692         return ETagValue;
1693         
1696 string CardDAV2::GetETagHeader(){
1697         
1698         // Go through each of the lines looking for the
1699         // 'DAV:' section.
1700         
1701         string HeaderName;
1702         string HeaderValue;
1703         bool FastForward = false;
1704         
1705         for (int HeaderSeek = 0; HeaderSeek < PageHeader.size(); HeaderSeek++){
1706                 
1707                 if (FastForward == true){
1708                         
1709                         if (PageHeader[HeaderSeek] == '\n'){
1710                                 FastForward = false;
1711                         }
1712                         
1713                         continue;
1714                         
1715                 }
1716                 
1717                 try {
1718                         PageHeader.substr(HeaderSeek, 5) == "ETag:";
1719                 }
1720                 
1721                 catch (const out_of_range &oor){
1722                         break;
1723                 }
1724                 
1725                 if (PageHeader.substr(HeaderSeek, 5) == "ETag:"){
1726                         
1727                         int CharacterSeek = 5;
1728                         
1729                         while ((HeaderSeek + CharacterSeek) < PageHeader.size()){
1730                                 
1731                                 if (PageHeader.substr((HeaderSeek + CharacterSeek), 2) == "\r\n"){
1732                                         break;
1733                                 }
1734                                 
1735                                 HeaderValue += PageHeader.substr((HeaderSeek + CharacterSeek), 1);
1736                                 CharacterSeek++;
1737                         }
1738                         
1739                         break;
1740                         
1741                 } else {
1742                         
1743                         FastForward = true;
1744                         continue;
1745                         
1746                 }
1747                 
1748                 if (PageHeader[HeaderSeek] == '\n'){
1749                         HeaderName = "";
1750                 }
1751                 
1752                 //HeaderName += PageHeader.substr(HeaderSeek, 1);
1753                 
1754         }
1755         
1756         // Check for quotation marks at the start and end and strip
1757         // them out.
1758         
1759         if (HeaderValue.size() >= 2){
1760                 
1761                 if (HeaderValue[0] == '"'){
1762                         HeaderValue.erase((HeaderValue.size() - 1));
1763                         HeaderValue.erase(0);
1764                 }
1765                 
1766         }
1767         
1768         return HeaderValue;
1769         
1772 vector<string> CardDAV2::GetDAVHeader(){
1773         
1774         // Go through each of the lines looking for the
1775         // 'DAV:' section.
1776         
1777         string HeaderName;
1778         string HeaderValue;
1779         bool FastForward = false;
1780         vector<string> DAVHeaderList;
1781         
1782         for (int HeaderSeek = 0; HeaderSeek < PageHeader.size(); HeaderSeek++){
1783                 
1784                 if (FastForward == true){
1785                         
1786                         if (PageHeader[HeaderSeek] == '\n'){
1787                                 FastForward = false;
1788                         }
1789                         
1790                         continue;
1791                         
1792                 }
1793                 
1794                 try {
1795                         PageHeader.substr(HeaderSeek, 4) == "DAV:";
1796                 }
1797                 
1798                 catch (const out_of_range &oor){
1799                         break;
1800                 }
1801                 
1802                 if (PageHeader.substr(HeaderSeek, 4) == "DAV:"){
1803                         
1804                         int CharacterSeek = 5;
1805                         
1806                         while ((HeaderSeek + CharacterSeek) < PageHeader.size()){
1807                                 
1808                                 if (PageHeader.substr((HeaderSeek + CharacterSeek), 2) == "\r\n"){
1809                                         break;
1810                                 }
1811                                 
1812                                 HeaderValue += PageHeader.substr((HeaderSeek + CharacterSeek), 1);
1813                                 CharacterSeek++;
1814                         }
1815                         
1816                         break;
1817                         
1818                 } else {
1819                         
1820                         FastForward = true;
1821                         continue;
1822                         
1823                 }
1824                 
1825                 if (PageHeader[HeaderSeek] == '\n'){
1826                         HeaderName = "";
1827                 }
1828                 
1829                 //HeaderName += PageHeader.substr(HeaderSeek, 1);
1830                 
1831         }
1832         
1833         // Split the header data.
1834         
1835         std::string DAVHeaderValue;
1836         
1837         for (int HeaderSeek = 0; HeaderSeek < HeaderValue.size(); HeaderSeek++){
1838                 
1839                 if (HeaderValue.substr(HeaderSeek, 1) == ","){
1840                         DAVHeaderList.push_back(DAVHeaderValue);
1841                         DAVHeaderValue = "";
1842                         HeaderSeek++;
1843                         continue;
1844                 }
1845                 
1846                 DAVHeaderValue += HeaderValue[HeaderSeek];
1847                 
1848         }
1849         
1850         if (DAVHeaderValue.size() > 0){
1851                 
1852                 DAVHeaderList.push_back(DAVHeaderValue);
1853                 
1854         }
1855         
1856         return DAVHeaderList;
1857         
1860 void CardDAV2::ProcessContactData(COContactList *ContactList){
1861         
1862         xmlDocPtr xmlCardDAVDoc;
1863         xmlCardDAVDoc = xmlReadMemory(PageData.c_str(), (int)PageData.size(), "noname.xml", NULL, 0);
1865         xmlNodePtr MultiStatusNode;
1866         xmlNodePtr ResponseNode;
1867         xmlNodePtr ResponseDataNode;
1868         xmlNodePtr PropStatNode;
1869         xmlNodePtr ValueNode;
1870         xmlNodePtr ETagNode;
1871         xmlNodePtr StatusNode;
1873         std::string HREFValue;
1874         std::string ETagValue;
1875         std::string StatusValue;
1876         std::string SyncValue;
1878         // Go through the document!
1880         MultiStatusNode = xmlCardDAVDoc->children;
1882         if (MultiStatusNode == nullptr){
1883                 return;
1884         }
1886         bool SyncTokenFound = false;
1888         // Tranverse through the catacombs of the response to get our ETag for the file and
1889         // the server syncronisation token.
1890         
1891         for (ResponseNode = MultiStatusNode->children;
1892                 ResponseNode != nullptr;
1893                 ResponseNode = ResponseNode->next){
1895                 // Check if tag is response or sync-token.
1897                 if (!xmlStrcmp(ResponseNode->name, (const xmlChar *)"response") ||
1898                 !xmlStrcmp(ResponseNode->name, (const xmlChar *)"d:response") ||
1899                 !xmlStrcmp(ResponseNode->name, (const xmlChar *)"D:response")){
1901                         COContactStatus ContactStatus = COCS_UNKNOWN;
1902                         
1903                         for (ResponseDataNode = ResponseNode->children;
1904                                 ResponseDataNode != nullptr;
1905                                 ResponseDataNode = ResponseDataNode->next){
1907                                 if (!xmlStrcmp(ResponseDataNode->name, (const xmlChar *)"href") ||
1908                                 !xmlStrcmp(ResponseDataNode->name, (const xmlChar *)"d:href") ||
1909                                 !xmlStrcmp(ResponseDataNode->name, (const xmlChar *)"D:href")){
1910                                 
1911                                         HREFValue = (const char*)ResponseDataNode->children->content;
1913                                         // Get the filename after the last forward slash.
1914                                         
1915                                         int LastSlash = 0;
1916                                         
1917                                         for (int HREFValueSeek = 0; HREFValueSeek < HREFValue.size(); HREFValueSeek++){
1918                                                 
1919                                                 if (HREFValue[HREFValueSeek] == '/'){
1920                                                 
1921                                                         LastSlash = HREFValueSeek;
1922                                                         
1923                                                 }
1924                                                 
1925                                         }
1926                                         
1927                                         HREFValue = HREFValue.substr((LastSlash + 1));
1928                                         
1929                                 } else if (!xmlStrcmp(ResponseDataNode->name, (const xmlChar *)"propstat") ||
1930                                 !xmlStrcmp(ResponseDataNode->name, (const xmlChar *)"d:propstat") ||
1931                                 !xmlStrcmp(ResponseDataNode->name, (const xmlChar *)"D:propstat")){
1933                                         for (PropStatNode = ResponseDataNode->children;
1934                                                 PropStatNode != nullptr;
1935                                                 PropStatNode = PropStatNode->next){
1937                                                 if (!xmlStrcmp(PropStatNode->name, (const xmlChar *)"prop") ||
1938                                                         !xmlStrcmp(PropStatNode->name, (const xmlChar *)"d:prop") ||
1939                                                         !xmlStrcmp(PropStatNode->name, (const xmlChar *)"D:prop")){
1941                                                         for (ETagNode = PropStatNode->children;
1942                                                                 ETagNode != nullptr;
1943                                                                 ETagNode = ETagNode->next){
1945                                                                         if (!xmlStrcmp(ETagNode->name, (const xmlChar *)"getetag") ||
1946                                                                         !xmlStrcmp(ETagNode->name, (const xmlChar *)"getetag") ||
1947                                                                         !xmlStrcmp(ETagNode->name, (const xmlChar *)"getetag")){
1949                                                                                 ETagValue = (const char*)ETagNode->children->content;
1951                                                                                 if (ETagValue.size() > 2 && ETagValue.substr(0,1) == "\""){
1952                                                                                         ETagValue.erase((ETagValue.size() - 1),1);
1953                                                                                         ETagValue.erase(0,1);
1954                                                                                 }
1956                                                                         }
1957                                                         
1959                                                         }
1961                                                 } else if (!xmlStrcmp(PropStatNode->name, (const xmlChar *)"status") ||
1962                                                         !xmlStrcmp(PropStatNode->name, (const xmlChar *)"d:status") ||
1963                                                         !xmlStrcmp(PropStatNode->name, (const xmlChar *)"D:status")){
1965                                                         StatusValue = (const char*)PropStatNode->children->content;
1967                                                         if (StatusValue == "HTTP/1.1 200 OK"){
1969                                                                 ContactStatus = COCS_UPDATED;
1971                                                         } else if (StatusValue == "HTTP/1.1 404 Not Found"){
1973                                                                 ContactStatus = COCS_DELETED;
1975                                                         } else {
1977                                                                 ContactStatus = COCS_UNKNOWN;
1979                                                         }
1981                                                 }
1983                                         }
1985                                 }
1987                         }
1989                         COContactData ContactInformation;
1990                         
1991                         ContactInformation.Location = HREFValue;
1992                         ContactInformation.Data = ETagValue;
1993                         ContactInformation.Status = ContactStatus;
1995                         HREFValue.clear();
1996                         ETagValue.clear();
1997                         StatusValue.clear();
1998                         
1999                         ContactList->ListData.push_back(ContactInformation);
2001                 } else if (!xmlStrcmp(ResponseNode->name, (const xmlChar *)"sync-token") ||
2002                         !xmlStrcmp(ResponseNode->name, (const xmlChar *)"d:sync-token") ||
2003                         !xmlStrcmp(ResponseNode->name, (const xmlChar *)"D:sync-token")){
2005                         SyncValue = (const char*)ResponseNode->children->content;
2007                 }
2009         }
2011         ContactList->SyncToken = SyncValue;
2013         xmlFreeDoc(xmlCardDAVDoc);
2015         return;
2016         
Xestia Software Development
Yn Maystri
© 2006 - 2019 Xestia Software Development
Software

Xestia Address Book
Xestia Calendar
Development

Xestia Gelforn
Everything else

About
News
Privacy Policy