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__)
55 SetConnectionObject(conn);
59 struct CardDAVCURLPasser {
62 bool HeaderMode = TRUE;
64 } CardDAVHeader, CardDAVFooter;
66 CardDAVHeader.Data = this;
67 CardDAVHeader.HeaderMode = TRUE;
69 CardDAVFooter.Data = this;
70 CardDAVFooter.HeaderMode = FALSE;
75 ServerAddressURL = ServerAddress + wxT(":") + wxString::Format(wxT("%i"), ServerPort) + ServerPrefix;
76 ServerAddressSSL = wxT("https://") + ServerAddressURL;
77 ServerAddressNormal = wxT("http://") + ServerAddressURL;
79 ServerAuth = ServerUser + wxT(":") + ServerPass;
81 // Load the sync token file (if it exists).
83 wxCharBuffer SyncDataBuffer;
90 if (!SyncTokenInc.IsEmpty()){
92 SyncData = wxT("<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n");
93 SyncData.Append(wxT("<D:sync-collection xmlns:D=\"DAV:\"\n"));
94 SyncData.Append(wxT(" xmlns:C=\"urn:ietf:params:xml:ns:carddav\">\n"));
95 SyncData.Append(wxT("<D:sync-token>"));
96 SyncData.Append(SyncTokenInc);
97 SyncData.Append(wxT("</D:sync-token>\n"));
98 SyncData.Append(wxT("<D:sync-level>1</D:sync-level>\n"));
99 SyncData.Append(wxT("<D:prop>\n"));
100 SyncData.Append(wxT(" <D:getetag/>\n"));
101 SyncData.Append(wxT("</D:prop>\n"));
102 SyncData.Append(wxT("</D:sync-collection>"));
104 SyncDataBuffer = SyncData.ToUTF8();
108 SyncData = wxT("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
109 SyncData.Append(wxT("<D:sync-collection xmlns:D=\"DAV:\""));
110 SyncData.Append(wxT(" xmlns:C=\"urn:ietf:params:xml:ns:carddav\">\n"));
111 SyncData.Append(wxT("<D:sync-token/>\n"));
112 SyncData.Append(wxT("<D:sync-level>1</D:sync-level>\n"));
113 SyncData.Append(wxT("<D:prop>\n"));
114 SyncData.Append(wxT(" <D:getetag/>\n"));
115 SyncData.Append(wxT("</D:prop>\n"));
116 SyncData.Append(wxT("</D:sync-collection>\n"));
118 SyncDataBuffer = SyncData.ToUTF8();
122 const char* query = SyncDataBuffer.data();
126 std::map<int,int>::iterator ActIter;
127 struct UploadDataStruc UploadData;
129 ActIter = ActivityListPtr->find((int)ItemIndex);
131 curl_slist *slist = NULL;
133 slist = curl_slist_append(slist, "Depth: 1");
137 wxString ServerCertFilename;
138 bool MatchingCert = FALSE;
140 curl_easy_setopt(conn, CURLOPT_URL, (const char*)ServerAddressSSL.mb_str(wxConvUTF8));
141 curl_easy_setopt(conn, CURLOPT_NOPROGRESS, 0);
142 curl_easy_setopt(conn, CURLOPT_HTTPAUTH, CURLAUTH_ANYSAFE);
143 curl_easy_setopt(conn, CURLOPT_TIMEOUT, 60);
144 curl_easy_setopt(conn, CURLOPT_FAILONERROR, TRUE);
145 curl_easy_setopt(conn, CURLOPT_USERAGENT, XSDAB_USERAGENT);
146 curl_easy_setopt(conn, CURLOPT_USERPWD, (const char*)ServerAuth.mb_str(wxConvUTF8));
147 curl_easy_setopt(conn, CURLOPT_WRITEFUNCTION, WritebackFunc);
148 curl_easy_setopt(conn, CURLOPT_WRITEDATA, &PageData);
149 curl_easy_setopt(conn, CURLOPT_WRITEHEADER, &PageHeader);
150 curl_easy_setopt(conn, CURLOPT_PROGRESSDATA, this);
151 curl_easy_setopt(conn, CURLOPT_PROGRESSFUNCTION, ProgressFunc);
152 curl_easy_setopt(conn, CURLOPT_CUSTOMREQUEST, "REPORT");
153 curl_easy_setopt(conn, CURLOPT_NOSIGNAL, 1);
154 curl_easy_setopt(conn, CURLOPT_HTTPHEADER, slist);
155 curl_easy_setopt(conn, CURLOPT_CERTINFO, 1);
157 #if defined(__APPLE__)
161 ServerCertFilename = GetAccountDir(ServerAccount, TRUE);
163 if (wxFile::Exists(ServerCertFilename) == TRUE){
165 curl_easy_setopt(conn, CURLOPT_SSL_VERIFYPEER, 1);
166 curl_easy_setopt(conn, CURLOPT_SSL_VERIFYHOST, 2);
167 curl_easy_setopt(conn, CURLOPT_CAINFO, (const char*)ServerCertFilename.mb_str(wxConvUTF8));
173 curl_easy_setopt(conn, CURLOPT_POSTFIELDS, query);
174 curl_easy_setopt(conn, CURLOPT_POSTFIELDSIZE, strlen(query));
176 claconncode = (curl_easy_perform(conn));
178 // If CURLE_PEER_FAILED_VERIFICATION is returned, retry without
179 // the local certificate in use.
181 if (claconncode == CURLE_PEER_FAILED_VERIFICATION){
183 curl_easy_cleanup(conn);
184 conn = curl_easy_init();
186 curl_easy_setopt(conn, CURLOPT_URL, (const char*)ServerAddressSSL.mb_str(wxConvUTF8));
187 curl_easy_setopt(conn, CURLOPT_NOPROGRESS, 0);
188 curl_easy_setopt(conn, CURLOPT_HTTPAUTH, CURLAUTH_ANYSAFE);
189 curl_easy_setopt(conn, CURLOPT_TIMEOUT, 60);
190 curl_easy_setopt(conn, CURLOPT_FAILONERROR, TRUE);
191 curl_easy_setopt(conn, CURLOPT_USERAGENT, XSDAB_USERAGENT);
192 curl_easy_setopt(conn, CURLOPT_USERPWD, (const char*)ServerAuth.mb_str(wxConvUTF8));
193 curl_easy_setopt(conn, CURLOPT_WRITEFUNCTION, WritebackFunc);
194 curl_easy_setopt(conn, CURLOPT_WRITEDATA, &PageData);
195 curl_easy_setopt(conn, CURLOPT_WRITEHEADER, &PageHeader);
196 curl_easy_setopt(conn, CURLOPT_PROGRESSDATA, this);
197 curl_easy_setopt(conn, CURLOPT_PROGRESSFUNCTION, ProgressFunc);
198 curl_easy_setopt(conn, CURLOPT_CUSTOMREQUEST, "REPORT");
199 curl_easy_setopt(conn, CURLOPT_NOSIGNAL, 1);
200 curl_easy_setopt(conn, CURLOPT_HTTPHEADER, slist);
201 curl_easy_setopt(conn, CURLOPT_CERTINFO, 1);
202 curl_easy_setopt(conn, CURLOPT_POSTFIELDS, query);
203 curl_easy_setopt(conn, CURLOPT_POSTFIELDSIZE, strlen(query));
205 claconncode = (curl_easy_perform(conn));
207 // If claconncode is CURLE_OK then delete the certificate file as that
208 // is no longer needed.
210 if (claconncode == CURLE_OK){
212 // Delete the certificate file.
214 wxRemoveFile(ServerCertFilename);
220 // Check if it fails with a CURLE_SSL_CACERT then compare
221 // the certificates as PEM files.
223 #if defined(__APPLE__)
227 if (claconncode == CURLE_SSL_CACERT && wxFile::Exists(ServerCertFilename) == TRUE){
230 sslerrconn = curl_easy_init();
231 CURLcode sslerrconncode;
233 wxString ServerAddressOnly = wxT("https://") + ServerAddress + wxT(":") + wxString::Format(wxT("%i"), ServerPort) + wxT("/");
235 curl_easy_setopt(sslerrconn, CURLOPT_URL, (const char*)ServerAddressOnly.mb_str(wxConvUTF8));
236 curl_easy_setopt(sslerrconn, CURLOPT_NOPROGRESS, 0);
237 curl_easy_setopt(sslerrconn, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
238 curl_easy_setopt(sslerrconn, CURLOPT_TIMEOUT, 60);
239 curl_easy_setopt(sslerrconn, CURLOPT_FAILONERROR, TRUE);
240 curl_easy_setopt(sslerrconn, CURLOPT_USERAGENT, XSDAB_USERAGENT);
241 curl_easy_setopt(sslerrconn, CURLOPT_WRITEFUNCTION, WritebackFunc);
242 curl_easy_setopt(sslerrconn, CURLOPT_WRITEDATA, &PageData);
243 curl_easy_setopt(sslerrconn, CURLOPT_WRITEHEADER, &PageHeader);
244 curl_easy_setopt(sslerrconn, CURLOPT_PROGRESSDATA, this);
245 curl_easy_setopt(sslerrconn, CURLOPT_PROGRESSFUNCTION, ProgressFunc);
246 curl_easy_setopt(sslerrconn, CURLOPT_NOSIGNAL, 1);
247 curl_easy_setopt(sslerrconn, CURLOPT_SSL_VERIFYPEER, 0);
248 curl_easy_setopt(sslerrconn, CURLOPT_CERTINFO, 1);
250 wxString SSLLocalData;
251 wxString SSLServerData;
253 sslerrconncode = (curl_easy_perform(sslerrconn));
255 SSLCertCol = BuildSSLCollection(sslerrconn);
256 std::map<int, SSLCertData>::iterator SSLCDIter = SSLCertCol.SSLCollection.find(0);
257 std::multimap<wxString,wxString>::iterator SSLDataIter = SSLCDIter->second.CertData.find(wxT("Cert"));
259 wxFFile SSLLocalFile;
261 #if wxABI_VERSION < 20900
262 SSLLocalFile.Open(ServerCertFilename.c_str(), wxT("r"));
264 SSLLocalFile.Open(ServerCertFilename, wxT("r"));
267 // Load the recovery database for tasks not done.
269 if (SSLLocalFile.IsOpened() == TRUE){
271 // Check if we are using wxWidgets version 2.8 or less and
272 // execute the required command accordingly.
274 SSLLocalFile.ReadAll(&SSLLocalData, wxConvAuto());
279 SSLServerData = SSLDataIter->second;
281 if (SSLLocalData == SSLServerData){
283 // Server key matches with local key so retry with CURLOPT_SSL_VERIFYPEER
284 // and CURLOPT_SSL_VERIFYHOST off.
286 curl_easy_cleanup(conn);
287 conn = curl_easy_init();
292 curl_easy_setopt(conn, CURLOPT_URL, (const char*)ServerAddressSSL.mb_str(wxConvUTF8));
293 curl_easy_setopt(conn, CURLOPT_NOPROGRESS, 0);
294 curl_easy_setopt(conn, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
295 curl_easy_setopt(conn, CURLOPT_TIMEOUT, 60);
296 curl_easy_setopt(conn, CURLOPT_FAILONERROR, TRUE);
297 curl_easy_setopt(conn, CURLOPT_USERAGENT, XSDAB_USERAGENT);
298 curl_easy_setopt(conn, CURLOPT_USERPWD, (const char*)ServerAuth.mb_str(wxConvUTF8));
299 curl_easy_setopt(conn, CURLOPT_WRITEFUNCTION, WritebackFunc);
300 curl_easy_setopt(conn, CURLOPT_WRITEDATA, &PageData);
301 curl_easy_setopt(conn, CURLOPT_WRITEHEADER, &PageHeader);
302 curl_easy_setopt(conn, CURLOPT_PROGRESSDATA, this);
303 curl_easy_setopt(conn, CURLOPT_PROGRESSFUNCTION, ProgressFunc);
304 curl_easy_setopt(conn, CURLOPT_CUSTOMREQUEST, "REPORT");
305 curl_easy_setopt(conn, CURLOPT_NOSIGNAL, 1);
306 curl_easy_setopt(conn, CURLOPT_HTTPHEADER, slist);
307 curl_easy_setopt(conn, CURLOPT_CERTINFO, 1);
308 curl_easy_setopt(conn, CURLOPT_POSTFIELDS, query);
309 curl_easy_setopt(conn, CURLOPT_POSTFIELDSIZE, strlen(query));
310 curl_easy_setopt(conn, CURLOPT_SSL_VERIFYHOST, 0);
311 curl_easy_setopt(conn, CURLOPT_SSL_VERIFYPEER, 0);
313 claconncode = (curl_easy_perform(conn));
319 if (MatchingCert == FALSE){
321 claconncode = CURLE_SSL_CACERT;
322 return ContactListFinal;
326 curl_easy_cleanup(sslerrconn);
332 // Sort out SSL error.
334 // When SSL cert error occurs, connect again and fetch certificates.
335 // Display a message to the user explaining that an invalid
336 // certificate has been given and let the user decide what
339 if (claconncode == CURLE_OK){
341 } else if (claconncode == CURLE_SSL_CACERT || claconncode == CURLE_PEER_FAILED_VERIFICATION){
344 sslerrconn = curl_easy_init();
345 CURLcode sslerrconncode;
347 wxString ServerAddressOnly = wxT("https://") + ServerAddress + wxT(":") + wxString::Format(wxT("%i"), ServerPort) + wxT("/");
349 // Replace conn with sslerrconn!
351 curl_easy_setopt(sslerrconn, CURLOPT_URL, (const char*)ServerAddressOnly.mb_str(wxConvUTF8));
352 curl_easy_setopt(sslerrconn, CURLOPT_NOPROGRESS, 0);
353 curl_easy_setopt(sslerrconn, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
354 curl_easy_setopt(sslerrconn, CURLOPT_TIMEOUT, 60);
355 curl_easy_setopt(sslerrconn, CURLOPT_FAILONERROR, TRUE);
356 curl_easy_setopt(sslerrconn, CURLOPT_USERAGENT, XSDAB_USERAGENT);
357 curl_easy_setopt(sslerrconn, CURLOPT_WRITEFUNCTION, WritebackFunc);
358 curl_easy_setopt(sslerrconn, CURLOPT_WRITEDATA, &PageData);
359 curl_easy_setopt(sslerrconn, CURLOPT_WRITEHEADER, &PageHeader);
360 curl_easy_setopt(sslerrconn, CURLOPT_PROGRESSDATA, this);
361 curl_easy_setopt(sslerrconn, CURLOPT_PROGRESSFUNCTION, ProgressFunc);
362 curl_easy_setopt(sslerrconn, CURLOPT_NOSIGNAL, 1);
363 curl_easy_setopt(sslerrconn, CURLOPT_SSL_VERIFYPEER, 0);
364 curl_easy_setopt(sslerrconn, CURLOPT_CERTINFO, 1);
366 #if defined(__APPLE__)
368 SetConnectionObject(sslerrconn);
372 sslerrconncode = (curl_easy_perform(sslerrconn));
374 SSLCertCol = BuildSSLCollection(sslerrconn);
375 SSLCertCol.SuccessCode = 1;
377 return ContactListFinal;
379 } else if (claconncode == CURLE_HTTP_RETURNED_ERROR){
381 fprintf(stderr, "curl_easy_perform() failed: %s\n",
382 curl_easy_strerror(claconncode));
384 curl_easy_getinfo(conn, CURLINFO_RESPONSE_CODE, &http_code);
385 fprintf(stderr, "Error code was: %d\n", http_code);
387 return ContactListFinal;
391 fprintf(stderr, "curl_easy_perform() failed: %s\n",
392 curl_easy_strerror(claconncode));
394 curl_easy_getinfo(conn, CURLINFO_RESPONSE_CODE, &http_code);
395 fprintf(stderr, "Error code was: %d\n", http_code);
397 return ContactListFinal;
401 SSLCertCol = BuildSSLCollection(conn);
407 wxString EmptyString;
409 curl_easy_setopt(conn, CURLOPT_URL, (const char*)ServerAddressNormal.mb_str(wxConvUTF8));
410 curl_easy_setopt(conn, CURLOPT_NOPROGRESS, 0);
411 curl_easy_setopt(conn, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
412 curl_easy_setopt(conn, CURLOPT_TIMEOUT, 60);
413 curl_easy_setopt(conn, CURLOPT_FAILONERROR, TRUE);
414 curl_easy_setopt(conn, CURLOPT_USERAGENT, XSDAB_USERAGENT);
415 curl_easy_setopt(conn, CURLOPT_USERPWD, (const char*)ServerAuth.mb_str(wxConvUTF8));
416 curl_easy_setopt(conn, CURLOPT_WRITEFUNCTION, WritebackFunc);
417 curl_easy_setopt(conn, CURLOPT_WRITEDATA, &PageData);
418 curl_easy_setopt(conn, CURLOPT_WRITEHEADER, &PageHeader);
419 curl_easy_setopt(conn, CURLOPT_PROGRESSDATA, this);
420 curl_easy_setopt(conn, CURLOPT_PROGRESSFUNCTION, ProgressFunc);
421 curl_easy_setopt(conn, CURLOPT_CUSTOMREQUEST, "REPORT");
422 curl_easy_setopt(conn, CURLOPT_NOSIGNAL, 1);
423 curl_easy_setopt(conn, CURLOPT_HTTPHEADER, slist);
424 curl_easy_setopt(conn, CURLOPT_POSTFIELDS, query);
425 curl_easy_setopt(conn, CURLOPT_POSTFIELDSIZE, strlen(query));
430 claconncode = (curl_easy_perform(conn));
432 if (claconncode == CURLE_OK){
436 } else if (claconncode == CURLE_HTTP_RETURNED_ERROR){
438 fprintf(stderr, "curl_easy_perform() failed: %s\n",
439 curl_easy_strerror(claconncode));
441 curl_easy_getinfo(conn, CURLINFO_RESPONSE_CODE, &http_code);
442 fprintf(stderr, "Error code was: %i\n", http_code);
444 return ContactListFinal;
448 fprintf(stderr, "curl_easy_perform() failed: %s\n",
449 curl_easy_strerror(claconncode));
451 curl_easy_getinfo(conn, CURLINFO_RESPONSE_CODE, &http_code);
452 fprintf(stderr, "Error code was: %i\n", http_code);
454 return ContactListFinal;
460 xmlDocPtr xmlCardDAVDoc;
461 xmlCardDAVDoc = xmlReadMemory(PageData.mb_str(wxConvUTF8), (int)PageData.Len(), "noname.xml", NULL, 0);
463 xmlNodePtr nodeLevel1;
464 xmlNodePtr nodeLevel2;
465 xmlNodePtr nodeLevel3;
466 xmlNodePtr nodeLevel4;
467 xmlNodePtr nodeLevel5;
468 xmlNodePtr nodeLevel6;
470 xmlNodePtr nodeStatusLv1;
471 xmlNodePtr nodeStatusLv2;
473 std::map<wxString,wxString> xmlDataMap;
474 std::map<wxString,wxString> ServerETagData;
476 wxString DataFilename;
477 wxString DataSyncToken;
480 bool SyncTokenFound = FALSE;
482 std::string xmlStringSafe;
484 // Tranverse through the catacombs of the response to get our ETag for the file and
485 // the server syncronisation token.
487 // Start by getting all the server ETag data.
489 for (nodeLevel1 = xmlCardDAVDoc->children;
491 nodeLevel1 = nodeLevel1->next)
494 for (nodeLevel2 = nodeLevel1->children;
496 nodeLevel2 = nodeLevel2->next)
499 for (nodeLevel3 = nodeLevel2->children;
501 nodeLevel3 = nodeLevel3->next)
505 bool HREFFound = FALSE;
506 bool ETagFound = FALSE;
507 bool HTTPStatus = FALSE;
509 if (!xmlStrcmp(nodeLevel3->name, (const xmlChar *)"href") ||
510 !xmlStrcmp(nodeLevel3->name, (const xmlChar *)"d:href") ||
511 !xmlStrcmp(nodeLevel3->name, (const xmlChar *)"D:href")
516 for (nodeLevel4 = nodeLevel3->children;
518 nodeLevel4 = nodeLevel4->next)
521 if (!xmlStrcmp(nodeLevel4->name, (const xmlChar *)"text") ||
522 !xmlStrcmp(nodeLevel4->name, (const xmlChar *)"d:text") ||
523 !xmlStrcmp(nodeLevel4->name, (const xmlChar *)"D:text")
526 DataFilename = wxString::FromUTF8((const char*)nodeLevel4->content);
527 wxStringTokenizer wSTDFilename(DataFilename, wxT("/"));
529 while (wSTDFilename.HasMoreTokens()){
531 DataFilename = wSTDFilename.GetNextToken();
546 for (nodeLevel4 = nodeLevel3->children;
548 nodeLevel4 = nodeLevel4->next)
551 for (nodeStatusLv1 = nodeLevel3->children;
552 nodeStatusLv1 != NULL;
553 nodeStatusLv1 = nodeStatusLv1->next)
556 if (wxString::FromUTF8((const char*)nodeStatusLv1->content) == wxT("HTTP/1.1 404 Not Found")){
564 if ((!xmlStrcmp(nodeStatusLv1->name, (const xmlChar *)"status") ||
565 !xmlStrcmp(nodeStatusLv1->name, (const xmlChar *)"d:status") ||
566 !xmlStrcmp(nodeStatusLv1->name, (const xmlChar *)"D:status")) && HTTPStatus == FALSE)
571 for (nodeStatusLv2 = nodeStatusLv1->children;
572 nodeStatusLv2 != NULL;
573 nodeStatusLv2 = nodeStatusLv2->next)
576 if (!xmlStrcmp(nodeStatusLv2->name, (const xmlChar *)"text") ||
577 !xmlStrcmp(nodeStatusLv2->name, (const xmlChar *)"d:text") ||
578 !xmlStrcmp(nodeStatusLv2->name, (const xmlChar *)"D:text")
581 if (wxString::FromUTF8((const char*)nodeStatusLv2->content) == wxT("HTTP/1.1 200 OK")){
587 // This is currently in a WebDAV draft and may hopefully be enabled when this changes.
589 //} else if (wxString::FromUTF8((const char*)nodeStatusLv2->content) == wxT("HTTP/1.1 201 Created")){
591 // DataFileStatus = 0;
606 for (nodeLevel5 = nodeLevel4->children;
608 nodeLevel5 = nodeLevel5->next)
611 if (!xmlStrcmp(nodeLevel5->name, (const xmlChar *)"getetag") ||
612 !xmlStrcmp(nodeLevel5->name, (const xmlChar *)"d:getetag") ||
613 !xmlStrcmp(nodeLevel5->name, (const xmlChar *)"D:getetag")
616 for (nodeLevel6 = nodeLevel5->children;
618 nodeLevel6 = nodeLevel6->next)
621 // Strip the quotes from the ETag.
623 ETagData = wxString::FromUTF8((const char*)nodeLevel6->content);
624 if (ETagData.Mid(0, 1) == wxT("\"") && ETagData.Mid((ETagData.Len() - 1), 1) == wxT("\"")){
626 ETagData.Remove(0, 1);
627 ETagData.RemoveLast();
643 if (HREFFound == TRUE && ETagFound == TRUE && HTTPStatus == TRUE){
645 // Add to the map data.
649 SData.ETagData = ETagData;
650 SData.DataFlag = DataFileStatus;
652 ContactListFinal.ListData.insert(std::make_pair(DataFilename, SData));
664 if ((!xmlStrcmp(nodeLevel2->name, (const xmlChar *)"sync-token") ||
665 !xmlStrcmp(nodeLevel2->name, (const xmlChar *)"d:sync-token") ||
666 !xmlStrcmp(nodeLevel2->name, (const xmlChar *)"D:sync-token")) &&
667 SyncTokenFound == FALSE
670 for (nodeLevel3 = nodeLevel2->children;
672 nodeLevel3 = nodeLevel3->next)
675 if (!xmlStrcmp(nodeLevel3->name, (const xmlChar *)"text") ||
676 !xmlStrcmp(nodeLevel3->name, (const xmlChar *)"d:text") ||
677 !xmlStrcmp(nodeLevel3->name, (const xmlChar *)"D:text")
680 DataSyncToken = wxString::FromUTF8((const char*)nodeLevel3->content);
682 SyncTokenFound = TRUE;
694 for (nodeLevel1 = xmlCardDAVDoc->children;
696 nodeLevel1 = nodeLevel1->next)
699 for (nodeLevel2 = nodeLevel1->children;
701 nodeLevel2 = nodeLevel2->next)
705 bool HREFFound = FALSE;
706 bool ETagFound = FALSE;
707 bool HTTPStatus = FALSE;
709 for (nodeLevel3 = nodeLevel2->children;
711 nodeLevel3 = nodeLevel3->next)
714 if (!xmlStrcmp(nodeLevel3->name, (const xmlChar *)"href") ||
715 !xmlStrcmp(nodeLevel3->name, (const xmlChar *)"d:href") ||
716 !xmlStrcmp(nodeLevel3->name, (const xmlChar *)"D:href")
721 for (nodeLevel4 = nodeLevel3->children;
723 nodeLevel4 = nodeLevel4->next)
726 if (!xmlStrcmp(nodeLevel4->name, (const xmlChar *)"text") ||
727 !xmlStrcmp(nodeLevel4->name, (const xmlChar *)"d:text") ||
728 !xmlStrcmp(nodeLevel4->name, (const xmlChar *)"D:text")
731 DataFilename = wxString::FromUTF8((const char*)nodeLevel4->content);
732 wxStringTokenizer wSTDFilename(DataFilename, wxT("/"));
734 while (wSTDFilename.HasMoreTokens()){
736 DataFilename = wSTDFilename.GetNextToken();
751 for (nodeLevel4 = nodeLevel3->children;
753 nodeLevel4 = nodeLevel4->next)
756 for (nodeStatusLv1 = nodeLevel3->children;
757 nodeStatusLv1 != NULL;
758 nodeStatusLv1 = nodeStatusLv1->next)
761 if (wxString::FromUTF8((const char*)nodeStatusLv1->content) == wxT("HTTP/1.1 404 Not Found")){
769 if ((!xmlStrcmp(nodeStatusLv1->name, (const xmlChar *)"status") ||
770 !xmlStrcmp(nodeStatusLv1->name, (const xmlChar *)"d:status") ||
771 !xmlStrcmp(nodeStatusLv1->name, (const xmlChar *)"D:status")) && HTTPStatus == FALSE)
776 for (nodeStatusLv2 = nodeStatusLv1->children;
777 nodeStatusLv2 != NULL;
778 nodeStatusLv2 = nodeStatusLv2->next)
781 if (!xmlStrcmp(nodeStatusLv2->name, (const xmlChar *)"text") ||
782 !xmlStrcmp(nodeStatusLv2->name, (const xmlChar *)"d:text") ||
783 !xmlStrcmp(nodeStatusLv2->name, (const xmlChar *)"D:text")
786 if (wxString::FromUTF8((const char*)nodeStatusLv2->content) == wxT("HTTP/1.1 200 OK")){
792 // This is currently in a WebDAV draft and may hopefully be enabled when this changes.
794 //} else if (wxString::FromUTF8((const char*)nodeStatusLv2->content) == wxT("HTTP/1.1 201 Created")){
796 // DataFileStatus = 0;
811 for (nodeLevel5 = nodeLevel4->children;
813 nodeLevel5 = nodeLevel5->next)
816 if (!xmlStrcmp(nodeLevel5->name, (const xmlChar *)"getetag") ||
817 !xmlStrcmp(nodeLevel5->name, (const xmlChar *)"d:getetag") ||
818 !xmlStrcmp(nodeLevel5->name, (const xmlChar *)"D:getetag")
821 for (nodeLevel6 = nodeLevel5->children;
823 nodeLevel6 = nodeLevel6->next)
826 // Strip the quotes from the ETag.
828 ETagData = wxString::FromUTF8((const char*)nodeLevel6->content);
829 if (ETagData.Mid(0, 1) == wxT("\"") && ETagData.Mid((ETagData.Len() - 1), 1) == wxT("\"")){
831 ETagData.Remove(0, 1);
832 ETagData.RemoveLast();
850 if (HREFFound == TRUE && HTTPStatus == TRUE && DataFileStatus == 2){
854 SData.ETagData = wxT("");
855 SData.DataFlag = DataFileStatus;
857 ContactListFinal.ListData.insert(std::make_pair(DataFilename, SData));
861 if (HREFFound == TRUE && ETagFound == TRUE && HTTPStatus == TRUE){
863 // Add to the map data.
867 SData.ETagData = ETagData;
868 SData.DataFlag = DataFileStatus;
870 ContactListFinal.ListData.insert(std::make_pair(DataFilename, SData));
879 DataFilename.Clear();
881 if ((!xmlStrcmp(nodeLevel2->name, (const xmlChar *)"sync-token") ||
882 !xmlStrcmp(nodeLevel2->name, (const xmlChar *)"d:sync-token") ||
883 !xmlStrcmp(nodeLevel2->name, (const xmlChar *)"D:sync-token")) &&
884 SyncTokenFound == FALSE
887 for (nodeLevel3 = nodeLevel2->children;
889 nodeLevel3 = nodeLevel3->next)
892 if (!xmlStrcmp(nodeLevel3->name, (const xmlChar *)"text") ||
893 !xmlStrcmp(nodeLevel3->name, (const xmlChar *)"d:text") ||
894 !xmlStrcmp(nodeLevel3->name, (const xmlChar *)"D:text")
897 DataSyncToken = wxString::FromUTF8((const char*)nodeLevel3->content);
899 SyncTokenFound = TRUE;
911 // Get the sync token.
913 if (SyncTokenFound == TRUE){
915 ContactListFinal.SyncToken = DataSyncToken;
921 SleepFor(2000000000);
923 xmlFreeDoc(xmlCardDAVDoc);
924 curl_easy_cleanup(conn);
926 SyncDataBuffer.reset();
928 // Get the first result.
930 return ContactListFinal;