Home | News | Projects | Releases
Bugs | RFE | Repositories | Help
Updated CardDAV2/ConnectionObject implementation
[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 #include <iostream>
23 using namespace std;
25 CardDAV2::CardDAV2(string ServerAddress, int ServerPort, string ServerUser, string ServerPass, bool ServerSSL){
27         this->ServerAddress = ServerAddress;
28         this->ServerPort = ServerPort;
29         this->ServerUser = ServerUser;
30         this->ServerPass = ServerPass;
31         this->ServerSSL = ServerSSL;
33         TestMode = true;
34         this->SetupConnectionObject();
36 }
38 CardDAV2::CardDAV2(string ServerAddress, int ServerPort, string ServerUser, string ServerPass, bool ServerSSL, string ServerPrefix, string ServerAccount){
40         this->ServerAddress = ServerAddress;
41         this->ServerPort = ServerPort;
42         this->ServerUser = ServerUser;
43         this->ServerPass = ServerPass;
44         this->ServerSSL = ServerSSL;
45         this->ServerPrefix = ServerPrefix;
46         this->ServerAccount = ServerAccount;
49         TestMode = false;
50         this->SetupConnectionObject();
52 }
54 size_t CardDAV2::WritebackFunc(char *ptr, size_t size, size_t nmemb, void *stream){
56         return static_cast<CardDAV2PassObject*>(stream)->CardDAV2Object->WritebackFuncImplementation(ptr, size, nmemb, stream);
57         
58 }
60 size_t CardDAV2::WritebackFuncImplementation(char *ptr, size_t size, size_t nmemb, void *stream){
61         
62         // Writeback function for the CardDAV object.
63                 
64         CardDAV2PassObject *data = static_cast<CardDAV2PassObject*>(stream);
65         data->DataSetting->append(ptr);
66         
67         // Get the SSL engine pointer and trust if required on certain operating systems.
69         if (data->ServerUsingSSL == true) {
71 #if defined(__APPLE__)
73                 const struct curl_tlssessioninfo *TLSInfo;
74                 CURLcode TLSCode;
75                 TLSCode = curl_easy_getinfo(data->ConnectionSessionObject, CURLINFO_TLS_SSL_PTR, &TLSInfo);
77                 SecTrustRef CertificateData;
78                 
79                 if (TLSInfo->internals != nullptr && TLSCode == CURLE_OK) {
80                         SSLCopyPeerTrust((SSLContext*)TLSInfo->internals, &CertificateData);
81                         data->SSLContext = CertificateData;
82                 }
84 #elif defined(__WIN32__)
86                 const struct curl_tlssessioninfo *TLSInfo;
87                 CURLcode TLSCode;
88                 TLSCode = curl_easy_getinfo(data->ConnectionSessionObject, CURLINFO_TLS_SSL_PTR, &TLSInfo);
90                 if (TLSInfo->internals != nullptr && TLSCode == CURLE_OK) {
92                         // Free the previous certificate data.
94                         //CertFreeCertificateContext(CertificateData);
96                         PCCERT_CONTEXT CertificateData;
98                         PCtxtHandle SSLHandle = (PCtxtHandle)TLSInfo->internals;
99                         SECURITY_STATUS GetData = QueryContextAttributes(SSLHandle, SECPKG_ATTR_REMOTE_CERT_CONTEXT, &CertificateData);
101                         data->SSLContext = CertificateData;
103                 }
105 #endif
107         }
109         return size * nmemb;
113 void CardDAV2::SetCertificateData() {
117 CardDAV2::~CardDAV2(){
118         
119         curl_easy_cleanup(ConnectionSession);
120         ConnectionSession = nullptr;
121         
122         if (HeaderList != nullptr){
123                 curl_slist_free_all(HeaderList);
124                 HeaderList = nullptr;
125         }
127 #if defined(__WIN32__)
129         if (CertificateData != nullptr) {
131                 CertFreeCertificateContext(CertificateData);
133         }
135 #endif
136         
139 #if defined(__APPLE__)
141 SecTrustRef CardDAV2::BuildSSLCollection(){
142         
143         return CertificateData;
144         
147 #elif defined(__WIN32__)
149 PCCERT_CONTEXT CardDAV2::BuildSSLCollection(){
151         return CertificateData;
155 #else
157 SSLCertCollectionString CardDAV2::BuildSSLCollection(){
159         // Build and return the SSL collection.
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         curl_easy_getinfo(ConnectionSession, CURLINFO_CERTINFO, &certptr.certinfo);
174         std::string CertPropName;
175         std::string CertPropValue;
177         for (int i = 0; i < certptr.certinfo->num_of_certs; i++){
179                 struct curl_slist *slist;
180                 SSLCertDataString SSLCertDataInc;
181                 
182                 for (slist = certptr.certinfo->certinfo[i]; slist; slist = slist->next){
183                         
184                         // Using wxStringTokenizer from wxWidgets.
185                         
186                         wxStringTokenizer CertDataInc(wxString::FromUTF8(slist->data), ":");
187                         
188                         // Get first token as the property name.
189                         
190                         CertPropName = CertDataInc.GetNextToken().ToStdString();
191                         
192                         // Get remaining tokens as the property value.
193                         
194                         while(CertDataInc.HasMoreTokens()){
195                         
196                                 CertPropValue.append(CertDataInc.GetNextToken());
197                         
198                         }
199                         
200                         SSLCertDataInc.CertData.insert(std::make_pair(CertPropName, CertPropValue));
201                         CertPropName.clear();
202                         CertPropValue.clear();
203                         
204                 }
205         
206                 SSLCertInfo.SSLCollection.insert(std::make_pair(i, SSLCertDataInc));
207         
208         }
209         
210         return SSLCertInfo;
214 #endif
216 void CardDAV2::BypassSSLVerification(bool EnableBypass) {
217         EnableSSLBypass = EnableBypass;
218         SSLSelfSigned = EnableBypass;
221 void CardDAV2::SetupConnectionObject(){
222         ConnectionSession = curl_easy_init();
225 bool CardDAV2::IsTaskCompleted(){
226         return false;
229 COConnectResult CardDAV2::Connect(bool DoAuthentication){
230         
231         ServerSSL ? SetupDefaultParametersSSL(DoAuthentication) : SetupDefaultParametersNonSSL(DoAuthentication);
232         ResetResults();
233         
234         COConnectResult ConnectResult = COCONNECT_UNITTESTFAIL;
235         string ServerAddressURL = BuildURL("/principals/");
237         curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddressURL.c_str());
238         
239         if (TestMode == true){
240                 SessionResult = curl_easy_perform(ConnectionSession);
241         } else {
242                 SessionResult = curl_easy_perform(ConnectionSession);           
243         }
245         switch(SessionResult){
246                 case CURLE_OK:
247                 case CURLE_HTTP_RETURNED_ERROR:
248                         SSLStatus = true;
249                         SSLVerified = COSSL_VERIFIED;
250                         ConnectResult = COCONNECT_OK;
251                         break;
252                 case CURLE_SSL_CACERT:
253                 case CURLE_SSL_CONNECT_ERROR:
254                         SSLStatus = true;
255                         ConnectResult = COCONNECT_OK;
256                         SSLVerified = COSSL_UNABLETOVERIFY;
257                         break;
258                 default:
259                         ConnectResult = COCONNECT_INVALID;
260                         break;
261         };
262         
263         // Set the certificate data (if required).
265 #if defined(__APPLE__)
266         
267         if (ServerSSL) {
268                 
269                 CertificateData = PageHeaderObject.SSLContext;
270                 
271         }
272         
273 #elif defined(__WIN32__)
275         if (ServerSSL) {
277                 CertificateData = PageHeaderObject.SSLContext;
279         }
281 #endif
283         // Check if an error occured before continuing.
284         
285         // Check if authentication was successful.
286         
287         long SessionResponseCode = 0;
288         
289         curl_easy_getinfo(ConnectionSession, CURLINFO_RESPONSE_CODE, &SessionResponseCode);
290         
291         if (DoAuthentication == true){
292                 
293                 // Get the HTTP status code (Should be 200 and not 403).
294                 // Return error otherwise.
295                 
296                 if (SessionResponseCode == 200){
297                         ConnectResult = COCONNECT_OK;
298                         AuthPassed = true;
299                         ValidResponse = true;
300                 } else if (SessionResponseCode == 401){
301                         ConnectResult = COCONNECT_AUTHFAIL;
302                         AuthPassed = false;
303                         ValidResponse = true;
304                 } else if (SessionResponseCode >= 200) {
305                         ConnectResult = COCONNECT_INVALID;
306                         AuthPassed = false;
307                         ValidResponse = true;
308                 } else {
309                         ConnectResult = COCONNECT_INVALID;
310                         AuthPassed = false;
311                         ValidResponse = false;                  
312                 }
313                 
314         } else {
315                 
316                 ValidResponse = true;
317                 
318         }
319         
320         // Check the header to see if CardDAV is supported.
321         
322         vector<string> DAVHeaderValues = GetDAVHeader();
323         
324         for (vector<string>::iterator DAVHeaderValuesIter = DAVHeaderValues.begin();
325                 DAVHeaderValuesIter != DAVHeaderValues.end(); DAVHeaderValuesIter++){
326                 
327                 if ((*DAVHeaderValuesIter) == "addressbook"){
328                         CanProcess = true;
329                         break;
330                 }
331                         
332         }
333         
334         return ConnectResult;
335         
338 COServerResponse CardDAV2::GetDefaultPrefix(string *ServerPrefix){
340         // Check if authentication was successful, otherwise don't do anything.
342         COServerResponse ServerResponse;
343         
344         if (AuthPassed == false){
345                 ServerResponse.RequestResult = COREQUEST_ERROR_NOTCONNECTED;
346                 ServerResponse.EntityTag = "";
347                 ServerResponse.SessionCode = 0;
348                 ServerResponse.ResultCode = 0;
349                 ServerResponse.ResultMessage = "";
350                 return ServerResponse;
351         }
353         ServerSSL ? SetupDefaultParametersSSL(true) : SetupDefaultParametersNonSSL(true);
354         ResetResults();
355         
356         // Need to do three requests:
357         
358         // 1. Get the current user principal URI.
359         // 2. Get the address book home URI.
360         // 3. Get the default address book URI.
361         
362         // Setup the first query finding out where the principal URL is.
363         
364         const char* CurrentUserPrincipalXMLQuery = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"
365                 "<D:propfind xmlns:D=\"DAV:\">\n"
366                 " <D:prop>"
367                 "  <D:current-user-principal/>\n"
368                 " </D:prop>"
369                 "</D:propfind>";
371         // Setup the second query finding out where the address book home URL is.
372         
373         const char* AddressBookHomeXMLQuery = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"
374         "<D:propfind xmlns:D=\"DAV:\""
375         "  xmlns:C=\"urn:ietf:params:xml:ns:carddav\">\n"
376         "  <D:prop>\n"
377         "    <C:addressbook-home-set/>\n"
378         "  </D:prop>\n"
379         "</D:propfind>";
380         
381         // Setup the third query finding out where the default address book URL is.
382         
383         const char* DefaultAddressBookXMLQuery = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"
384         "<D:propfind xmlns:D=\"DAV:\""
385         "  xmlns:C=\"urn:ietf:params:xml:ns:carddav\">\n"
386         "  <D:prop>\n"
387         "    <C:default-addressbook-URL/>\n"    
388         "  </D:prop>\n"
389         "</D:propfind>";
390         
391         string ServerAddressURL = BuildURL("/principals/");
392         curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddressURL.c_str());
393         curl_easy_setopt(ConnectionSession, CURLOPT_CUSTOMREQUEST, "PROPFIND");
394         curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDS, CurrentUserPrincipalXMLQuery);
395         curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDSIZE, strlen(CurrentUserPrincipalXMLQuery));
396         
397         if (TestMode == true){
398                 SessionResult = curl_easy_perform(ConnectionSession);
399         } else {
400                 
401         }
402         
403         switch(SessionResult){
404                 case CURLE_OK:
405                         SSLStatus = true;
406                         SSLVerified = COSSL_VERIFIED;
407                         break;
408                 case CURLE_SSL_CACERT:
409                 case CURLE_SSL_CONNECT_ERROR:
410                         SSLStatus = true;
411                         SSLVerified = COSSL_UNABLETOVERIFY;
412                         break;
413                 default:
414                         break;
415         };
416         
417         long SessionResponseCode = 0;
418         
419         curl_easy_getinfo(ConnectionSession, CURLINFO_RESPONSE_CODE, &SessionResponseCode);
420         
421         if (SessionResponseCode == 200 || SessionResponseCode == 207){
422                 AuthPassed = true;
423                 ValidResponse = true;
424         } else if (SessionResponseCode == 403){
425                 AuthPassed = false;
426                 ValidResponse = true;
427         } else if (SessionResponseCode >= 400) {
428                 AuthPassed = false;
429                 ValidResponse = true;
430         } else {
431                 AuthPassed = false;
432                 ValidResponse = false;                  
433         }
434         
435         if (ValidResponse == false && AuthPassed == false){
436                 ServerResponse.RequestResult = COREQUEST_ERROR_SERVER;
437                 ServerResponse.EntityTag = "";
438                 ServerResponse.SessionCode = SessionResult;
439                 ServerResponse.ResultCode = SessionResponseCode;
440                 ServerResponse.ResultMessage = "";
441                 return ServerResponse;
442         }
443         
444         // Process the first response.
445         
446         string UserPrincipalURI = GetUserPrincipalURI();
447         
448         // Cleanup and reset for the second connection.
449         
450         ServerSSL ? SetupDefaultParametersSSL(true) : SetupDefaultParametersNonSSL(true);
451         ResetResults();
453         ServerAddressURL = BuildURL(UserPrincipalURI);
454         curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddressURL.c_str());
455         curl_easy_setopt(ConnectionSession, CURLOPT_CUSTOMREQUEST, "PROPFIND");
456         curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDS, AddressBookHomeXMLQuery);
457         curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDSIZE, strlen(AddressBookHomeXMLQuery));
458         
459         if (TestMode == true){
460                 SessionResult = curl_easy_perform(ConnectionSession);
461         } else {
462                 
463         }
464         
465         switch(SessionResult){
466                 case CURLE_OK:
467                         SSLStatus = true;
468                         SSLVerified = COSSL_VERIFIED;
469                         break;
470                 case CURLE_SSL_CACERT:
471                 case CURLE_SSL_CONNECT_ERROR:
472                         SSLStatus = true;
473                         SSLVerified = COSSL_UNABLETOVERIFY;
474                         break;
475                 default:
476                         break;
477         };
478         
479         SessionResponseCode = 0;
480         
481         curl_easy_getinfo(ConnectionSession, CURLINFO_RESPONSE_CODE, &SessionResponseCode);
482         
483         if (SessionResponseCode == 200 || SessionResponseCode == 207){
484                 AuthPassed = true;
485                 ValidResponse = true;
486         } else if (SessionResponseCode == 403){
487                 AuthPassed = false;
488                 ValidResponse = true;
489         } else if (SessionResponseCode >= 400) {
490                 AuthPassed = false;
491                 ValidResponse = true;
492         } else {
493                 AuthPassed = false;
494                 ValidResponse = false;                  
495         }
496         
497         if (ValidResponse == false && AuthPassed == false){
498                 ServerResponse.RequestResult = COREQUEST_ERROR_SERVER;
499                 ServerResponse.EntityTag = "";
500                 ServerResponse.SessionCode = SessionResult;
501                 ServerResponse.ResultCode = SessionResponseCode;
502                 ServerResponse.ResultMessage = "";
503                 return ServerResponse;
504         }
505         
506         // Process the second response.
507         
508         string AddressBookHomeURI = GetAddressBookHomeURI();
509         
510         // Cleanup and reset for the second connection.
511         
512         ServerSSL ? SetupDefaultParametersSSL(true) : SetupDefaultParametersNonSSL(true);
513         ResetResults();
514         
515         ServerAddressURL = BuildURL(AddressBookHomeURI);
516         curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddressURL.c_str());
517         curl_easy_setopt(ConnectionSession, CURLOPT_CUSTOMREQUEST, "PROPFIND");
518         curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDS, DefaultAddressBookXMLQuery);
519         curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDSIZE, strlen(DefaultAddressBookXMLQuery));
520         
521         if (TestMode == true){
522                 SessionResult = curl_easy_perform(ConnectionSession);
523         } else {
524                 
525         }
526         
527         switch(SessionResult){
528                 case CURLE_OK:
529                         SSLStatus = true;
530                         SSLVerified = COSSL_VERIFIED;
531                         break;
532                 case CURLE_SSL_CACERT:
533                 case CURLE_SSL_CONNECT_ERROR:
534                         SSLStatus = true;
535                         SSLVerified = COSSL_UNABLETOVERIFY;
536                         break;
537                 default:
538                         break;
539         };
540         
541         SessionResponseCode = 0;
542         
543         curl_easy_getinfo(ConnectionSession, CURLINFO_RESPONSE_CODE, &SessionResponseCode);
544         
545         if (SessionResponseCode == 200 || SessionResponseCode == 207){
546                 AuthPassed = true;
547                 ValidResponse = true;
548         } else if (SessionResponseCode == 403){
549                 AuthPassed = false;
550                 ValidResponse = true;
551         } else if (SessionResponseCode >= 200) {
552                 AuthPassed = false;
553                 ValidResponse = true;
554         } else {
555                 AuthPassed = false;
556                 ValidResponse = false;                  
557         }
558         
559         if (ValidResponse == false || AuthPassed == false){
560                 ServerResponse.RequestResult = COREQUEST_ERROR_SERVER;
561                 ServerResponse.EntityTag = "";
562                 ServerResponse.SessionCode = SessionResult;
563                 ServerResponse.ResultCode = SessionResponseCode;
564                 ServerResponse.ResultMessage = "";
565                 return ServerResponse;
566         }
567         
568         // Process the second response.
569         
570         (*ServerPrefix) = GetDefaultAddressBookURI();
571         
572         CanProcess = true;
573         
574         ServerResponse.RequestResult = COREQUEST_OK;
575         ServerResponse.EntityTag = "";
576         ServerResponse.SessionCode = SessionResult;
577         ServerResponse.ResultCode = SessionResponseCode;
578         ServerResponse.ResultMessage = SessionErrorBuffer;
579         return ServerResponse;
580         
583 std::string CardDAV2::GetUserPrincipalURI(){
584         
585         xmlDocPtr xmlCardDAVDoc;
586         xmlCardDAVDoc = xmlReadMemory(PageData.c_str(), (int)PageData.size(), "noname.xml", NULL, 0);
587         string UserPrincipalURI = "";
588         
589         xmlNodePtr nodeLevel1;
590         xmlNodePtr nodeLevel2;
591         xmlNodePtr nodeLevel3;
592         xmlNodePtr nodeLevel4;
593         xmlNodePtr nodeLevel5;
594         xmlNodePtr nodeLevel6;
595         xmlNodePtr nodeLevel7;
596                 
597         for (nodeLevel1 = xmlCardDAVDoc->children;
598                 nodeLevel1 != NULL;
599                 nodeLevel1 = nodeLevel1->next)
600         {
602                 for (nodeLevel2 = nodeLevel1->children;
603                         nodeLevel2 != NULL;
604                         nodeLevel2 = nodeLevel2->next)
605                 {
608                         for (nodeLevel3 = nodeLevel2->children;
609                         nodeLevel3 != NULL;
610                         nodeLevel3 = nodeLevel3->next)
611                         {
612                         
613                                 for (nodeLevel4 = nodeLevel3->children;
614                                 nodeLevel4 != NULL;
615                                 nodeLevel4 = nodeLevel4->next)
616                                 {
617                         
618                                         for (nodeLevel5 = nodeLevel4->children;
619                                         nodeLevel5 != NULL;
620                                         nodeLevel5 = nodeLevel5->next)
621                                         {
622                         
623                                                 for (nodeLevel6 = nodeLevel5->children;
624                                                 nodeLevel6 != NULL;
625                                                 nodeLevel6 = nodeLevel6->next)
626                                                 {
627                         
628                                                         if (!xmlStrcmp(nodeLevel6->name, (const xmlChar *)"href") ||
629                                                         !xmlStrcmp(nodeLevel6->name, (const xmlChar *)"d:href") ||
630                                                         !xmlStrcmp(nodeLevel6->name, (const xmlChar *)"D:href")
631                                                         ){
632                         
633                                                                 // Found the <href> part so extract the principal URL address.
634                                                                 
635                                                                 for (nodeLevel7 = nodeLevel6->children;
636                                                                 nodeLevel7 != NULL;
637                                                                 nodeLevel7 = nodeLevel7->next)
638                                                                 {
639                                                                 
640                                                                         UserPrincipalURI = ((const char*)nodeLevel7->content);
642                                                                 }
643                         
644                                                         }
645                         
646                                                 }
647                         
648                                         }
649                         
650                                 }
651                         
652                         }
653                 
654                 }
655                 
656         }
657         
658         xmlFreeDoc(xmlCardDAVDoc);
659         
660         return UserPrincipalURI;
661         
664 std::string CardDAV2::GetAddressBookHomeURI(){
665         
666         xmlDocPtr xmlCardDAVDoc;
667         xmlCardDAVDoc = xmlReadMemory(PageData.c_str(), (int)PageData.size(), "noname.xml", NULL, 0);
668         string AddressBookHomeURI = "";
669         
670         xmlNodePtr nodeLevel1;
671         xmlNodePtr nodeLevel2;
672         xmlNodePtr nodeLevel3;
673         xmlNodePtr nodeLevel4;
674         xmlNodePtr nodeLevel5;
675         xmlNodePtr nodeLevel6;
676         xmlNodePtr nodeLevel7;
677                 
678         for (nodeLevel1 = xmlCardDAVDoc->children;
679                 nodeLevel1 != NULL;
680                 nodeLevel1 = nodeLevel1->next)
681         {
683                 for (nodeLevel2 = nodeLevel1->children;
684                         nodeLevel2 != NULL;
685                         nodeLevel2 = nodeLevel2->next)
686                 {
689                         for (nodeLevel3 = nodeLevel2->children;
690                         nodeLevel3 != NULL;
691                         nodeLevel3 = nodeLevel3->next)
692                         {
693                         
694                                 for (nodeLevel4 = nodeLevel3->children;
695                                 nodeLevel4 != NULL;
696                                 nodeLevel4 = nodeLevel4->next)
697                                 {
698                         
699                                         for (nodeLevel5 = nodeLevel4->children;
700                                         nodeLevel5 != NULL;
701                                         nodeLevel5 = nodeLevel5->next)
702                                         {
703                         
704                                                 for (nodeLevel6 = nodeLevel5->children;
705                                                 nodeLevel6 != NULL;
706                                                 nodeLevel6 = nodeLevel6->next)
707                                                 {
708                         
709                                                         if (!xmlStrcmp(nodeLevel6->name, (const xmlChar *)"href") ||
710                                                         !xmlStrcmp(nodeLevel6->name, (const xmlChar *)"d:href") ||
711                                                         !xmlStrcmp(nodeLevel6->name, (const xmlChar *)"D:href")
712                                                         ){
713                         
714                                                                 // Found the <href> part so extract the principal URL address.
715                                                                 
716                                                                 for (nodeLevel7 = nodeLevel6->children;
717                                                                 nodeLevel7 != NULL;
718                                                                 nodeLevel7 = nodeLevel7->next)
719                                                                 {
720                                                                 
721                                                                         AddressBookHomeURI = ((const char*)nodeLevel7->content);
723                                                                 }
724                         
725                                                         }
726                         
727                                                 }
728                         
729                                         }
730                         
731                                 }
732                         
733                         }
734                 
735                 }
736                 
737         }
738         
739         xmlFreeDoc(xmlCardDAVDoc);
740         
741         return AddressBookHomeURI;
742         
745 std::string CardDAV2::GetDefaultAddressBookURI(){
746         
747         xmlDocPtr xmlCardDAVDoc;
748         xmlCardDAVDoc = xmlReadMemory(PageData.c_str(), (int)PageData.size(), "noname.xml", NULL, 0);
749         string DefaultAddressBookURI = "";
750         
751         xmlNodePtr nodeLevel1;
752         xmlNodePtr nodeLevel2;
753         xmlNodePtr nodeLevel3;
754         xmlNodePtr nodeLevel4;
755         xmlNodePtr nodeLevel5;
756         xmlNodePtr nodeLevel6;
757         xmlNodePtr nodeLevel7;
758                 
759         for (nodeLevel1 = xmlCardDAVDoc->children;
760                 nodeLevel1 != NULL;
761                 nodeLevel1 = nodeLevel1->next)
762         {
764                 for (nodeLevel2 = nodeLevel1->children;
765                         nodeLevel2 != NULL;
766                         nodeLevel2 = nodeLevel2->next)
767                 {
770                         for (nodeLevel3 = nodeLevel2->children;
771                         nodeLevel3 != NULL;
772                         nodeLevel3 = nodeLevel3->next)
773                         {
774                         
775                                 for (nodeLevel4 = nodeLevel3->children;
776                                 nodeLevel4 != NULL;
777                                 nodeLevel4 = nodeLevel4->next)
778                                 {
779                         
780                                         for (nodeLevel5 = nodeLevel4->children;
781                                         nodeLevel5 != NULL;
782                                         nodeLevel5 = nodeLevel5->next)
783                                         {
784                         
785                                                 for (nodeLevel6 = nodeLevel5->children;
786                                                 nodeLevel6 != NULL;
787                                                 nodeLevel6 = nodeLevel6->next)
788                                                 {
789                         
790                                                         if (!xmlStrcmp(nodeLevel6->name, (const xmlChar *)"href") ||
791                                                         !xmlStrcmp(nodeLevel6->name, (const xmlChar *)"d:href") ||
792                                                         !xmlStrcmp(nodeLevel6->name, (const xmlChar *)"D:href")
793                                                         ){
794                         
795                                                                 // Found the <href> part so extract the principal URL address.
796                                                                 
797                                                                 for (nodeLevel7 = nodeLevel6->children;
798                                                                 nodeLevel7 != NULL;
799                                                                 nodeLevel7 = nodeLevel7->next)
800                                                                 {
801                                                                 
802                                                                         DefaultAddressBookURI = ((const char*)nodeLevel7->content);
804                                                                 }
805                         
806                                                         }
807                         
808                                                 }
809                         
810                                         }
811                         
812                                 }
813                         
814                         }
815                 
816                 }
817                 
818         }
819         
820         xmlFreeDoc(xmlCardDAVDoc);
821         
822         return DefaultAddressBookURI;
823         
826 COServerResponse CardDAV2::AddContact(std::string Location, std::string Data){
827         
828         // Check if authentication was successful, otherwise don't do anything.
830         COServerResponse ServerResponse;
831         
832         if (AuthPassed == false){
833                 ServerResponse.RequestResult = COREQUEST_ERROR_NOTCONNECTED;
834                 ServerResponse.EntityTag = "";
835                 ServerResponse.SessionCode = 0;
836                 ServerResponse.ResultCode = 0;
837                 ServerResponse.ResultMessage = "";
838                 return ServerResponse;
839         }
841         ServerSSL ? SetupDefaultParametersSSL(true) : SetupDefaultParametersNonSSL(true);
842         ResetResults();
843         
844         string ServerAddressURL = BuildURL(ServerPrefix + Location);
845         curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddressURL.c_str());
846         curl_easy_setopt(ConnectionSession, CURLOPT_CUSTOMREQUEST, "PUT");
847         curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDS, Data.c_str());
848         curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDSIZE, strlen(Data.c_str()));
849         
850         HeaderList = curl_slist_append(HeaderList, "Content-Type: text/vcard; charset=utf-8");
852         curl_easy_setopt(ConnectionSession, CURLOPT_HTTPHEADER, HeaderList);
853         
854         if (TestMode == true){
855                 SessionResult = curl_easy_perform(ConnectionSession);
856         } else {
857                 SessionResult = curl_easy_perform(ConnectionSession);
858         }
859         
860         switch(SessionResult){
861                 case CURLE_OK:
862                         SSLStatus = true;
863                         SSLVerified = COSSL_VERIFIED;
864                         break;
865                 case CURLE_SSL_CACERT:
866                 case CURLE_SSL_CONNECT_ERROR:
867                         SSLStatus = true;
868                         SSLVerified = COSSL_UNABLETOVERIFY;
869                         break;
870                 default:
871                         break;
872         };
873         
874         long SessionResponseCode = 0;
875         
876         curl_easy_getinfo(ConnectionSession, CURLINFO_RESPONSE_CODE, &SessionResponseCode);
877         
878         if (SessionResponseCode == 200 || SessionResponseCode == 201 || SessionResponseCode == 204){
879                 AuthPassed = true;
880                 ValidResponse = true;
881         } else if (SessionResponseCode == 403){
882                 AuthPassed = false;
883                 ValidResponse = true;
884         } else if (SessionResponseCode >= 400){
885                 AuthPassed = false;
886                 ValidResponse = true;
887         } else {
888                 AuthPassed = false;
889                 ValidResponse = false;                  
890         }
891         
892         if (ValidResponse == false || AuthPassed == false){
893                 ServerResponse.RequestResult = COREQUEST_ERROR_SERVER;
894                 ServerResponse.EntityTag = "";
895                 ServerResponse.SessionCode = SessionResult;
896                 ServerResponse.ResultCode = SessionResponseCode;
897                 ServerResponse.ResultMessage = "";
898                 return ServerResponse;
899         }
900         
901         CanProcess = true;
902         
903         ServerResponse.RequestResult = COREQUEST_OK;
904         ServerResponse.EntityTag = "";
905         ServerResponse.SessionCode = SessionResult;
906         ServerResponse.ResultCode = SessionResponseCode;
907         ServerResponse.ResultMessage = SessionErrorBuffer;
908         return ServerResponse;
909         
912 COServerResponse CardDAV2::EditContact(std::string Location, std::string Data){
914         // Check if authentication was successful, otherwise don't do anything.
916         COServerResponse ServerResponse;
917         
918         if (AuthPassed == false){
919                 ServerResponse.RequestResult = COREQUEST_ERROR_NOTCONNECTED;
920                 ServerResponse.EntityTag = "";
921                 ServerResponse.SessionCode = 0;
922                 ServerResponse.ResultCode = 0;
923                 ServerResponse.ResultMessage = "";
924                 return ServerResponse;
925         }
927         ServerSSL ? SetupDefaultParametersSSL(true) : SetupDefaultParametersNonSSL(true);
928         ResetResults();
929         
930         string ServerAddressURL = BuildURL(ServerPrefix + Location);
931         curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddressURL.c_str());
932         curl_easy_setopt(ConnectionSession, CURLOPT_CUSTOMREQUEST, "PUT");
933         curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDS, Data.c_str());
934         curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDSIZE, strlen(Data.c_str()));
935         
936         HeaderList = curl_slist_append(HeaderList, "Content-Type: text/vcard; charset=utf-8");
938         curl_easy_setopt(ConnectionSession, CURLOPT_HTTPHEADER, HeaderList);
939         
940         if (TestMode == true){
941                 SessionResult = curl_easy_perform(ConnectionSession);
942         } else {
943                 SessionResult = curl_easy_perform(ConnectionSession);
944         }
945         
946         switch(SessionResult){
947                 case CURLE_OK:
948                         SSLStatus = true;
949                         SSLVerified = COSSL_VERIFIED;
950                         break;
951                 case CURLE_SSL_CACERT:
952                 case CURLE_SSL_CONNECT_ERROR:
953                         SSLStatus = true;
954                         SSLVerified = COSSL_UNABLETOVERIFY;
955                         break;
956                 default:
957                         break;
958         };
959         
960         long SessionResponseCode = 0;
961         
962         curl_easy_getinfo(ConnectionSession, CURLINFO_RESPONSE_CODE, &SessionResponseCode);
963         
964         if (SessionResponseCode == 200 || SessionResponseCode == 201 || SessionResponseCode == 204){
965                 AuthPassed = true;
966                 ValidResponse = true;
967         } else if (SessionResponseCode == 403){
968                 AuthPassed = false;
969                 ValidResponse = true;
970         } else if (SessionResponseCode >= 400){
971                 AuthPassed = false;
972                 ValidResponse = true;
973         } else {
974                 AuthPassed = false;
975                 ValidResponse = false;                  
976         }
977         
978         if (ValidResponse == false || AuthPassed == false){
979                 ServerResponse.RequestResult = COREQUEST_ERROR_SERVER;
980                 ServerResponse.EntityTag = "";
981                 ServerResponse.SessionCode = SessionResult;
982                 ServerResponse.ResultCode = SessionResponseCode;
983                 ServerResponse.ResultMessage = "";
984                 return ServerResponse;
985         }
986         
987         CanProcess = true;
988         
989         ServerResponse.RequestResult = COREQUEST_OK;
990         ServerResponse.EntityTag = "";
991         ServerResponse.SessionCode = SessionResult;
992         ServerResponse.ResultCode = SessionResponseCode;
993         ServerResponse.ResultMessage = SessionErrorBuffer;
994         return ServerResponse;
995         
998 COServerResponse CardDAV2::DeleteContact(std::string Location){
999         
1000         // Check if authentication was successful, otherwise don't do anything.
1002         COServerResponse ServerResponse;
1003         
1004         if (AuthPassed == false){
1005                 ServerResponse.RequestResult = COREQUEST_ERROR_NOTCONNECTED;
1006                 ServerResponse.EntityTag = "";
1007                 ServerResponse.SessionCode = 0;
1008                 ServerResponse.ResultCode = 0;
1009                 ServerResponse.ResultMessage = "";
1010                 return ServerResponse;
1011         }
1013         ServerSSL ? SetupDefaultParametersSSL(true) : SetupDefaultParametersNonSSL(true);
1014         ResetResults();
1015         
1016         string ServerAddressURL = BuildURL(ServerPrefix + Location);
1017         curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddressURL.c_str());
1018         curl_easy_setopt(ConnectionSession, CURLOPT_CUSTOMREQUEST, "DELETE");
1019         
1020         if (TestMode == true){
1021                 SessionResult = curl_easy_perform(ConnectionSession);
1022         } else {
1023                 SessionResult = curl_easy_perform(ConnectionSession);
1024         }
1025         
1026         switch(SessionResult){
1027                 case CURLE_OK:
1028                         SSLStatus = true;
1029                         SSLVerified = COSSL_VERIFIED;
1030                         break;
1031                 case CURLE_SSL_CACERT:
1032                 case CURLE_SSL_CONNECT_ERROR:
1033                         SSLStatus = true;
1034                         SSLVerified = COSSL_UNABLETOVERIFY;
1035                         break;
1036                 default:
1037                         break;
1038         };
1039         
1040         long SessionResponseCode = 0;
1041         
1042         curl_easy_getinfo(ConnectionSession, CURLINFO_RESPONSE_CODE, &SessionResponseCode);
1043         
1044         if (SessionResponseCode == 200 || SessionResponseCode == 202 || SessionResponseCode == 204){
1045                 AuthPassed = true;
1046                 ValidResponse = true;
1047         } else if (SessionResponseCode == 403){
1048                 AuthPassed = false;
1049                 ValidResponse = true;
1050         } else if (SessionResponseCode >= 400){
1051                 AuthPassed = false;
1052                 ValidResponse = true;
1053         } else {
1054                 AuthPassed = false;
1055                 ValidResponse = false;                  
1056         }
1057         
1058         if (ValidResponse == false || AuthPassed == false){
1059                 ServerResponse.RequestResult = COREQUEST_ERROR_SERVER;
1060                 ServerResponse.EntityTag = "";
1061                 ServerResponse.SessionCode = SessionResult;
1062                 ServerResponse.ResultCode = SessionResponseCode;
1063                 ServerResponse.ResultMessage = "";
1064                 return ServerResponse;
1065         }
1066         
1067         CanProcess = true;
1068         
1069         ServerResponse.RequestResult = COREQUEST_OK;
1070         ServerResponse.EntityTag = "";
1071         ServerResponse.SessionCode = SessionResult;
1072         ServerResponse.ResultCode = SessionResponseCode;
1073         ServerResponse.ResultMessage = SessionErrorBuffer;
1074         return ServerResponse;
1075         
1078 COServerResponse CardDAV2::GetServerEntityTagValue(std::string Location){
1079         
1080         // Check if authentication was successful, otherwise don't do anything.
1082         COServerResponse ServerResponse;
1083         
1084         if (AuthPassed == false){
1085                 ServerResponse.RequestResult = COREQUEST_ERROR_NOTCONNECTED;
1086                 ServerResponse.EntityTag = "";
1087                 ServerResponse.SessionCode = 0;
1088                 ServerResponse.ResultCode = 0;
1089                 ServerResponse.ResultMessage = "";
1090                 return ServerResponse;
1091         }
1093         ServerSSL ? SetupDefaultParametersSSL(true) : SetupDefaultParametersNonSSL(true);
1094         ResetResults();
1095         
1096         static const char* GetETagQuery =
1097         "<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
1098         "<C:addressbook-query xmlns:D=\"DAV:\""
1099         "       xmlns:C=\"urn:ietf:params:xml:ns:carddav\">"
1100         "<D:prop><D:getetag/>"
1101         "</D:prop>"
1102         "<C:filter/>"
1103         "</C:addressbook-query>";
1104         
1105         string ServerAddressURL = BuildURL(ServerPrefix + Location);
1106         curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddressURL.c_str());
1107         curl_easy_setopt(ConnectionSession, CURLOPT_CUSTOMREQUEST, "REPORT");
1108         curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDS, GetETagQuery);
1109         curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDSIZE, strlen(GetETagQuery));
1110         
1111         if (TestMode == true){
1112                 SessionResult = curl_easy_perform(ConnectionSession);
1113         } else {
1114                 SessionResult = curl_easy_perform(ConnectionSession);
1115         }
1116         
1117         switch(SessionResult){
1118                 case CURLE_OK:
1119                         SSLStatus = true;
1120                         SSLVerified = COSSL_VERIFIED;
1121                         break;
1122                 case CURLE_SSL_CACERT:
1123                 case CURLE_SSL_CONNECT_ERROR:
1124                         SSLStatus = true;
1125                         SSLVerified = COSSL_UNABLETOVERIFY;
1126                         break;
1127                 default:
1128                         break;
1129         };
1130         
1131         long SessionResponseCode = 0;
1132         
1133         curl_easy_getinfo(ConnectionSession, CURLINFO_RESPONSE_CODE, &SessionResponseCode);
1134         
1135         if (SessionResponseCode == 207){
1136                 AuthPassed = true;
1137                 ValidResponse = true;
1138         } else if (SessionResponseCode == 403){
1139                 AuthPassed = false;
1140                 ValidResponse = true;
1141         } else if (SessionResponseCode >= 400){
1142                 AuthPassed = false;
1143                 ValidResponse = true;
1144         } else {
1145                 AuthPassed = false;
1146                 ValidResponse = false;                  
1147         }
1148         
1149         if (ValidResponse == false || AuthPassed == false){
1150                 ServerResponse.RequestResult = COREQUEST_ERROR_SERVER;
1151                 ServerResponse.EntityTag = "";
1152                 ServerResponse.SessionCode = SessionResult;
1153                 ServerResponse.ResultCode = SessionResponseCode;
1154                 ServerResponse.ResultMessage = "";
1155                 return ServerResponse;
1156         }
1157         
1158         CanProcess = true;
1159         
1160         ServerResponse.RequestResult = COREQUEST_OK;
1161         ServerResponse.EntityTag = GetETagValue();
1162         ServerResponse.SessionCode = SessionResult;
1163         ServerResponse.ResultCode = SessionResponseCode;
1164         ServerResponse.ResultMessage = SessionErrorBuffer;
1165         
1166         return ServerResponse;
1167         
1170 COServerResponse CardDAV2::GetContact(std::string Location, std::string *ContactData){
1171         
1172         // Check if authentication was successful, otherwise don't do anything.
1174         COServerResponse ServerResponse;
1175         
1176         if (AuthPassed == false){
1177                 ServerResponse.RequestResult = COREQUEST_ERROR_NOTCONNECTED;
1178                 ServerResponse.EntityTag = "";
1179                 ServerResponse.SessionCode = 0;
1180                 ServerResponse.ResultCode = 0;
1181                 ServerResponse.ResultMessage = "";
1182                 return ServerResponse;
1183         }
1185         ServerSSL ? SetupDefaultParametersSSL(true) : SetupDefaultParametersNonSSL(true);
1186         ResetResults();
1187         
1188         string ServerAddressURL = BuildURL(ServerPrefix + Location);
1189         curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddressURL.c_str());
1190         curl_easy_setopt(ConnectionSession, CURLOPT_CUSTOMREQUEST, "GET");
1191         
1192         if (TestMode == true){
1193                 SessionResult = curl_easy_perform(ConnectionSession);
1194         } else {
1195                 SessionResult = curl_easy_perform(ConnectionSession);
1196         }
1197         
1198         switch(SessionResult){
1199                 case CURLE_OK:
1200                         SSLStatus = true;
1201                         SSLVerified = COSSL_VERIFIED;
1202                         break;
1203                 case CURLE_SSL_CACERT:
1204                 case CURLE_SSL_CONNECT_ERROR:
1205                         SSLStatus = true;
1206                         SSLVerified = COSSL_UNABLETOVERIFY;
1207                         break;
1208                 default:
1209                         break;
1210         };
1211         
1212         long SessionResponseCode = 0;
1213         
1214         curl_easy_getinfo(ConnectionSession, CURLINFO_RESPONSE_CODE, &SessionResponseCode);
1215         
1216         if (SessionResponseCode == 200){
1217                 AuthPassed = true;
1218                 ValidResponse = true;
1219         } else if (SessionResponseCode == 403){
1220                 AuthPassed = false;
1221                 ValidResponse = true;
1222         } else if (SessionResponseCode >= 400){
1223                 AuthPassed = false;
1224                 ValidResponse = true;
1225         } else {
1226                 AuthPassed = false;
1227                 ValidResponse = false;                  
1228         }
1229         
1230         if (ValidResponse == false && AuthPassed == false){
1231                 ServerResponse.RequestResult = COREQUEST_ERROR_SERVER;
1232                 ServerResponse.EntityTag = "";
1233                 ServerResponse.SessionCode = SessionResult;
1234                 ServerResponse.ResultCode = SessionResponseCode;
1235                 ServerResponse.ResultMessage = "";
1236                 return ServerResponse;
1237         }
1238         
1239         CanProcess = true;
1240         
1241         ServerResponse.RequestResult = COREQUEST_OK;
1242         ServerResponse.EntityTag = "";
1243         ServerResponse.SessionCode = SessionResult;
1244         ServerResponse.ResultCode = SessionResponseCode;
1245         ServerResponse.ResultMessage = SessionErrorBuffer;
1246         
1247         (*ContactData) = PageData;
1248         
1249         return ServerResponse;
1250         
1253 COContactList CardDAV2::GetContactList(std::string SyncToken){
1254         
1255         COContactList ServerContactList;
1256         
1257         // Check if authentication was successful, otherwise don't do anything.
1258         
1259         if (AuthPassed == false){
1260                 ServerContactList.ServerResponse.RequestResult = COREQUEST_ERROR_NOTCONNECTED;
1261                 ServerContactList.ServerResponse.EntityTag = "";
1262                 ServerContactList.ServerResponse.SessionCode = 0;
1263                 ServerContactList.ServerResponse.ResultCode = 0;
1264                 ServerContactList.ServerResponse.ResultMessage = "";
1265                 return ServerContactList;
1266         }
1268         ServerSSL ? SetupDefaultParametersSSL(true) : SetupDefaultParametersNonSSL(true);
1269         ResetResults();
1270         
1271         std::string SyncData;
1272         
1273         // TODO: Copy old code from CardDAV class as needed.
1274         
1275         if (SyncToken.size() > 0){
1276                 
1277                 SyncData = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"
1278                 "<D:sync-collection xmlns:D=\"DAV:\"\n"
1279                 " xmlns:C=\"urn:ietf:params:xml:ns:carddav\">\n"
1280                 "<D:sync-token>";
1281                 SyncData.append(SyncToken);
1282                 SyncData.append("</D:sync-token>\n"
1283                 "<D:sync-level>1</D:sync-level>\n"
1284                 "<D:prop>\n"
1285                 "       <D:getetag/>\n"
1286                 "</D:prop>\n"
1287                 "</D:sync-collection>");
1288         
1289         } else {
1290                 
1291                 SyncData = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"
1292                 "<D:sync-collection xmlns:D=\"DAV:\"\n"
1293                 " xmlns:C=\"urn:ietf:params:xml:ns:carddav\">\n"
1294                 "<D:sync-level>1</D:sync-level>\n"
1295                 "<D:prop>\n"
1296                 "       <D:getetag/>\n"
1297                 "</D:prop>\n"
1298                 "</D:sync-collection>";
1300         }
1301         
1302         string ServerAddressURL = BuildURL(ServerPrefix);
1303         
1304         curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddressURL.c_str());
1305         curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDS, SyncData.c_str());
1306         curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDSIZE, strlen(SyncData.c_str()));
1307         curl_easy_setopt(ConnectionSession, CURLOPT_CUSTOMREQUEST, "REPORT");
1308         
1309         HeaderList = curl_slist_append(HeaderList, "Content-Type: application/xml; charset=utf-8");
1310         HeaderList = curl_slist_append(HeaderList, "Depth: 1");
1312         curl_easy_setopt(ConnectionSession, CURLOPT_HTTPHEADER, HeaderList);
1313         
1314         if (TestMode == true){
1315                 SessionResult = curl_easy_perform(ConnectionSession);
1316         } else {
1317                 SessionResult = curl_easy_perform(ConnectionSession);
1318         }
1319         
1320         switch(SessionResult){
1321                 case CURLE_OK:
1322                         SSLStatus = true;
1323                         SSLVerified = COSSL_VERIFIED;
1324                         break;
1325                 case CURLE_SSL_CACERT:
1326                 case CURLE_SSL_CONNECT_ERROR:
1327                         SSLStatus = true;
1328                         SSLVerified = COSSL_UNABLETOVERIFY;
1329                         break;
1330                 default:
1331                         break;
1332         };
1333         
1334         long SessionResponseCode = 0;
1335         
1336         curl_easy_getinfo(ConnectionSession, CURLINFO_RESPONSE_CODE, &SessionResponseCode);
1337         
1338         if (SessionResponseCode == 207){
1339                 AuthPassed = true;
1340                 ValidResponse = true;
1341         } else if (SessionResponseCode == 403){
1342                 AuthPassed = false;
1343                 ValidResponse = true;
1344         } else if (SessionResponseCode >= 400){
1345                 AuthPassed = false;
1346                 ValidResponse = true;
1347         } else {
1348                 AuthPassed = false;
1349                 ValidResponse = false;                  
1350         }
1351         
1352         if (ValidResponse == false || AuthPassed == false){
1353                 ServerContactList.ServerResponse.RequestResult = COREQUEST_ERROR_SERVER;
1354                 ServerContactList.ServerResponse.EntityTag = "";
1355                 ServerContactList.ServerResponse.SessionCode = SessionResult;
1356                 ServerContactList.ServerResponse.ResultCode = SessionResponseCode;
1357                 ServerContactList.ServerResponse.ResultMessage = "";
1358                 return ServerContactList;
1359         }
1360         
1361         CanProcess = true;
1362         
1363         ProcessContactData(&ServerContactList);
1364         
1365         ServerContactList.ServerResponse.RequestResult = COREQUEST_OK;
1366         ServerContactList.ServerResponse.EntityTag = "";
1367         ServerContactList.ServerResponse.SessionCode = SessionResult;
1368         ServerContactList.ServerResponse.ResultCode = SessionResponseCode;
1369         ServerContactList.ServerResponse.ResultMessage = SessionErrorBuffer;
1370         
1371         return ServerContactList;
1372         
1374         
1375 bool CardDAV2::CanDoProcessing(){
1376         return CanProcess;
1379 bool CardDAV2::CanDoSSL(){
1380         return SSLStatus;
1383 COSSLVerified CardDAV2::SSLVerify(){
1384         return SSLVerified;
1387 bool CardDAV2::AbleToLogin(){
1388         return AuthPassed;
1391 bool CardDAV2::HasValidResponse(){
1392         return ValidResponse;
1395 bool CardDAV2::IsSelfSigned(){
1396         return SSLSelfSigned;
1399 void CardDAV2::SetupDefaultParametersNonSSL(bool DoAuthentication){
1400         
1401         std::string ServerAddress = "";
1403         string ServerAddressURL = "http://" + ServerAddress + ":" + to_string(ServerPort) + "/";
1404         string UsernamePassword = ServerUser + ":" + ServerPass;
1406         PageDataObject.CardDAV2Object = this;
1407         PageDataObject.ConnectionSessionObject = ConnectionSession;
1408         PageDataObject.DataSetting = &PageData;
1409         PageDataObject.ServerUsingSSL = false;
1411         PageHeaderObject.CardDAV2Object = this;
1412         PageHeaderObject.ConnectionSessionObject = ConnectionSession;
1413         PageHeaderObject.DataSetting = &PageHeader;
1414         PageHeaderObject.ServerUsingSSL = false;
1415         
1416         curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddress.c_str());
1417         curl_easy_setopt(ConnectionSession, CURLOPT_NOPROGRESS, 0L);
1418         curl_easy_setopt(ConnectionSession, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST|CURLAUTH_BASIC);
1419         curl_easy_setopt(ConnectionSession, CURLOPT_TIMEOUT, 60);
1420         curl_easy_setopt(ConnectionSession, CURLOPT_FAILONERROR, true);
1421         curl_easy_setopt(ConnectionSession, CURLOPT_USERAGENT, XSDAB_USERAGENT);
1422         curl_easy_setopt(ConnectionSession, CURLOPT_WRITEFUNCTION, CardDAV2::WritebackFunc);
1423         curl_easy_setopt(ConnectionSession, CURLOPT_WRITEDATA, &PageDataObject);
1424         curl_easy_setopt(ConnectionSession, CURLOPT_WRITEHEADER, &PageHeaderObject);
1425         curl_easy_setopt(ConnectionSession, CURLOPT_NOSIGNAL, 1L);
1426         curl_easy_setopt(ConnectionSession, CURLOPT_CUSTOMREQUEST, "GET");
1427         curl_easy_setopt(ConnectionSession, CURLOPT_HTTPHEADER, nullptr);
1428         curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDS, nullptr);
1429         curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDSIZE, 0L);
1431         if (DoAuthentication == true){
1432                 curl_easy_setopt(ConnectionSession, CURLOPT_USERPWD, UsernamePassword.c_str());
1433         } else {
1434                 curl_easy_setopt(ConnectionSession, CURLOPT_USERPWD, NULL);             
1435         }
1436         
1439 void CardDAV2::SetupDefaultParametersSSL(bool DoAuthentication){
1440         
1441         // Setup the default parameters.
1442         
1443         string ServerAddressURL = "https://" + ServerAddress + ":" + to_string(ServerPort) + "/";
1444         string UsernamePassword = ServerUser + ":" + ServerPass;
1446         PageDataObject.CardDAV2Object = this;
1447         PageDataObject.ConnectionSessionObject = ConnectionSession;
1448         PageDataObject.DataSetting = &PageData;
1449         PageDataObject.ServerUsingSSL = true;
1451         PageHeaderObject.CardDAV2Object = this;
1452         PageHeaderObject.ConnectionSessionObject = ConnectionSession;
1453         PageHeaderObject.DataSetting = &PageHeader;
1454         PageHeaderObject.ServerUsingSSL = true;
1455         
1456         curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddressURL.c_str());
1457         curl_easy_setopt(ConnectionSession, CURLOPT_NOPROGRESS, 1L);
1458         curl_easy_setopt(ConnectionSession, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST|CURLAUTH_BASIC);
1459         curl_easy_setopt(ConnectionSession, CURLOPT_TIMEOUT, 60);
1460         curl_easy_setopt(ConnectionSession, CURLOPT_FAILONERROR, 0L);
1461         curl_easy_setopt(ConnectionSession, CURLOPT_USERAGENT, XSDAB_USERAGENT);
1462         curl_easy_setopt(ConnectionSession, CURLOPT_WRITEFUNCTION, CardDAV2::WritebackFunc);
1463         curl_easy_setopt(ConnectionSession, CURLOPT_WRITEDATA, &PageDataObject);
1464         curl_easy_setopt(ConnectionSession, CURLOPT_WRITEHEADER, &PageHeaderObject);
1465         curl_easy_setopt(ConnectionSession, CURLOPT_ERRORBUFFER, SessionErrorBuffer);
1466         curl_easy_setopt(ConnectionSession, CURLOPT_NOSIGNAL, 1L);
1467         curl_easy_setopt(ConnectionSession, CURLOPT_CERTINFO, 1L);
1468         curl_easy_setopt(ConnectionSession, CURLOPT_VERBOSE, 2L);
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 (SSLStatus == true){
1515                 ServerAddressURL = "https://" + ServerAddress + ":" + to_string(ServerPort) + URI;      
1516         } else {
1517                 ServerAddressURL = "https://" + 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