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