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