1 // carddav-contactlist.cpp - CardDAV Object - Contact list subroutines.
3 // (c) 2012-2015 Xestia Software Development.
5 // This file is part of Xestia Address Book.
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.
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.
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/>
20 #include "../version.h"
22 #include <wx/tokenzr.h>
24 #include <libxml/parser.h>
25 #include <libxml/tree.h>
28 #include "../vcard/vcard.h"
29 #include "../common/dirs.h"
31 ContactListData CardDAV::GetContactList(wxString SyncTokenInc){
33 // Get the contact list.
35 ContactListData ContactListFinal;
36 std::map<wxString,FileSyncData> ContactList;
43 AbortConnection = FALSE;
46 wxString ServerAddressURL;
48 wxString ServerAddressSSL;
49 wxString ServerAddressNormal;
51 conn = curl_easy_init();
53 #if defined(__APPLE__)
54 SetConnectionObject(conn);
57 struct CardDAVCURLPasser {
60 bool HeaderMode = TRUE;
62 } CardDAVHeader, CardDAVFooter;
64 CardDAVHeader.Data = this;
65 CardDAVHeader.HeaderMode = TRUE;
67 CardDAVFooter.Data = this;
68 CardDAVFooter.HeaderMode = FALSE;
73 ServerAddressURL = ServerAddress + wxT(":") + wxString::Format(wxT("%i"), ServerPort) + ServerPrefix;
74 ServerAddressSSL = wxT("https://") + ServerAddressURL;
75 ServerAddressNormal = wxT("http://") + ServerAddressURL;
77 ServerAuth = ServerUser + wxT(":") + ServerPass;
79 // Load the sync token file (if it exists).
81 wxCharBuffer SyncDataBuffer;
88 if (!SyncTokenInc.IsEmpty()){
90 SyncData = wxT("<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n");
91 SyncData.Append(wxT("<D:sync-collection xmlns:D=\"DAV:\"\n"));
92 SyncData.Append(wxT(" xmlns:C=\"urn:ietf:params:xml:ns:carddav\">\n"));
93 SyncData.Append(wxT("<D:sync-token>"));
94 SyncData.Append(SyncTokenInc);
95 SyncData.Append(wxT("</D:sync-token>\n"));
96 SyncData.Append(wxT("<D:sync-level>1</D:sync-level>\n"));
97 SyncData.Append(wxT("<D:prop>\n"));
98 SyncData.Append(wxT(" <D:getetag/>\n"));
99 SyncData.Append(wxT("</D:prop>\n"));
100 SyncData.Append(wxT("</D:sync-collection>"));
102 SyncDataBuffer = SyncData.ToUTF8();
106 SyncData = wxT("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
107 SyncData.Append(wxT("<D:sync-collection xmlns:D=\"DAV:\""));
108 SyncData.Append(wxT(" xmlns:C=\"urn:ietf:params:xml:ns:carddav\">\n"));
109 SyncData.Append(wxT("<D:sync-token/>\n"));
110 SyncData.Append(wxT("<D:sync-level>1</D:sync-level>\n"));
111 SyncData.Append(wxT("<D:prop>\n"));
112 SyncData.Append(wxT(" <D:getetag/>\n"));
113 SyncData.Append(wxT("</D:prop>\n"));
114 SyncData.Append(wxT("</D:sync-collection>\n"));
116 SyncDataBuffer = SyncData.ToUTF8();
120 const char* query = SyncDataBuffer.data();
124 std::map<int,int>::iterator ActIter;
125 struct UploadDataStruc UploadData;
127 ActIter = ActivityListPtr->find((int)ItemIndex);
129 curl_slist *slist = NULL;
131 slist = curl_slist_append(slist, "Depth: 1");
135 wxString ServerCertFilename;
136 bool MatchingCert = FALSE;
138 curl_easy_setopt(conn, CURLOPT_URL, (const char*)ServerAddressSSL.mb_str(wxConvUTF8));
139 curl_easy_setopt(conn, CURLOPT_NOPROGRESS, 0);
140 curl_easy_setopt(conn, CURLOPT_HTTPAUTH, CURLAUTH_ANYSAFE);
141 curl_easy_setopt(conn, CURLOPT_TIMEOUT, 60);
142 curl_easy_setopt(conn, CURLOPT_FAILONERROR, TRUE);
143 curl_easy_setopt(conn, CURLOPT_USERAGENT, XSDAB_USERAGENT);
144 curl_easy_setopt(conn, CURLOPT_USERPWD, (const char*)ServerAuth.mb_str(wxConvUTF8));
145 curl_easy_setopt(conn, CURLOPT_WRITEFUNCTION, WritebackFunc);
146 curl_easy_setopt(conn, CURLOPT_WRITEDATA, &PageData);
147 curl_easy_setopt(conn, CURLOPT_WRITEHEADER, &PageHeader);
148 curl_easy_setopt(conn, CURLOPT_PROGRESSDATA, this);
149 curl_easy_setopt(conn, CURLOPT_PROGRESSFUNCTION, ProgressFunc);
150 curl_easy_setopt(conn, CURLOPT_CUSTOMREQUEST, "REPORT");
151 curl_easy_setopt(conn, CURLOPT_NOSIGNAL, 1);
152 curl_easy_setopt(conn, CURLOPT_HTTPHEADER, slist);
153 curl_easy_setopt(conn, CURLOPT_CERTINFO, 1);
155 #if defined(__APPLE__)
159 ServerCertFilename = GetAccountDir(ServerAccount, TRUE);
161 if (wxFile::Exists(ServerCertFilename) == TRUE){
163 curl_easy_setopt(conn, CURLOPT_SSL_VERIFYPEER, 1);
164 curl_easy_setopt(conn, CURLOPT_SSL_VERIFYHOST, 2);
165 curl_easy_setopt(conn, CURLOPT_CAINFO, (const char*)ServerCertFilename.mb_str(wxConvUTF8));
171 curl_easy_setopt(conn, CURLOPT_POSTFIELDS, query);
172 curl_easy_setopt(conn, CURLOPT_POSTFIELDSIZE, strlen(query));
174 claconncode = (curl_easy_perform(conn));
176 // If CURLE_PEER_FAILED_VERIFICATION is returned, retry without
177 // the local certificate in use.
179 if (claconncode == CURLE_PEER_FAILED_VERIFICATION){
181 curl_easy_cleanup(conn);
182 conn = curl_easy_init();
184 curl_easy_setopt(conn, CURLOPT_URL, (const char*)ServerAddressSSL.mb_str(wxConvUTF8));
185 curl_easy_setopt(conn, CURLOPT_NOPROGRESS, 0);
186 curl_easy_setopt(conn, CURLOPT_HTTPAUTH, CURLAUTH_ANYSAFE);
187 curl_easy_setopt(conn, CURLOPT_TIMEOUT, 60);
188 curl_easy_setopt(conn, CURLOPT_FAILONERROR, TRUE);
189 curl_easy_setopt(conn, CURLOPT_USERAGENT, XSDAB_USERAGENT);
190 curl_easy_setopt(conn, CURLOPT_USERPWD, (const char*)ServerAuth.mb_str(wxConvUTF8));
191 curl_easy_setopt(conn, CURLOPT_WRITEFUNCTION, WritebackFunc);
192 curl_easy_setopt(conn, CURLOPT_WRITEDATA, &PageData);
193 curl_easy_setopt(conn, CURLOPT_WRITEHEADER, &PageHeader);
194 curl_easy_setopt(conn, CURLOPT_PROGRESSDATA, this);
195 curl_easy_setopt(conn, CURLOPT_PROGRESSFUNCTION, ProgressFunc);
196 curl_easy_setopt(conn, CURLOPT_CUSTOMREQUEST, "REPORT");
197 curl_easy_setopt(conn, CURLOPT_NOSIGNAL, 1);
198 curl_easy_setopt(conn, CURLOPT_HTTPHEADER, slist);
199 curl_easy_setopt(conn, CURLOPT_CERTINFO, 1);
200 curl_easy_setopt(conn, CURLOPT_POSTFIELDS, query);
201 curl_easy_setopt(conn, CURLOPT_POSTFIELDSIZE, strlen(query));
203 claconncode = (curl_easy_perform(conn));
205 // If claconncode is CURLE_OK then delete the certificate file as that
206 // is no longer needed.
208 if (claconncode == CURLE_OK){
210 // Delete the certificate file.
212 wxRemoveFile(ServerCertFilename);
218 // Check if it fails with a CURLE_SSL_CACERT then compare
219 // the certificates as PEM files.
221 #if defined(__APPLE__)
225 if (claconncode == CURLE_SSL_CACERT && wxFile::Exists(ServerCertFilename) == TRUE){
228 sslerrconn = curl_easy_init();
229 CURLcode sslerrconncode;
231 wxString ServerAddressOnly = wxT("https://") + ServerAddress + wxT(":") + wxString::Format(wxT("%i"), ServerPort) + wxT("/");
233 curl_easy_setopt(sslerrconn, CURLOPT_URL, (const char*)ServerAddressOnly.mb_str(wxConvUTF8));
234 curl_easy_setopt(sslerrconn, CURLOPT_NOPROGRESS, 0);
235 curl_easy_setopt(sslerrconn, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
236 curl_easy_setopt(sslerrconn, CURLOPT_TIMEOUT, 60);
237 curl_easy_setopt(sslerrconn, CURLOPT_FAILONERROR, TRUE);
238 curl_easy_setopt(sslerrconn, CURLOPT_USERAGENT, XSDAB_USERAGENT);
239 curl_easy_setopt(sslerrconn, CURLOPT_WRITEFUNCTION, WritebackFunc);
240 curl_easy_setopt(sslerrconn, CURLOPT_WRITEDATA, &PageData);
241 curl_easy_setopt(sslerrconn, CURLOPT_WRITEHEADER, &PageHeader);
242 curl_easy_setopt(sslerrconn, CURLOPT_PROGRESSDATA, this);
243 curl_easy_setopt(sslerrconn, CURLOPT_PROGRESSFUNCTION, ProgressFunc);
244 curl_easy_setopt(sslerrconn, CURLOPT_NOSIGNAL, 1);
245 curl_easy_setopt(sslerrconn, CURLOPT_SSL_VERIFYPEER, 0);
246 curl_easy_setopt(sslerrconn, CURLOPT_CERTINFO, 1);
248 wxString SSLLocalData;
249 wxString SSLServerData;
251 sslerrconncode = (curl_easy_perform(sslerrconn));
253 SSLCertCol = BuildSSLCollection(sslerrconn);
254 std::map<int, SSLCertData>::iterator SSLCDIter = SSLCertCol.SSLCollection.find(0);
255 std::multimap<wxString,wxString>::iterator SSLDataIter = SSLCDIter->second.CertData.find(wxT("Cert"));
257 wxFFile SSLLocalFile;
259 #if wxABI_VERSION < 20900
260 SSLLocalFile.Open(ServerCertFilename.c_str(), wxT("r"));
262 SSLLocalFile.Open(ServerCertFilename, wxT("r"));
265 // Load the recovery database for tasks not done.
267 if (SSLLocalFile.IsOpened() == TRUE){
269 // Check if we are using wxWidgets version 2.8 or less and
270 // execute the required command accordingly.
272 SSLLocalFile.ReadAll(&SSLLocalData, wxConvAuto());
277 SSLServerData = SSLDataIter->second;
279 if (SSLLocalData == SSLServerData){
281 // Server key matches with local key so retry with CURLOPT_SSL_VERIFYPEER
282 // and CURLOPT_SSL_VERIFYHOST off.
284 curl_easy_cleanup(conn);
285 conn = curl_easy_init();
290 curl_easy_setopt(conn, CURLOPT_URL, (const char*)ServerAddressSSL.mb_str(wxConvUTF8));
291 curl_easy_setopt(conn, CURLOPT_NOPROGRESS, 0);
292 curl_easy_setopt(conn, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
293 curl_easy_setopt(conn, CURLOPT_TIMEOUT, 60);
294 curl_easy_setopt(conn, CURLOPT_FAILONERROR, TRUE);
295 curl_easy_setopt(conn, CURLOPT_USERAGENT, XSDAB_USERAGENT);
296 curl_easy_setopt(conn, CURLOPT_USERPWD, (const char*)ServerAuth.mb_str(wxConvUTF8));
297 curl_easy_setopt(conn, CURLOPT_WRITEFUNCTION, WritebackFunc);
298 curl_easy_setopt(conn, CURLOPT_WRITEDATA, &PageData);
299 curl_easy_setopt(conn, CURLOPT_WRITEHEADER, &PageHeader);
300 curl_easy_setopt(conn, CURLOPT_PROGRESSDATA, this);
301 curl_easy_setopt(conn, CURLOPT_PROGRESSFUNCTION, ProgressFunc);
302 curl_easy_setopt(conn, CURLOPT_CUSTOMREQUEST, "REPORT");
303 curl_easy_setopt(conn, CURLOPT_NOSIGNAL, 1);
304 curl_easy_setopt(conn, CURLOPT_HTTPHEADER, slist);
305 curl_easy_setopt(conn, CURLOPT_CERTINFO, 1);
306 curl_easy_setopt(conn, CURLOPT_POSTFIELDS, query);
307 curl_easy_setopt(conn, CURLOPT_POSTFIELDSIZE, strlen(query));
308 curl_easy_setopt(conn, CURLOPT_SSL_VERIFYHOST, 0);
309 curl_easy_setopt(conn, CURLOPT_SSL_VERIFYPEER, 0);
311 claconncode = (curl_easy_perform(conn));
317 if (MatchingCert == FALSE){
319 claconncode = CURLE_SSL_CACERT;
320 return ContactListFinal;
324 curl_easy_cleanup(sslerrconn);
330 // Sort out SSL error.
332 // When SSL cert error occurs, connect again and fetch certificates.
333 // Display a message to the user explaining that an invalid
334 // certificate has been given and let the user decide what
337 if (claconncode == CURLE_OK){
339 } else if (claconncode == CURLE_SSL_CACERT || claconncode == CURLE_PEER_FAILED_VERIFICATION){
342 sslerrconn = curl_easy_init();
343 CURLcode sslerrconncode;
345 wxString ServerAddressOnly = wxT("https://") + ServerAddress + wxT(":") + wxString::Format(wxT("%i"), ServerPort) + wxT("/");
347 // Replace conn with sslerrconn!
349 curl_easy_setopt(sslerrconn, CURLOPT_URL, (const char*)ServerAddressOnly.mb_str(wxConvUTF8));
350 curl_easy_setopt(sslerrconn, CURLOPT_NOPROGRESS, 0);
351 curl_easy_setopt(sslerrconn, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
352 curl_easy_setopt(sslerrconn, CURLOPT_TIMEOUT, 60);
353 curl_easy_setopt(sslerrconn, CURLOPT_FAILONERROR, TRUE);
354 curl_easy_setopt(sslerrconn, CURLOPT_USERAGENT, XSDAB_USERAGENT);
355 curl_easy_setopt(sslerrconn, CURLOPT_WRITEFUNCTION, WritebackFunc);
356 curl_easy_setopt(sslerrconn, CURLOPT_WRITEDATA, &PageData);
357 curl_easy_setopt(sslerrconn, CURLOPT_WRITEHEADER, &PageHeader);
358 curl_easy_setopt(sslerrconn, CURLOPT_PROGRESSDATA, this);
359 curl_easy_setopt(sslerrconn, CURLOPT_PROGRESSFUNCTION, ProgressFunc);
360 curl_easy_setopt(sslerrconn, CURLOPT_NOSIGNAL, 1);
361 curl_easy_setopt(sslerrconn, CURLOPT_SSL_VERIFYPEER, 0);
362 curl_easy_setopt(sslerrconn, CURLOPT_CERTINFO, 1);
364 #if defined(__APPLE__)
365 SetConnectionObject(sslerrconn);
368 sslerrconncode = (curl_easy_perform(sslerrconn));
370 SSLCertCol = BuildSSLCollection(sslerrconn);
371 SSLCertCol.SuccessCode = 1;
373 return ContactListFinal;
375 } else if (claconncode == CURLE_HTTP_RETURNED_ERROR){
377 fprintf(stderr, "curl_easy_perform() failed: %s\n",
378 curl_easy_strerror(claconncode));
380 curl_easy_getinfo(conn, CURLINFO_RESPONSE_CODE, &http_code);
381 fprintf(stderr, "Error code was: %d\n", http_code);
383 return ContactListFinal;
387 fprintf(stderr, "curl_easy_perform() failed: %s\n",
388 curl_easy_strerror(claconncode));
390 curl_easy_getinfo(conn, CURLINFO_RESPONSE_CODE, &http_code);
391 fprintf(stderr, "Error code was: %d\n", http_code);
393 return ContactListFinal;
397 SSLCertCol = BuildSSLCollection(conn);
403 wxString EmptyString;
405 curl_easy_setopt(conn, CURLOPT_URL, (const char*)ServerAddressNormal.mb_str(wxConvUTF8));
406 curl_easy_setopt(conn, CURLOPT_NOPROGRESS, 0);
407 curl_easy_setopt(conn, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
408 curl_easy_setopt(conn, CURLOPT_TIMEOUT, 60);
409 curl_easy_setopt(conn, CURLOPT_FAILONERROR, TRUE);
410 curl_easy_setopt(conn, CURLOPT_USERAGENT, XSDAB_USERAGENT);
411 curl_easy_setopt(conn, CURLOPT_USERPWD, (const char*)ServerAuth.mb_str(wxConvUTF8));
412 curl_easy_setopt(conn, CURLOPT_WRITEFUNCTION, WritebackFunc);
413 curl_easy_setopt(conn, CURLOPT_WRITEDATA, &PageData);
414 curl_easy_setopt(conn, CURLOPT_WRITEHEADER, &PageHeader);
415 curl_easy_setopt(conn, CURLOPT_PROGRESSDATA, this);
416 curl_easy_setopt(conn, CURLOPT_PROGRESSFUNCTION, ProgressFunc);
417 curl_easy_setopt(conn, CURLOPT_CUSTOMREQUEST, "REPORT");
418 curl_easy_setopt(conn, CURLOPT_NOSIGNAL, 1);
419 curl_easy_setopt(conn, CURLOPT_HTTPHEADER, slist);
420 curl_easy_setopt(conn, CURLOPT_POSTFIELDS, query);
421 curl_easy_setopt(conn, CURLOPT_POSTFIELDSIZE, strlen(query));
426 claconncode = (curl_easy_perform(conn));
428 if (claconncode == CURLE_OK){
432 } else if (claconncode == CURLE_HTTP_RETURNED_ERROR){
434 fprintf(stderr, "curl_easy_perform() failed: %s\n",
435 curl_easy_strerror(claconncode));
437 curl_easy_getinfo(conn, CURLINFO_RESPONSE_CODE, &http_code);
438 fprintf(stderr, "Error code was: %i\n", http_code);
440 return ContactListFinal;
444 fprintf(stderr, "curl_easy_perform() failed: %s\n",
445 curl_easy_strerror(claconncode));
447 curl_easy_getinfo(conn, CURLINFO_RESPONSE_CODE, &http_code);
448 fprintf(stderr, "Error code was: %i\n", http_code);
450 return ContactListFinal;
456 xmlDocPtr xmlCardDAVDoc;
457 xmlCardDAVDoc = xmlReadMemory(PageData.mb_str(wxConvUTF8), (int)PageData.Len(), "noname.xml", NULL, 0);
459 xmlNodePtr nodeLevel1;
460 xmlNodePtr nodeLevel2;
461 xmlNodePtr nodeLevel3;
462 xmlNodePtr nodeLevel4;
463 xmlNodePtr nodeLevel5;
464 xmlNodePtr nodeLevel6;
466 xmlNodePtr nodeStatusLv1;
467 xmlNodePtr nodeStatusLv2;
469 std::map<wxString,wxString> xmlDataMap;
470 std::map<wxString,wxString> ServerETagData;
472 wxString DataFilename;
473 wxString DataSyncToken;
476 bool SyncTokenFound = FALSE;
478 std::string xmlStringSafe;
480 // Tranverse through the catacombs of the response to get our ETag for the file and
481 // the server syncronisation token.
483 // Start by getting all the server ETag data.
485 for (nodeLevel1 = xmlCardDAVDoc->children;
487 nodeLevel1 = nodeLevel1->next)
490 for (nodeLevel2 = nodeLevel1->children;
492 nodeLevel2 = nodeLevel2->next)
495 for (nodeLevel3 = nodeLevel2->children;
497 nodeLevel3 = nodeLevel3->next)
501 bool HREFFound = FALSE;
502 bool ETagFound = FALSE;
503 bool HTTPStatus = FALSE;
505 if (!xmlStrcmp(nodeLevel3->name, (const xmlChar *)"href") ||
506 !xmlStrcmp(nodeLevel3->name, (const xmlChar *)"d:href") ||
507 !xmlStrcmp(nodeLevel3->name, (const xmlChar *)"D:href")
512 for (nodeLevel4 = nodeLevel3->children;
514 nodeLevel4 = nodeLevel4->next)
517 if (!xmlStrcmp(nodeLevel4->name, (const xmlChar *)"text") ||
518 !xmlStrcmp(nodeLevel4->name, (const xmlChar *)"d:text") ||
519 !xmlStrcmp(nodeLevel4->name, (const xmlChar *)"D:text")
522 DataFilename = wxString::FromUTF8((const char*)nodeLevel4->content);
523 wxStringTokenizer wSTDFilename(DataFilename, wxT("/"));
525 while (wSTDFilename.HasMoreTokens()){
527 DataFilename = wSTDFilename.GetNextToken();
542 for (nodeLevel4 = nodeLevel3->children;
544 nodeLevel4 = nodeLevel4->next)
547 for (nodeStatusLv1 = nodeLevel3->children;
548 nodeStatusLv1 != NULL;
549 nodeStatusLv1 = nodeStatusLv1->next)
552 if (wxString::FromUTF8((const char*)nodeStatusLv1->content) == wxT("HTTP/1.1 404 Not Found")){
560 if ((!xmlStrcmp(nodeStatusLv1->name, (const xmlChar *)"status") ||
561 !xmlStrcmp(nodeStatusLv1->name, (const xmlChar *)"d:status") ||
562 !xmlStrcmp(nodeStatusLv1->name, (const xmlChar *)"D:status")) && HTTPStatus == FALSE)
567 for (nodeStatusLv2 = nodeStatusLv1->children;
568 nodeStatusLv2 != NULL;
569 nodeStatusLv2 = nodeStatusLv2->next)
572 if (!xmlStrcmp(nodeStatusLv2->name, (const xmlChar *)"text") ||
573 !xmlStrcmp(nodeStatusLv2->name, (const xmlChar *)"d:text") ||
574 !xmlStrcmp(nodeStatusLv2->name, (const xmlChar *)"D:text")
577 if (wxString::FromUTF8((const char*)nodeStatusLv2->content) == wxT("HTTP/1.1 200 OK")){
583 // This is currently in a WebDAV draft and may hopefully be enabled when this changes.
585 //} else if (wxString::FromUTF8((const char*)nodeStatusLv2->content) == wxT("HTTP/1.1 201 Created")){
587 // DataFileStatus = 0;
602 for (nodeLevel5 = nodeLevel4->children;
604 nodeLevel5 = nodeLevel5->next)
607 if (!xmlStrcmp(nodeLevel5->name, (const xmlChar *)"getetag") ||
608 !xmlStrcmp(nodeLevel5->name, (const xmlChar *)"d:getetag") ||
609 !xmlStrcmp(nodeLevel5->name, (const xmlChar *)"D:getetag")
612 for (nodeLevel6 = nodeLevel5->children;
614 nodeLevel6 = nodeLevel6->next)
617 // Strip the quotes from the ETag.
619 ETagData = wxString::FromUTF8((const char*)nodeLevel6->content);
620 if (ETagData.Mid(0, 1) == wxT("\"") && ETagData.Mid((ETagData.Len() - 1), 1) == wxT("\"")){
622 ETagData.Remove(0, 1);
623 ETagData.RemoveLast();
639 if (HREFFound == TRUE && ETagFound == TRUE && HTTPStatus == TRUE){
641 // Add to the map data.
645 SData.ETagData = ETagData;
646 SData.DataFlag = DataFileStatus;
648 ContactListFinal.ListData.insert(std::make_pair(DataFilename, SData));
660 if ((!xmlStrcmp(nodeLevel2->name, (const xmlChar *)"sync-token") ||
661 !xmlStrcmp(nodeLevel2->name, (const xmlChar *)"d:sync-token") ||
662 !xmlStrcmp(nodeLevel2->name, (const xmlChar *)"D:sync-token")) &&
663 SyncTokenFound == FALSE
666 for (nodeLevel3 = nodeLevel2->children;
668 nodeLevel3 = nodeLevel3->next)
671 if (!xmlStrcmp(nodeLevel3->name, (const xmlChar *)"text") ||
672 !xmlStrcmp(nodeLevel3->name, (const xmlChar *)"d:text") ||
673 !xmlStrcmp(nodeLevel3->name, (const xmlChar *)"D:text")
676 DataSyncToken = wxString::FromUTF8((const char*)nodeLevel3->content);
678 SyncTokenFound = TRUE;
690 for (nodeLevel1 = xmlCardDAVDoc->children;
692 nodeLevel1 = nodeLevel1->next)
695 for (nodeLevel2 = nodeLevel1->children;
697 nodeLevel2 = nodeLevel2->next)
701 bool HREFFound = FALSE;
702 bool ETagFound = FALSE;
703 bool HTTPStatus = FALSE;
705 for (nodeLevel3 = nodeLevel2->children;
707 nodeLevel3 = nodeLevel3->next)
710 if (!xmlStrcmp(nodeLevel3->name, (const xmlChar *)"href") ||
711 !xmlStrcmp(nodeLevel3->name, (const xmlChar *)"d:href") ||
712 !xmlStrcmp(nodeLevel3->name, (const xmlChar *)"D:href")
717 for (nodeLevel4 = nodeLevel3->children;
719 nodeLevel4 = nodeLevel4->next)
722 if (!xmlStrcmp(nodeLevel4->name, (const xmlChar *)"text") ||
723 !xmlStrcmp(nodeLevel4->name, (const xmlChar *)"d:text") ||
724 !xmlStrcmp(nodeLevel4->name, (const xmlChar *)"D:text")
727 DataFilename = wxString::FromUTF8((const char*)nodeLevel4->content);
728 wxStringTokenizer wSTDFilename(DataFilename, wxT("/"));
730 while (wSTDFilename.HasMoreTokens()){
732 DataFilename = wSTDFilename.GetNextToken();
747 for (nodeLevel4 = nodeLevel3->children;
749 nodeLevel4 = nodeLevel4->next)
752 for (nodeStatusLv1 = nodeLevel3->children;
753 nodeStatusLv1 != NULL;
754 nodeStatusLv1 = nodeStatusLv1->next)
757 if (wxString::FromUTF8((const char*)nodeStatusLv1->content) == wxT("HTTP/1.1 404 Not Found")){
765 if ((!xmlStrcmp(nodeStatusLv1->name, (const xmlChar *)"status") ||
766 !xmlStrcmp(nodeStatusLv1->name, (const xmlChar *)"d:status") ||
767 !xmlStrcmp(nodeStatusLv1->name, (const xmlChar *)"D:status")) && HTTPStatus == FALSE)
772 for (nodeStatusLv2 = nodeStatusLv1->children;
773 nodeStatusLv2 != NULL;
774 nodeStatusLv2 = nodeStatusLv2->next)
777 if (!xmlStrcmp(nodeStatusLv2->name, (const xmlChar *)"text") ||
778 !xmlStrcmp(nodeStatusLv2->name, (const xmlChar *)"d:text") ||
779 !xmlStrcmp(nodeStatusLv2->name, (const xmlChar *)"D:text")
782 if (wxString::FromUTF8((const char*)nodeStatusLv2->content) == wxT("HTTP/1.1 200 OK")){
788 // This is currently in a WebDAV draft and may hopefully be enabled when this changes.
790 //} else if (wxString::FromUTF8((const char*)nodeStatusLv2->content) == wxT("HTTP/1.1 201 Created")){
792 // DataFileStatus = 0;
807 for (nodeLevel5 = nodeLevel4->children;
809 nodeLevel5 = nodeLevel5->next)
812 if (!xmlStrcmp(nodeLevel5->name, (const xmlChar *)"getetag") ||
813 !xmlStrcmp(nodeLevel5->name, (const xmlChar *)"d:getetag") ||
814 !xmlStrcmp(nodeLevel5->name, (const xmlChar *)"D:getetag")
817 for (nodeLevel6 = nodeLevel5->children;
819 nodeLevel6 = nodeLevel6->next)
822 // Strip the quotes from the ETag.
824 ETagData = wxString::FromUTF8((const char*)nodeLevel6->content);
825 if (ETagData.Mid(0, 1) == wxT("\"") && ETagData.Mid((ETagData.Len() - 1), 1) == wxT("\"")){
827 ETagData.Remove(0, 1);
828 ETagData.RemoveLast();
846 if (HREFFound == TRUE && HTTPStatus == TRUE && DataFileStatus == 2){
850 SData.ETagData = wxT("");
851 SData.DataFlag = DataFileStatus;
853 ContactListFinal.ListData.insert(std::make_pair(DataFilename, SData));
857 if (HREFFound == TRUE && ETagFound == TRUE && HTTPStatus == TRUE){
859 // Add to the map data.
863 SData.ETagData = ETagData;
864 SData.DataFlag = DataFileStatus;
866 ContactListFinal.ListData.insert(std::make_pair(DataFilename, SData));
875 DataFilename.Clear();
877 if ((!xmlStrcmp(nodeLevel2->name, (const xmlChar *)"sync-token") ||
878 !xmlStrcmp(nodeLevel2->name, (const xmlChar *)"d:sync-token") ||
879 !xmlStrcmp(nodeLevel2->name, (const xmlChar *)"D:sync-token")) &&
880 SyncTokenFound == FALSE
883 for (nodeLevel3 = nodeLevel2->children;
885 nodeLevel3 = nodeLevel3->next)
888 if (!xmlStrcmp(nodeLevel3->name, (const xmlChar *)"text") ||
889 !xmlStrcmp(nodeLevel3->name, (const xmlChar *)"d:text") ||
890 !xmlStrcmp(nodeLevel3->name, (const xmlChar *)"D:text")
893 DataSyncToken = wxString::FromUTF8((const char*)nodeLevel3->content);
895 SyncTokenFound = TRUE;
907 // Get the sync token.
909 if (SyncTokenFound == TRUE){
911 ContactListFinal.SyncToken = DataSyncToken;
917 SleepFor(2000000000);
919 xmlFreeDoc(xmlCardDAVDoc);
920 curl_easy_cleanup(conn);
922 SyncDataBuffer.reset();
924 // Get the first result.
926 return ContactListFinal;