Home | News | Projects | Releases
Bugs | RFE | Repositories | Help
Get etag value after adding a contact using the ConnectionObject interface
[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 size_t CardDAV2::WritebackFunc(char *ptr, size_t size, size_t nmemb, void *stream){
26         
27         return static_cast<CardDAV2*>(stream)->WritebackFuncImplementation(ptr, size, nmemb, stream);
28         
29 }
30         
31 size_t CardDAV2::WritebackFuncImplementation(char *ptr, size_t size, size_t nmemb, void *stream){
32         
33         // Writeback function for the CardDAV object.
34                 
35         string *data = static_cast<string*>(stream);
36         data->append(ptr);
37         
38         // Get the SSL engine pointer and trust if required on certain operating systems.
39         
40         if (ServerSSL){
41         
42 #if defined(__APPLE__)
43         
44                 const struct curl_tlssessioninfo *TLSInfo;
45                 CURLcode TLSCode;
46                 CURL *Connection = GetConnectionObject();
47                 TLSCode = curl_easy_getinfo(Connection, CURLINFO_TLS_SSL_PTR, &TLSInfo);
48         
49                 if (TLSInfo->internals != nullptr && TLSCode == CURLE_OK){
50                         SSLCopyPeerTrust((SSLContext*)TLSInfo->internals, &SecTrustObject);
51                 }
52         
53 #elif defined(__WIN32__)
55                 const struct curl_tlssessioninfo *TLSInfo;
56                 CURLcode TLSCode;
57                 CURL *Connection = GetConnectionObject();
58                 TLSCode = curl_easy_getinfo(Connection, CURLINFO_TLS_SSL_PTR, &TLSInfo);
60                 if (TLSInfo->internals != nullptr && TLSCode == CURLE_OK){
62                         // Free the previous certificate data.
64                         CertFreeCertificateContext(CertificateData);
66                         PCtxtHandle SSLHandle = (PCtxtHandle)TLSInfo->internals;
67                         SECURITY_STATUS GetData = QueryContextAttributes(SSLHandle, SECPKG_ATTR_REMOTE_CERT_CONTEXT, &CertificateData);
69                 }
71 #endif
73         }
74         
75         return size * nmemb;
77 }
79 CardDAV2::~CardDAV2(){
80         
81         curl_easy_cleanup(ConnectionSession);
82         ConnectionSession = nullptr;
83         
84         if (HeaderList != nullptr){
85                 curl_slist_free_all(HeaderList);
86                 HeaderList = nullptr;
87         }
88         
89 }
91 #if defined(__APPLE__)
93 #elif defined(__WIN32__)
95 #else
97 SSLCertCollectionString CardDAV2::BuildSSLCollection(){
99         // Build and return the SSL collection.
100         
101         SSLCertCollectionString SSLCertInfo;
103         // Grab the certificate data.
105         union {
106                 struct curl_slist *certdata;
107                 struct curl_certinfo *certinfo;
108         } certptr;
110         certptr.certdata = NULL;
111         
112         curl_easy_getinfo(ConnectionSession, CURLINFO_CERTINFO, &certptr.certinfo);
114         std::string CertPropName;
115         std::string CertPropValue;
117         for (int i = 0; i < certptr.certinfo->num_of_certs; i++){
119                 struct curl_slist *slist;
120                 SSLCertDataString SSLCertDataInc;
121                 
122                 for (slist = certptr.certinfo->certinfo[i]; slist; slist = slist->next){
123                         
124                         // Using wxStringTokenizer from wxWidgets.
125                         
126                         wxStringTokenizer CertDataInc(wxString::FromUTF8(slist->data), ":");
127                         
128                         // Get first token as the property name.
129                         
130                         CertPropName = CertDataInc.GetNextToken().ToStdString();
131                         
132                         // Get remaining tokens as the property value.
133                         
134                         while(CertDataInc.HasMoreTokens()){
135                         
136                                 CertPropValue.append(CertDataInc.GetNextToken());
137                         
138                         }
139                         
140                         SSLCertDataInc.CertData.insert(std::make_pair(CertPropName, CertPropValue));
141                         CertPropName.clear();
142                         CertPropValue.clear();
143                         
144                 }
145         
146                 SSLCertInfo.SSLCollection.insert(std::make_pair(i, SSLCertDataInc));
147         
148         }
149         
150         return SSLCertInfo;
154 void CardDAV2::BypassSSLVerification(bool EnableBypass){
155         EnableSSLBypass = EnableBypass;
156         SSLSelfSigned = EnableBypass;
159 #endif
161 void CardDAV2::SetupConnectionObject(){
162         ConnectionSession = curl_easy_init();
165 bool CardDAV2::IsTaskCompleted(){
166         return false;
169 COConnectResult CardDAV2::Connect(bool DoAuthentication){
170         
171         ServerSSL ? SetupDefaultParametersSSL(DoAuthentication) : SetupDefaultParametersNonSSL(DoAuthentication);
172         ResetResults();
173         
174         COConnectResult ConnectResult = COCONNECT_UNITTESTFAIL;
175         string ServerAddressURL = BuildURL("/principals/");
177         curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddressURL.c_str());
178         
179         if (TestMode == true){
180                 SessionResult = curl_easy_perform(ConnectionSession);
181         } else {
182                 SessionResult = curl_easy_perform(ConnectionSession);           
183         }
184         
185         switch(SessionResult){
186                 case CURLE_OK:
187                 case CURLE_HTTP_RETURNED_ERROR:
188                         SSLStatus = true;
189                         SSLVerified = COSSL_VERIFIED;
190                         ConnectResult = COCONNECT_OK;
191                         break;
192                 case CURLE_SSL_CACERT:
193                 case CURLE_SSL_CONNECT_ERROR:
194                         SSLStatus = true;
195                         ConnectResult = COCONNECT_OK;
196                         SSLVerified = COSSL_UNABLETOVERIFY;
197                         break;
198                 default:
199                         ConnectResult = COCONNECT_INVALID;
200                         break;
201         };
202         
203         // Check if an error occured before continuing.
204         
205         // Check if authentication was successful.
206         
207         long SessionResponseCode = 0;
208         
209         curl_easy_getinfo(ConnectionSession, CURLINFO_RESPONSE_CODE, &SessionResponseCode);
210         
211         if (DoAuthentication == true){
212                 
213                 // Get the HTTP status code (Should be 200 and not 403).
214                 // Return error otherwise.
215                 
216                 if (SessionResponseCode == 200){
217                         ConnectResult = COCONNECT_OK;
218                         AuthPassed = true;
219                         ValidResponse = true;
220                 } else if (SessionResponseCode == 401){
221                         ConnectResult = COCONNECT_AUTHFAIL;
222                         AuthPassed = false;
223                         ValidResponse = true;
224                 } else if (SessionResponseCode >= 200) {
225                         ConnectResult = COCONNECT_INVALID;
226                         AuthPassed = false;
227                         ValidResponse = true;
228                 } else {
229                         ConnectResult = COCONNECT_INVALID;
230                         AuthPassed = false;
231                         ValidResponse = false;                  
232                 }
233                 
234         } else {
235                 
236                 ValidResponse = true;
237                 
238         }
239         
240         // Check the header to see if CardDAV is supported.
241         
242         vector<string> DAVHeaderValues = GetDAVHeader();
243         
244         for (vector<string>::iterator DAVHeaderValuesIter = DAVHeaderValues.begin();
245                 DAVHeaderValuesIter != DAVHeaderValues.end(); DAVHeaderValuesIter++){
246                 
247                 if ((*DAVHeaderValuesIter) == "addressbook"){
248                         CanProcess = true;
249                         break;
250                 }
251                         
252         }
253         
254         return ConnectResult;
255         
258 COServerResponse CardDAV2::GetDefaultPrefix(string *ServerPrefix){
260         // Check if authentication was successful, otherwise don't do anything.
262         COServerResponse ServerResponse;
263         
264         if (AuthPassed == false){
265                 ServerResponse.RequestResult = COREQUEST_ERROR_NOTCONNECTED;
266                 ServerResponse.EntityTag = "";
267                 ServerResponse.SessionCode = 0;
268                 ServerResponse.ResultCode = 0;
269                 ServerResponse.ResultMessage = "";
270                 return ServerResponse;
271         }
273         ServerSSL ? SetupDefaultParametersSSL(true) : SetupDefaultParametersNonSSL(true);
274         ResetResults();
275         
276         // Need to do three requests:
277         
278         // 1. Get the current user principal URI.
279         // 2. Get the address book home URI.
280         // 3. Get the default address book URI.
281         
282         // Setup the first query finding out where the principal URL is.
283         
284         const char* CurrentUserPrincipalXMLQuery = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"
285                 "<D:propfind xmlns:D=\"DAV:\">\n"
286                 " <D:prop>"
287                 "  <D:current-user-principal/>\n"
288                 " </D:prop>"
289                 "</D:propfind>";
291         // Setup the second query finding out where the address book home URL is.
292         
293         const char* AddressBookHomeXMLQuery = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"
294         "<D:propfind xmlns:D=\"DAV:\""
295         "  xmlns:C=\"urn:ietf:params:xml:ns:carddav\">\n"
296         "  <D:prop>\n"
297         "    <C:addressbook-home-set/>\n"
298         "  </D:prop>\n"
299         "</D:propfind>";
300         
301         // Setup the third query finding out where the default address book URL is.
302         
303         const char* DefaultAddressBookXMLQuery = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"
304         "<D:propfind xmlns:D=\"DAV:\""
305         "  xmlns:C=\"urn:ietf:params:xml:ns:carddav\">\n"
306         "  <D:prop>\n"
307         "    <C:default-addressbook-URL/>\n"    
308         "  </D:prop>\n"
309         "</D:propfind>";
310         
311         string ServerAddressURL = BuildURL("/principals/");
312         curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddressURL.c_str());
313         curl_easy_setopt(ConnectionSession, CURLOPT_CUSTOMREQUEST, "PROPFIND");
314         curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDS, CurrentUserPrincipalXMLQuery);
315         curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDSIZE, strlen(CurrentUserPrincipalXMLQuery));
316         
317         if (TestMode == true){
318                 SessionResult = curl_easy_perform(ConnectionSession);
319         } else {
320                 
321         }
322         
323         switch(SessionResult){
324                 case CURLE_OK:
325                         SSLStatus = true;
326                         SSLVerified = COSSL_VERIFIED;
327                         break;
328                 case CURLE_SSL_CACERT:
329                 case CURLE_SSL_CONNECT_ERROR:
330                         SSLStatus = true;
331                         SSLVerified = COSSL_UNABLETOVERIFY;
332                         break;
333                 default:
334                         break;
335         };
336         
337         long SessionResponseCode = 0;
338         
339         curl_easy_getinfo(ConnectionSession, CURLINFO_RESPONSE_CODE, &SessionResponseCode);
340         
341         if (SessionResponseCode == 200 || SessionResponseCode == 207){
342                 AuthPassed = true;
343                 ValidResponse = true;
344         } else if (SessionResponseCode == 403){
345                 AuthPassed = false;
346                 ValidResponse = true;
347         } else if (SessionResponseCode >= 400) {
348                 AuthPassed = false;
349                 ValidResponse = true;
350         } else {
351                 AuthPassed = false;
352                 ValidResponse = false;                  
353         }
354         
355         if (ValidResponse == false && AuthPassed == false){
356                 ServerResponse.RequestResult = COREQUEST_ERROR_SERVER;
357                 ServerResponse.EntityTag = "";
358                 ServerResponse.SessionCode = SessionResult;
359                 ServerResponse.ResultCode = SessionResponseCode;
360                 ServerResponse.ResultMessage = "";
361                 return ServerResponse;
362         }
363         
364         // Process the first response.
365         
366         string UserPrincipalURI = GetUserPrincipalURI();
367         
368         // Cleanup and reset for the second connection.
369         
370         ServerSSL ? SetupDefaultParametersSSL(true) : SetupDefaultParametersNonSSL(true);
371         ResetResults();
373         ServerAddressURL = BuildURL(UserPrincipalURI);
374         curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddressURL.c_str());
375         curl_easy_setopt(ConnectionSession, CURLOPT_CUSTOMREQUEST, "PROPFIND");
376         curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDS, AddressBookHomeXMLQuery);
377         curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDSIZE, strlen(AddressBookHomeXMLQuery));
378         
379         if (TestMode == true){
380                 SessionResult = curl_easy_perform(ConnectionSession);
381         } else {
382                 
383         }
384         
385         switch(SessionResult){
386                 case CURLE_OK:
387                         SSLStatus = true;
388                         SSLVerified = COSSL_VERIFIED;
389                         break;
390                 case CURLE_SSL_CACERT:
391                 case CURLE_SSL_CONNECT_ERROR:
392                         SSLStatus = true;
393                         SSLVerified = COSSL_UNABLETOVERIFY;
394                         break;
395                 default:
396                         break;
397         };
398         
399         SessionResponseCode = 0;
400         
401         curl_easy_getinfo(ConnectionSession, CURLINFO_RESPONSE_CODE, &SessionResponseCode);
402         
403         if (SessionResponseCode == 200 || SessionResponseCode == 207){
404                 AuthPassed = true;
405                 ValidResponse = true;
406         } else if (SessionResponseCode == 403){
407                 AuthPassed = false;
408                 ValidResponse = true;
409         } else if (SessionResponseCode >= 400) {
410                 AuthPassed = false;
411                 ValidResponse = true;
412         } else {
413                 AuthPassed = false;
414                 ValidResponse = false;                  
415         }
416         
417         if (ValidResponse == false && AuthPassed == false){
418                 ServerResponse.RequestResult = COREQUEST_ERROR_SERVER;
419                 ServerResponse.EntityTag = "";
420                 ServerResponse.SessionCode = SessionResult;
421                 ServerResponse.ResultCode = SessionResponseCode;
422                 ServerResponse.ResultMessage = "";
423                 return ServerResponse;
424         }
425         
426         // Process the second response.
427         
428         string AddressBookHomeURI = GetAddressBookHomeURI();
429         
430         // Cleanup and reset for the second connection.
431         
432         ServerSSL ? SetupDefaultParametersSSL(true) : SetupDefaultParametersNonSSL(true);
433         ResetResults();
434         
435         ServerAddressURL = BuildURL(AddressBookHomeURI);
436         curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddressURL.c_str());
437         curl_easy_setopt(ConnectionSession, CURLOPT_CUSTOMREQUEST, "PROPFIND");
438         curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDS, DefaultAddressBookXMLQuery);
439         curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDSIZE, strlen(DefaultAddressBookXMLQuery));
440         
441         if (TestMode == true){
442                 SessionResult = curl_easy_perform(ConnectionSession);
443         } else {
444                 
445         }
446         
447         switch(SessionResult){
448                 case CURLE_OK:
449                         SSLStatus = true;
450                         SSLVerified = COSSL_VERIFIED;
451                         break;
452                 case CURLE_SSL_CACERT:
453                 case CURLE_SSL_CONNECT_ERROR:
454                         SSLStatus = true;
455                         SSLVerified = COSSL_UNABLETOVERIFY;
456                         break;
457                 default:
458                         break;
459         };
460         
461         SessionResponseCode = 0;
462         
463         curl_easy_getinfo(ConnectionSession, CURLINFO_RESPONSE_CODE, &SessionResponseCode);
464         
465         if (SessionResponseCode == 200 || SessionResponseCode == 207){
466                 AuthPassed = true;
467                 ValidResponse = true;
468         } else if (SessionResponseCode == 403){
469                 AuthPassed = false;
470                 ValidResponse = true;
471         } else if (SessionResponseCode >= 200) {
472                 AuthPassed = false;
473                 ValidResponse = true;
474         } else {
475                 AuthPassed = false;
476                 ValidResponse = false;                  
477         }
478         
479         if (ValidResponse == false && AuthPassed == false){
480                 ServerResponse.RequestResult = COREQUEST_ERROR_SERVER;
481                 ServerResponse.EntityTag = "";
482                 ServerResponse.SessionCode = SessionResult;
483                 ServerResponse.ResultCode = SessionResponseCode;
484                 ServerResponse.ResultMessage = "";
485                 return ServerResponse;
486         }
487         
488         // Process the second response.
489         
490         (*ServerPrefix) = GetDefaultAddressBookURI();
491         
492         CanProcess = true;
493         
494         ServerResponse.RequestResult = COREQUEST_OK;
495         ServerResponse.EntityTag = "";
496         ServerResponse.SessionCode = SessionResult;
497         ServerResponse.ResultCode = SessionResponseCode;
498         ServerResponse.ResultMessage = SessionErrorBuffer;
499         return ServerResponse;
500         
503 std::string CardDAV2::GetUserPrincipalURI(){
504         
505         xmlDocPtr xmlCardDAVDoc;
506         xmlCardDAVDoc = xmlReadMemory(PageData.c_str(), (int)PageData.size(), "noname.xml", NULL, 0);
507         string UserPrincipalURI = "";
508         
509         xmlNodePtr nodeLevel1;
510         xmlNodePtr nodeLevel2;
511         xmlNodePtr nodeLevel3;
512         xmlNodePtr nodeLevel4;
513         xmlNodePtr nodeLevel5;
514         xmlNodePtr nodeLevel6;
515         xmlNodePtr nodeLevel7;
516                 
517         for (nodeLevel1 = xmlCardDAVDoc->children;
518                 nodeLevel1 != NULL;
519                 nodeLevel1 = nodeLevel1->next)
520         {
522                 for (nodeLevel2 = nodeLevel1->children;
523                         nodeLevel2 != NULL;
524                         nodeLevel2 = nodeLevel2->next)
525                 {
528                         for (nodeLevel3 = nodeLevel2->children;
529                         nodeLevel3 != NULL;
530                         nodeLevel3 = nodeLevel3->next)
531                         {
532                         
533                                 for (nodeLevel4 = nodeLevel3->children;
534                                 nodeLevel4 != NULL;
535                                 nodeLevel4 = nodeLevel4->next)
536                                 {
537                         
538                                         for (nodeLevel5 = nodeLevel4->children;
539                                         nodeLevel5 != NULL;
540                                         nodeLevel5 = nodeLevel5->next)
541                                         {
542                         
543                                                 for (nodeLevel6 = nodeLevel5->children;
544                                                 nodeLevel6 != NULL;
545                                                 nodeLevel6 = nodeLevel6->next)
546                                                 {
547                         
548                                                         if (!xmlStrcmp(nodeLevel6->name, (const xmlChar *)"href") ||
549                                                         !xmlStrcmp(nodeLevel6->name, (const xmlChar *)"d:href") ||
550                                                         !xmlStrcmp(nodeLevel6->name, (const xmlChar *)"D:href")
551                                                         ){
552                         
553                                                                 // Found the <href> part so extract the principal URL address.
554                                                                 
555                                                                 for (nodeLevel7 = nodeLevel6->children;
556                                                                 nodeLevel7 != NULL;
557                                                                 nodeLevel7 = nodeLevel7->next)
558                                                                 {
559                                                                 
560                                                                         UserPrincipalURI = ((const char*)nodeLevel7->content);
562                                                                 }
563                         
564                                                         }
565                         
566                                                 }
567                         
568                                         }
569                         
570                                 }
571                         
572                         }
573                 
574                 }
575                 
576         }
577         
578         xmlFreeDoc(xmlCardDAVDoc);
579         
580         return UserPrincipalURI;
581         
584 std::string CardDAV2::GetAddressBookHomeURI(){
585         
586         xmlDocPtr xmlCardDAVDoc;
587         xmlCardDAVDoc = xmlReadMemory(PageData.c_str(), (int)PageData.size(), "noname.xml", NULL, 0);
588         string AddressBookHomeURI = "";
589         
590         xmlNodePtr nodeLevel1;
591         xmlNodePtr nodeLevel2;
592         xmlNodePtr nodeLevel3;
593         xmlNodePtr nodeLevel4;
594         xmlNodePtr nodeLevel5;
595         xmlNodePtr nodeLevel6;
596         xmlNodePtr nodeLevel7;
597                 
598         for (nodeLevel1 = xmlCardDAVDoc->children;
599                 nodeLevel1 != NULL;
600                 nodeLevel1 = nodeLevel1->next)
601         {
603                 for (nodeLevel2 = nodeLevel1->children;
604                         nodeLevel2 != NULL;
605                         nodeLevel2 = nodeLevel2->next)
606                 {
609                         for (nodeLevel3 = nodeLevel2->children;
610                         nodeLevel3 != NULL;
611                         nodeLevel3 = nodeLevel3->next)
612                         {
613                         
614                                 for (nodeLevel4 = nodeLevel3->children;
615                                 nodeLevel4 != NULL;
616                                 nodeLevel4 = nodeLevel4->next)
617                                 {
618                         
619                                         for (nodeLevel5 = nodeLevel4->children;
620                                         nodeLevel5 != NULL;
621                                         nodeLevel5 = nodeLevel5->next)
622                                         {
623                         
624                                                 for (nodeLevel6 = nodeLevel5->children;
625                                                 nodeLevel6 != NULL;
626                                                 nodeLevel6 = nodeLevel6->next)
627                                                 {
628                         
629                                                         if (!xmlStrcmp(nodeLevel6->name, (const xmlChar *)"href") ||
630                                                         !xmlStrcmp(nodeLevel6->name, (const xmlChar *)"d:href") ||
631                                                         !xmlStrcmp(nodeLevel6->name, (const xmlChar *)"D:href")
632                                                         ){
633                         
634                                                                 // Found the <href> part so extract the principal URL address.
635                                                                 
636                                                                 for (nodeLevel7 = nodeLevel6->children;
637                                                                 nodeLevel7 != NULL;
638                                                                 nodeLevel7 = nodeLevel7->next)
639                                                                 {
640                                                                 
641                                                                         AddressBookHomeURI = ((const char*)nodeLevel7->content);
643                                                                 }
644                         
645                                                         }
646                         
647                                                 }
648                         
649                                         }
650                         
651                                 }
652                         
653                         }
654                 
655                 }
656                 
657         }
658         
659         xmlFreeDoc(xmlCardDAVDoc);
660         
661         return AddressBookHomeURI;
662         
665 std::string CardDAV2::GetDefaultAddressBookURI(){
666         
667         xmlDocPtr xmlCardDAVDoc;
668         xmlCardDAVDoc = xmlReadMemory(PageData.c_str(), (int)PageData.size(), "noname.xml", NULL, 0);
669         string DefaultAddressBookURI = "";
670         
671         xmlNodePtr nodeLevel1;
672         xmlNodePtr nodeLevel2;
673         xmlNodePtr nodeLevel3;
674         xmlNodePtr nodeLevel4;
675         xmlNodePtr nodeLevel5;
676         xmlNodePtr nodeLevel6;
677         xmlNodePtr nodeLevel7;
678                 
679         for (nodeLevel1 = xmlCardDAVDoc->children;
680                 nodeLevel1 != NULL;
681                 nodeLevel1 = nodeLevel1->next)
682         {
684                 for (nodeLevel2 = nodeLevel1->children;
685                         nodeLevel2 != NULL;
686                         nodeLevel2 = nodeLevel2->next)
687                 {
690                         for (nodeLevel3 = nodeLevel2->children;
691                         nodeLevel3 != NULL;
692                         nodeLevel3 = nodeLevel3->next)
693                         {
694                         
695                                 for (nodeLevel4 = nodeLevel3->children;
696                                 nodeLevel4 != NULL;
697                                 nodeLevel4 = nodeLevel4->next)
698                                 {
699                         
700                                         for (nodeLevel5 = nodeLevel4->children;
701                                         nodeLevel5 != NULL;
702                                         nodeLevel5 = nodeLevel5->next)
703                                         {
704                         
705                                                 for (nodeLevel6 = nodeLevel5->children;
706                                                 nodeLevel6 != NULL;
707                                                 nodeLevel6 = nodeLevel6->next)
708                                                 {
709                         
710                                                         if (!xmlStrcmp(nodeLevel6->name, (const xmlChar *)"href") ||
711                                                         !xmlStrcmp(nodeLevel6->name, (const xmlChar *)"d:href") ||
712                                                         !xmlStrcmp(nodeLevel6->name, (const xmlChar *)"D:href")
713                                                         ){
714                         
715                                                                 // Found the <href> part so extract the principal URL address.
716                                                                 
717                                                                 for (nodeLevel7 = nodeLevel6->children;
718                                                                 nodeLevel7 != NULL;
719                                                                 nodeLevel7 = nodeLevel7->next)
720                                                                 {
721                                                                 
722                                                                         DefaultAddressBookURI = ((const char*)nodeLevel7->content);
724                                                                 }
725                         
726                                                         }
727                         
728                                                 }
729                         
730                                         }
731                         
732                                 }
733                         
734                         }
735                 
736                 }
737                 
738         }
739         
740         xmlFreeDoc(xmlCardDAVDoc);
741         
742         return DefaultAddressBookURI;
743         
746 COServerResponse CardDAV2::AddContact(std::string Location, std::string Data){
747         
748         // Check if authentication was successful, otherwise don't do anything.
750         COServerResponse ServerResponse;
751         
752         if (AuthPassed == false){
753                 ServerResponse.RequestResult = COREQUEST_ERROR_NOTCONNECTED;
754                 ServerResponse.EntityTag = "";
755                 ServerResponse.SessionCode = 0;
756                 ServerResponse.ResultCode = 0;
757                 ServerResponse.ResultMessage = "";
758                 return ServerResponse;
759         }
761         ServerSSL ? SetupDefaultParametersSSL(true) : SetupDefaultParametersNonSSL(true);
762         ResetResults();
763         
764         string ServerAddressURL = BuildURL(ServerPrefix + Location);
765         curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddressURL.c_str());
766         curl_easy_setopt(ConnectionSession, CURLOPT_CUSTOMREQUEST, "PUT");
767         curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDS, Data.c_str());
768         curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDSIZE, strlen(Data.c_str()));
769         
770         HeaderList = curl_slist_append(HeaderList, "Content-Type: text/vcard; charset=utf-8");
772         curl_easy_setopt(ConnectionSession, CURLOPT_HTTPHEADER, HeaderList);
773         
774         if (TestMode == true){
775                 SessionResult = curl_easy_perform(ConnectionSession);
776         } else {
777                 SessionResult = curl_easy_perform(ConnectionSession);
778         }
779         
780         switch(SessionResult){
781                 case CURLE_OK:
782                         SSLStatus = true;
783                         SSLVerified = COSSL_VERIFIED;
784                         break;
785                 case CURLE_SSL_CACERT:
786                 case CURLE_SSL_CONNECT_ERROR:
787                         SSLStatus = true;
788                         SSLVerified = COSSL_UNABLETOVERIFY;
789                         break;
790                 default:
791                         break;
792         };
793         
794         long SessionResponseCode = 0;
795         
796         curl_easy_getinfo(ConnectionSession, CURLINFO_RESPONSE_CODE, &SessionResponseCode);
797         
798         if (SessionResponseCode == 200 || SessionResponseCode == 201 || SessionResponseCode == 204){
799                 AuthPassed = true;
800                 ValidResponse = true;
801         } else if (SessionResponseCode == 403){
802                 AuthPassed = false;
803                 ValidResponse = true;
804         } else if (SessionResponseCode >= 400){
805                 AuthPassed = false;
806                 ValidResponse = true;
807         } else {
808                 AuthPassed = false;
809                 ValidResponse = false;                  
810         }
811         
812         if (ValidResponse == false && AuthPassed == false){
813                 ServerResponse.RequestResult = COREQUEST_ERROR_SERVER;
814                 ServerResponse.EntityTag = "";
815                 ServerResponse.SessionCode = SessionResult;
816                 ServerResponse.ResultCode = SessionResponseCode;
817                 ServerResponse.ResultMessage = "";
818                 return ServerResponse;
819         }
820         
821         CanProcess = true;
822         
823         ServerResponse.RequestResult = COREQUEST_OK;
824         ServerResponse.EntityTag = "";
825         ServerResponse.SessionCode = SessionResult;
826         ServerResponse.ResultCode = SessionResponseCode;
827         ServerResponse.ResultMessage = SessionErrorBuffer;
828         return ServerResponse;
829         
832 COServerResponse CardDAV2::EditContact(std::string Location, std::string Data){
833         
836 COServerResponse CardDAV2::DeleteContact(std::string Location, std::string EntityTag){
837         
840 COServerResponse CardDAV2::GetServerEntityTagValue(std::string Location){
841         
842         // Check if authentication was successful, otherwise don't do anything.
844         COServerResponse ServerResponse;
845         
846         if (AuthPassed == false){
847                 ServerResponse.RequestResult = COREQUEST_ERROR_NOTCONNECTED;
848                 ServerResponse.EntityTag = "";
849                 ServerResponse.SessionCode = 0;
850                 ServerResponse.ResultCode = 0;
851                 ServerResponse.ResultMessage = "";
852                 return ServerResponse;
853         }
855         ServerSSL ? SetupDefaultParametersSSL(true) : SetupDefaultParametersNonSSL(true);
856         ResetResults();
857         
858         static const char* GetETagQuery =
859         "<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
860         "<C:addressbook-query xmlns:D=\"DAV:\""
861         "       xmlns:C=\"urn:ietf:params:xml:ns:carddav\">"
862         "<D:prop><D:getetag/>"
863         "</D:prop>"
864         "<C:filter/>"
865         "</C:addressbook-query>";
866         
867         string ServerAddressURL = BuildURL(ServerPrefix + Location);
868         curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddressURL.c_str());
869         curl_easy_setopt(ConnectionSession, CURLOPT_CUSTOMREQUEST, "REPORT");
870         curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDS, GetETagQuery);
871         curl_easy_setopt(ConnectionSession, CURLOPT_POSTFIELDSIZE, strlen(GetETagQuery));
872         
873         if (TestMode == true){
874                 SessionResult = curl_easy_perform(ConnectionSession);
875         } else {
876                 SessionResult = curl_easy_perform(ConnectionSession);
877         }
878         
879         switch(SessionResult){
880                 case CURLE_OK:
881                         SSLStatus = true;
882                         SSLVerified = COSSL_VERIFIED;
883                         break;
884                 case CURLE_SSL_CACERT:
885                 case CURLE_SSL_CONNECT_ERROR:
886                         SSLStatus = true;
887                         SSLVerified = COSSL_UNABLETOVERIFY;
888                         break;
889                 default:
890                         break;
891         };
892         
893         long SessionResponseCode = 0;
894         
895         curl_easy_getinfo(ConnectionSession, CURLINFO_RESPONSE_CODE, &SessionResponseCode);
896         
897         if (SessionResponseCode == 207){
898                 AuthPassed = true;
899                 ValidResponse = true;
900         } else if (SessionResponseCode == 403){
901                 AuthPassed = false;
902                 ValidResponse = true;
903         } else if (SessionResponseCode >= 400){
904                 AuthPassed = false;
905                 ValidResponse = true;
906         } else {
907                 AuthPassed = false;
908                 ValidResponse = false;                  
909         }
910         
911         if (ValidResponse == false && AuthPassed == false){
912                 ServerResponse.RequestResult = COREQUEST_ERROR_SERVER;
913                 ServerResponse.EntityTag = "";
914                 ServerResponse.SessionCode = SessionResult;
915                 ServerResponse.ResultCode = SessionResponseCode;
916                 ServerResponse.ResultMessage = "";
917                 return ServerResponse;
918         }
919         
920         CanProcess = true;
921         
922         ServerResponse.RequestResult = COREQUEST_OK;
923         ServerResponse.EntityTag = GetETagValue();
924         ServerResponse.SessionCode = SessionResult;
925         ServerResponse.ResultCode = SessionResponseCode;
926         ServerResponse.ResultMessage = SessionErrorBuffer;
927         
928         return ServerResponse;
929         
932 COServerResponse CardDAV2::GetContact(std::string Location){
933         
936 COContactList CardDAV2::GetContactList(std::string SyncToken){
937         
939         
940 bool CardDAV2::CanDoProcessing(){
941         return CanProcess;
944 bool CardDAV2::CanDoSSL(){
945         return SSLStatus;
948 COSSLVerified CardDAV2::SSLVerify(){
949         return SSLVerified;
952 bool CardDAV2::AbleToLogin(){
953         return AuthPassed;
956 bool CardDAV2::HasValidResponse(){
957         return ValidResponse;
960 bool CardDAV2::IsSelfSigned(){
961         return SSLSelfSigned;
964 void CardDAV2::SetupDefaultParametersNonSSL(bool DoAuthentication){
965         
966         std::string ServerAddress = "";
968         string ServerAddressURL = "http://" + ServerAddress + ":" + to_string(ServerPort) + "/";
969         string UsernamePassword = ServerUser + ":" + ServerPass;
970         
971         curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddress.c_str());
972         curl_easy_setopt(ConnectionSession, CURLOPT_NOPROGRESS, 1L);
973         curl_easy_setopt(ConnectionSession, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
974         curl_easy_setopt(ConnectionSession, CURLOPT_TIMEOUT, 60);
975         curl_easy_setopt(ConnectionSession, CURLOPT_FAILONERROR, true);
976         curl_easy_setopt(ConnectionSession, CURLOPT_USERAGENT, XSDAB_USERAGENT);
977         curl_easy_setopt(ConnectionSession, CURLOPT_WRITEFUNCTION, CardDAV2::WritebackFunc);
978         curl_easy_setopt(ConnectionSession, CURLOPT_WRITEDATA, &PageData);
979         curl_easy_setopt(ConnectionSession, CURLOPT_WRITEHEADER, &PageHeader);
980         curl_easy_setopt(ConnectionSession, CURLOPT_NOSIGNAL, 1);
981         curl_easy_setopt(ConnectionSession, CURLOPT_CUSTOMREQUEST, "GET");
982         curl_easy_setopt(ConnectionSession, CURLOPT_HTTPHEADER, nullptr);
983         
984         if (DoAuthentication == true){
985                 curl_easy_setopt(ConnectionSession, CURLOPT_USERPWD, UsernamePassword.c_str());
986         } else {
987                 curl_easy_setopt(ConnectionSession, CURLOPT_USERPWD, ":");              
988         }
989         
992 void CardDAV2::SetupDefaultParametersSSL(bool DoAuthentication){
993         
994         // Setup the default parameters.
995         
996         string ServerAddressURL = "https://" + ServerAddress + ":" + to_string(ServerPort) + "/";
997         string UsernamePassword = ServerUser + ":" + ServerPass;
998         
999         curl_easy_setopt(ConnectionSession, CURLOPT_URL, ServerAddressURL.c_str());
1000         curl_easy_setopt(ConnectionSession, CURLOPT_NOPROGRESS, 1L);
1001         curl_easy_setopt(ConnectionSession, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
1002         curl_easy_setopt(ConnectionSession, CURLOPT_TIMEOUT, 60);
1003         curl_easy_setopt(ConnectionSession, CURLOPT_FAILONERROR, true);
1004         curl_easy_setopt(ConnectionSession, CURLOPT_USERAGENT, XSDAB_USERAGENT);
1005         curl_easy_setopt(ConnectionSession, CURLOPT_WRITEFUNCTION, CardDAV2::WritebackFunc);
1006         curl_easy_setopt(ConnectionSession, CURLOPT_WRITEDATA, &PageData);
1007         curl_easy_setopt(ConnectionSession, CURLOPT_WRITEHEADER, &PageHeader);
1008         curl_easy_setopt(ConnectionSession, CURLOPT_ERRORBUFFER, SessionErrorBuffer);
1009         curl_easy_setopt(ConnectionSession, CURLOPT_NOSIGNAL, 1);
1010         curl_easy_setopt(ConnectionSession, CURLOPT_CERTINFO, 1);
1011         curl_easy_setopt(ConnectionSession, CURLOPT_VERBOSE, 1);
1012         curl_easy_setopt(ConnectionSession, CURLOPT_CUSTOMREQUEST, "GET");
1013         curl_easy_setopt(ConnectionSession, CURLOPT_HTTPHEADER, nullptr);
1014         
1015         if (DoAuthentication == true){
1016                 curl_easy_setopt(ConnectionSession, CURLOPT_USERPWD, UsernamePassword.c_str());
1017         } else {
1018                 curl_easy_setopt(ConnectionSession, CURLOPT_USERPWD, ":");              
1019         }
1020         
1021         if (EnableSSLBypass == true){
1022                 curl_easy_setopt(ConnectionSession, CURLOPT_SSL_VERIFYHOST, 0);
1023                 curl_easy_setopt(ConnectionSession, CURLOPT_SSL_VERIFYPEER, 0);
1024         } else {
1025                 curl_easy_setopt(ConnectionSession, CURLOPT_SSL_VERIFYHOST, 2);
1026                 curl_easy_setopt(ConnectionSession, CURLOPT_SSL_VERIFYPEER, 1);         
1027         }
1028         
1029         if (TestMode == false && ServerAccount.size() > 0){
1030                 
1031                 // Check if the server certificate file exists.
1032                 
1033                 string CertificateFilename = GetAccountDir(ServerAccount, true);
1034                 
1035                 if (wxFile::Exists(CertificateFilename)){
1036                         
1037                         curl_easy_setopt(ConnectionSession, CURLOPT_CAINFO, CertificateFilename.c_str());
1038                         
1039                 }
1040                 
1041         }
1042         
1045 string CardDAV2::BuildURL(string URI){
1046         
1047         string ServerAddressURL;
1048         
1049         if (SSLStatus == true){
1050                 ServerAddressURL = "https://" + ServerAddress + ":" + to_string(ServerPort) + URI;      
1051         } else {
1052                 ServerAddressURL = "https://" + ServerAddress + ":" + to_string(ServerPort) + URI;
1053         }
1054         
1055         return ServerAddressURL;
1056         
1059 string CardDAV2::GetErrorMessage(){
1060         
1061         ErrorMessage = SessionErrorBuffer;      
1062         return ErrorMessage;
1063         
1066 void CardDAV2::ResetResults(){
1067         
1068         SSLStatus = false;
1069         COSSLVerified SSLVerified = COSSL_NORESULT;
1070         ValidResponse = false;
1071         AuthPassed = false;
1072         CanProcess = false;
1073         SSLSelfSigned = false;
1074         TaskCompleted = false;
1075         ErrorMessage = "";
1076         SessionErrorBuffer[0] = '\0';
1077         PageData = "";
1078         PageHeader = "";
1079         if (HeaderList != nullptr){
1080                 curl_slist_free_all(HeaderList);
1081                 HeaderList = nullptr;
1082         }
1083         
1086 string CardDAV2::GetETagValue(){
1087         
1088         xmlDocPtr xmlCardDAVDoc;
1090         xmlCardDAVDoc = xmlReadMemory(PageData.c_str(), (int)PageData.size(), "noname.xml", NULL, 0);
1092         xmlNodePtr nodeLevel1;
1093         xmlNodePtr nodeLevel2;
1094         xmlNodePtr nodeLevel3;
1095         xmlNodePtr nodeLevel4;
1096         xmlNodePtr nodeLevel5;
1097         xmlNodePtr nodeLevel6;
1099         //std::map<wxString,wxString> xmlDataMap;
1101         std::string DataFilename;
1102         std::string ETagData;
1104         std::string xmlStringSafe;
1105         std::string ETagValue;
1107         // Tranverse through the catacombs of the response to get our ETag for the file.
1109         for (nodeLevel1 = xmlCardDAVDoc->children;
1110                 nodeLevel1 != NULL;
1111                 nodeLevel1 = nodeLevel1->next)
1112         {
1114                 bool HREFFound = FALSE;
1115                 bool ETagFound = FALSE;
1117                 for (nodeLevel2 = nodeLevel1->children;
1118                         nodeLevel2 != NULL;
1119                         nodeLevel2 = nodeLevel2->next)
1120                 {
1122                         for (nodeLevel3 = nodeLevel2->children;
1123                         nodeLevel3 != NULL;
1124                         nodeLevel3 = nodeLevel3->next)
1125                         {
1127                                 if (!xmlStrcmp(nodeLevel3->name, (const xmlChar *)"href") ||
1128                                 !xmlStrcmp(nodeLevel3->name, (const xmlChar *)"d:href") ||
1129                                 !xmlStrcmp(nodeLevel3->name, (const xmlChar *)"D:href")
1130                                 ){
1132                                         // Get the filename.
1133                                         
1134                                         for (nodeLevel4 = nodeLevel3->children;
1135                                         nodeLevel4 != NULL;
1136                                         nodeLevel4 = nodeLevel4->next)
1137                                         {
1138                                         
1139                                                 if (!xmlStrcmp(nodeLevel4->name, (const xmlChar *)"text") ||
1140                                                 !xmlStrcmp(nodeLevel4->name, (const xmlChar *)"d:text") ||
1141                                                 !xmlStrcmp(nodeLevel4->name, (const xmlChar *)"D:text")
1142                                                 ){
1144                                                         DataFilename = wxString::FromUTF8((const char*)nodeLevel4->content);
1145                                                         wxStringTokenizer wSTDFilename(DataFilename, wxT("/"));
1146                                                 
1147                                                         while (wSTDFilename.HasMoreTokens()){
1148                                                         
1149                                                                 DataFilename = wSTDFilename.GetNextToken().ToStdString();
1150                                                         
1151                                                         }
1152                                                         
1153                                                         HREFFound = TRUE;
1154                                                 
1155                                                 }
1156                                                 
1157         
1158                                         
1159                                         }
1161                                 } else {
1163                                         for (nodeLevel4 = nodeLevel3->children;
1164                                         nodeLevel4 != NULL;
1165                                         nodeLevel4 = nodeLevel4->next)
1166                                         {
1167                                                         
1168                                                         for (nodeLevel5 = nodeLevel4->children;
1169                                                         nodeLevel5 != NULL;
1170                                                         nodeLevel5 = nodeLevel5->next)
1171                                                         {
1173                                                                 if (!xmlStrcmp(nodeLevel5->name, (const xmlChar *)"getetag") ||
1174                                                                 !xmlStrcmp(nodeLevel5->name, (const xmlChar *)"d:getetag") ||
1175                                                                 !xmlStrcmp(nodeLevel5->name, (const xmlChar *)"D:getetag")
1176                                                                 ){
1178                                                                         for (nodeLevel6 = nodeLevel5->children;
1179                                                                         nodeLevel6 != NULL;
1180                                                                         nodeLevel6 = nodeLevel6->next)
1181                                                                         {
1182                                                         
1183                                                                                 // Strip the quotes from the ETag.
1184                                                         
1185                                                                                 ETagData = (const char*)nodeLevel6->content;
1186                                                                                 if (ETagData[0] == '"' && ETagData[(ETagData.size() - 1)] == '"'){
1187                                                         
1188                                                                                         ETagData.erase(0, 1);
1189                                                                                         ETagData.erase((ETagData.size() - 1));
1190                                                         
1191                                                                                 }
1192                                                                         
1193                                                                                 ETagFound = TRUE;
1195                                                                         }
1196                                                                         
1197                                                                 }
1199                                                         }       
1201                                         }
1203                                 }
1205                         }
1207                 }
1208                 
1209                 if (HREFFound == TRUE && ETagFound == TRUE){
1210                                 
1211                         // Add to the map data.
1212                                 
1213                         ETagValue = ETagData;
1214                         
1215                         HREFFound = FALSE;
1216                         ETagFound = FALSE;
1217                         break;
1218                                 
1219                 }
1222         }
1224         xmlFreeDoc(xmlCardDAVDoc);
1225         
1226         return ETagValue;
1227         
1230 string CardDAV2::GetETagHeader(){
1231         
1232         // Go through each of the lines looking for the
1233         // 'DAV:' section.
1234         
1235         string HeaderName;
1236         string HeaderValue;
1237         bool FastForward = false;
1238         
1239         for (int HeaderSeek = 0; HeaderSeek < PageHeader.size(); HeaderSeek++){
1240                 
1241                 if (FastForward == true){
1242                         
1243                         if (PageHeader[HeaderSeek] == '\n'){
1244                                 FastForward = false;
1245                         }
1246                         
1247                         continue;
1248                         
1249                 }
1250                 
1251                 try {
1252                         PageHeader.substr(HeaderSeek, 5) == "ETag:";
1253                 }
1254                 
1255                 catch (const out_of_range &oor){
1256                         break;
1257                 }
1258                 
1259                 if (PageHeader.substr(HeaderSeek, 5) == "ETag:"){
1260                         
1261                         int CharacterSeek = 5;
1262                         
1263                         while ((HeaderSeek + CharacterSeek) < PageHeader.size()){
1264                                 
1265                                 if (PageHeader.substr((HeaderSeek + CharacterSeek), 2) == "\r\n"){
1266                                         break;
1267                                 }
1268                                 
1269                                 HeaderValue += PageHeader.substr((HeaderSeek + CharacterSeek), 1);
1270                                 CharacterSeek++;
1271                         }
1272                         
1273                         break;
1274                         
1275                 } else {
1276                         
1277                         FastForward = true;
1278                         continue;
1279                         
1280                 }
1281                 
1282                 if (PageHeader[HeaderSeek] == '\n'){
1283                         HeaderName = "";
1284                 }
1285                 
1286                 //HeaderName += PageHeader.substr(HeaderSeek, 1);
1287                 
1288         }
1289         
1290         // Check for quotation marks at the start and end and strip
1291         // them out.
1292         
1293         if (HeaderValue.size() >= 2){
1294                 
1295                 if (HeaderValue[0] == '"'){
1296                         HeaderValue.erase((HeaderValue.size() - 1));
1297                         HeaderValue.erase(0);
1298                 }
1299                 
1300         }
1301         
1302         return HeaderValue;
1303         
1306 vector<string> CardDAV2::GetDAVHeader(){
1307         
1308         // Go through each of the lines looking for the
1309         // 'DAV:' section.
1310         
1311         string HeaderName;
1312         string HeaderValue;
1313         bool FastForward = false;
1314         vector<string> DAVHeaderList;
1315         
1316         for (int HeaderSeek = 0; HeaderSeek < PageHeader.size(); HeaderSeek++){
1317                 
1318                 if (FastForward == true){
1319                         
1320                         if (PageHeader[HeaderSeek] == '\n'){
1321                                 FastForward = false;
1322                         }
1323                         
1324                         continue;
1325                         
1326                 }
1327                 
1328                 try {
1329                         PageHeader.substr(HeaderSeek, 4) == "DAV:";
1330                 }
1331                 
1332                 catch (const out_of_range &oor){
1333                         break;
1334                 }
1335                 
1336                 if (PageHeader.substr(HeaderSeek, 4) == "DAV:"){
1337                         
1338                         int CharacterSeek = 5;
1339                         
1340                         while ((HeaderSeek + CharacterSeek) < PageHeader.size()){
1341                                 
1342                                 if (PageHeader.substr((HeaderSeek + CharacterSeek), 2) == "\r\n"){
1343                                         break;
1344                                 }
1345                                 
1346                                 HeaderValue += PageHeader.substr((HeaderSeek + CharacterSeek), 1);
1347                                 CharacterSeek++;
1348                         }
1349                         
1350                         break;
1351                         
1352                 } else {
1353                         
1354                         FastForward = true;
1355                         continue;
1356                         
1357                 }
1358                 
1359                 if (PageHeader[HeaderSeek] == '\n'){
1360                         HeaderName = "";
1361                 }
1362                 
1363                 //HeaderName += PageHeader.substr(HeaderSeek, 1);
1364                 
1365         }
1366         
1367         // Split the header data.
1368         
1369         std::string DAVHeaderValue;
1370         
1371         for (int HeaderSeek = 0; HeaderSeek < HeaderValue.size(); HeaderSeek++){
1372                 
1373                 if (HeaderValue.substr(HeaderSeek, 1) == ","){
1374                         DAVHeaderList.push_back(DAVHeaderValue);
1375                         DAVHeaderValue = "";
1376                         HeaderSeek++;
1377                         continue;
1378                 }
1379                 
1380                 DAVHeaderValue += HeaderValue[HeaderSeek];
1381                 
1382         }
1383         
1384         if (DAVHeaderValue.size() > 0){
1385                 
1386                 DAVHeaderList.push_back(DAVHeaderValue);
1387                 
1388         }
1389         
1390         return DAVHeaderList;
1391         
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