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