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 struct CardDAVCURLPasser {
56 bool HeaderMode = TRUE;
58 } CardDAVHeader, CardDAVFooter;
60 CardDAVHeader.Data = this;
61 CardDAVHeader.HeaderMode = TRUE;
63 CardDAVFooter.Data = this;
64 CardDAVFooter.HeaderMode = FALSE;
69 ServerAddressURL = ServerAddress + wxT(":") + wxString::Format(wxT("%i"), ServerPort) + wxT("/") + ServerPrefix + wxT("/");
70 ServerAddressSSL = wxT("https://") + ServerAddressURL;
71 ServerAddressNormal = wxT("http://") + ServerAddressURL;
73 ServerAuth = ServerUser + wxT(":") + ServerPass;
75 // Load the sync token file (if it exists).
77 wxCharBuffer SyncDataBuffer;
84 if (!SyncTokenInc.IsEmpty()){
86 SyncData = wxT("<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n");
87 SyncData.Append(wxT("<D:sync-collection xmlns:D=\"DAV:\"\n"));
88 SyncData.Append(wxT(" xmlns:C=\"urn:ietf:params:xml:ns:carddav\">\n"));
89 SyncData.Append(wxT("<D:sync-token>"));
90 SyncData.Append(SyncTokenInc);
91 SyncData.Append(wxT("</D:sync-token>\n"));
92 SyncData.Append(wxT("<D:sync-level>1</D:sync-level>\n"));
93 SyncData.Append(wxT("<D:prop>\n"));
94 SyncData.Append(wxT(" <D:getetag/>\n"));
95 SyncData.Append(wxT("</D:prop>\n"));
96 SyncData.Append(wxT("</D:sync-collection>"));
98 SyncDataBuffer = SyncData.ToUTF8();
102 SyncData = wxT("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
103 SyncData.Append(wxT("<D:sync-collection xmlns:D=\"DAV:\""));
104 SyncData.Append(wxT(" xmlns:C=\"urn:ietf:params:xml:ns:carddav\">\n"));
105 SyncData.Append(wxT("<D:sync-token/>\n"));
106 SyncData.Append(wxT("<D:sync-level>1</D:sync-level>\n"));
107 SyncData.Append(wxT("<D:prop>\n"));
108 SyncData.Append(wxT(" <D:getetag/>\n"));
109 SyncData.Append(wxT("</D:prop>\n"));
110 SyncData.Append(wxT("</D:sync-collection>\n"));
112 SyncDataBuffer = SyncData.ToUTF8();
116 const char* query = SyncDataBuffer.data();
120 std::map<int,int>::iterator ActIter;
121 struct UploadDataStruc UploadData;
123 ActIter = ActivityListPtr->find((int)ItemIndex);
125 curl_slist *slist = NULL;
127 slist = curl_slist_append(slist, "Depth: 1");
131 wxString ServerCertFilename;
132 bool MatchingCert = FALSE;
134 curl_easy_setopt(conn, CURLOPT_URL, (const char*)ServerAddressSSL.mb_str(wxConvUTF8));
135 curl_easy_setopt(conn, CURLOPT_NOPROGRESS, 0);
136 curl_easy_setopt(conn, CURLOPT_HTTPAUTH, CURLAUTH_ANYSAFE);
137 curl_easy_setopt(conn, CURLOPT_TIMEOUT, 60);
138 curl_easy_setopt(conn, CURLOPT_FAILONERROR, TRUE);
139 curl_easy_setopt(conn, CURLOPT_USERAGENT, XSDAB_USERAGENT);
140 curl_easy_setopt(conn, CURLOPT_USERPWD, (const char*)ServerAuth.mb_str(wxConvUTF8));
141 curl_easy_setopt(conn, CURLOPT_WRITEFUNCTION, WritebackFunc);
142 curl_easy_setopt(conn, CURLOPT_WRITEDATA, &PageData);
143 curl_easy_setopt(conn, CURLOPT_WRITEHEADER, &PageHeader);
144 curl_easy_setopt(conn, CURLOPT_PROGRESSDATA, this);
145 curl_easy_setopt(conn, CURLOPT_PROGRESSFUNCTION, ProgressFunc);
146 curl_easy_setopt(conn, CURLOPT_CUSTOMREQUEST, "REPORT");
147 curl_easy_setopt(conn, CURLOPT_NOSIGNAL, 1);
148 curl_easy_setopt(conn, CURLOPT_HTTPHEADER, slist);
149 curl_easy_setopt(conn, CURLOPT_CERTINFO, 1);
151 ServerCertFilename = GetAccountDir(ServerAccount, TRUE);
153 if (wxFile::Exists(ServerCertFilename) == TRUE){
155 curl_easy_setopt(conn, CURLOPT_SSL_VERIFYPEER, 1);
156 curl_easy_setopt(conn, CURLOPT_SSL_VERIFYHOST, 2);
157 curl_easy_setopt(conn, CURLOPT_CAINFO, (const char*)ServerCertFilename.mb_str(wxConvUTF8));
161 curl_easy_setopt(conn, CURLOPT_POSTFIELDS, query);
162 curl_easy_setopt(conn, CURLOPT_POSTFIELDSIZE, strlen(query));
164 claconncode = (curl_easy_perform(conn));
166 // If CURLE_PEER_FAILED_VERIFICATION is returned, retry without
167 // the local certificate in use.
169 if (claconncode == CURLE_PEER_FAILED_VERIFICATION){
171 curl_easy_cleanup(conn);
172 conn = curl_easy_init();
174 curl_easy_setopt(conn, CURLOPT_URL, (const char*)ServerAddressSSL.mb_str(wxConvUTF8));
175 curl_easy_setopt(conn, CURLOPT_NOPROGRESS, 0);
176 curl_easy_setopt(conn, CURLOPT_HTTPAUTH, CURLAUTH_ANYSAFE);
177 curl_easy_setopt(conn, CURLOPT_TIMEOUT, 60);
178 curl_easy_setopt(conn, CURLOPT_FAILONERROR, TRUE);
179 curl_easy_setopt(conn, CURLOPT_USERAGENT, XSDAB_USERAGENT);
180 curl_easy_setopt(conn, CURLOPT_USERPWD, (const char*)ServerAuth.mb_str(wxConvUTF8));
181 curl_easy_setopt(conn, CURLOPT_WRITEFUNCTION, WritebackFunc);
182 curl_easy_setopt(conn, CURLOPT_WRITEDATA, &PageData);
183 curl_easy_setopt(conn, CURLOPT_WRITEHEADER, &PageHeader);
184 curl_easy_setopt(conn, CURLOPT_PROGRESSDATA, this);
185 curl_easy_setopt(conn, CURLOPT_PROGRESSFUNCTION, ProgressFunc);
186 curl_easy_setopt(conn, CURLOPT_CUSTOMREQUEST, "REPORT");
187 curl_easy_setopt(conn, CURLOPT_NOSIGNAL, 1);
188 curl_easy_setopt(conn, CURLOPT_HTTPHEADER, slist);
189 curl_easy_setopt(conn, CURLOPT_CERTINFO, 1);
190 curl_easy_setopt(conn, CURLOPT_POSTFIELDS, query);
191 curl_easy_setopt(conn, CURLOPT_POSTFIELDSIZE, strlen(query));
193 claconncode = (curl_easy_perform(conn));
195 // If claconncode is CURLE_OK then delete the certificate file as that
196 // is no longer needed.
198 if (claconncode == CURLE_OK){
200 // Delete the certificate file.
202 wxRemoveFile(ServerCertFilename);
208 // Check if it fails with a CURLE_SSL_CACERT then compare
209 // the certificates as PEM files.
211 if (claconncode == CURLE_SSL_CACERT && wxFile::Exists(ServerCertFilename) == TRUE){
214 sslerrconn = curl_easy_init();
215 CURLcode sslerrconncode;
217 wxString ServerAddressOnly = wxT("https://") + ServerAddress + wxT(":") + wxString::Format(wxT("%i"), ServerPort) + wxT("/");
219 curl_easy_setopt(sslerrconn, CURLOPT_URL, (const char*)ServerAddressOnly.mb_str(wxConvUTF8));
220 curl_easy_setopt(sslerrconn, CURLOPT_NOPROGRESS, 0);
221 curl_easy_setopt(sslerrconn, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
222 curl_easy_setopt(sslerrconn, CURLOPT_TIMEOUT, 60);
223 curl_easy_setopt(sslerrconn, CURLOPT_FAILONERROR, TRUE);
224 curl_easy_setopt(sslerrconn, CURLOPT_USERAGENT, XSDAB_USERAGENT);
225 curl_easy_setopt(sslerrconn, CURLOPT_WRITEFUNCTION, WritebackFunc);
226 curl_easy_setopt(sslerrconn, CURLOPT_WRITEDATA, &PageData);
227 curl_easy_setopt(sslerrconn, CURLOPT_WRITEHEADER, &PageHeader);
228 curl_easy_setopt(sslerrconn, CURLOPT_PROGRESSDATA, this);
229 curl_easy_setopt(sslerrconn, CURLOPT_PROGRESSFUNCTION, ProgressFunc);
230 curl_easy_setopt(sslerrconn, CURLOPT_NOSIGNAL, 1);
231 curl_easy_setopt(sslerrconn, CURLOPT_SSL_VERIFYPEER, 0);
232 curl_easy_setopt(sslerrconn, CURLOPT_CERTINFO, 1);
234 wxString SSLLocalData;
235 wxString SSLServerData;
237 sslerrconncode = (curl_easy_perform(sslerrconn));
239 SSLCertCol = BuildSSLCollection(sslerrconn);
240 std::map<int, SSLCertData>::iterator SSLCDIter = SSLCertCol.SSLCollection.find(0);
241 std::multimap<wxString,wxString>::iterator SSLDataIter = SSLCDIter->second.CertData.find(wxT("Cert"));
243 wxFFile SSLLocalFile;
245 #if wxABI_VERSION < 20900
246 SSLLocalFile.Open(ServerCertFilename.c_str(), wxT("r"));
248 SSLLocalFile.Open(ServerCertFilename, wxT("r"));
251 // Load the recovery database for tasks not done.
253 if (SSLLocalFile.IsOpened() == TRUE){
255 // Check if we are using wxWidgets version 2.8 or less and
256 // execute the required command accordingly.
258 SSLLocalFile.ReadAll(&SSLLocalData, wxConvAuto());
263 SSLServerData = SSLDataIter->second;
265 if (SSLLocalData == SSLServerData){
267 // Server key matches with local key so retry with CURLOPT_SSL_VERIFYPEER
268 // and CURLOPT_SSL_VERIFYHOST off.
270 curl_easy_cleanup(conn);
271 conn = curl_easy_init();
276 curl_easy_setopt(conn, CURLOPT_URL, (const char*)ServerAddressSSL.mb_str(wxConvUTF8));
277 curl_easy_setopt(conn, CURLOPT_NOPROGRESS, 0);
278 curl_easy_setopt(conn, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
279 curl_easy_setopt(conn, CURLOPT_TIMEOUT, 60);
280 curl_easy_setopt(conn, CURLOPT_FAILONERROR, TRUE);
281 curl_easy_setopt(conn, CURLOPT_USERAGENT, XSDAB_USERAGENT);
282 curl_easy_setopt(conn, CURLOPT_USERPWD, (const char*)ServerAuth.mb_str(wxConvUTF8));
283 curl_easy_setopt(conn, CURLOPT_WRITEFUNCTION, WritebackFunc);
284 curl_easy_setopt(conn, CURLOPT_WRITEDATA, &PageData);
285 curl_easy_setopt(conn, CURLOPT_WRITEHEADER, &PageHeader);
286 curl_easy_setopt(conn, CURLOPT_PROGRESSDATA, this);
287 curl_easy_setopt(conn, CURLOPT_PROGRESSFUNCTION, ProgressFunc);
288 curl_easy_setopt(conn, CURLOPT_CUSTOMREQUEST, "REPORT");
289 curl_easy_setopt(conn, CURLOPT_NOSIGNAL, 1);
290 curl_easy_setopt(conn, CURLOPT_HTTPHEADER, slist);
291 curl_easy_setopt(conn, CURLOPT_CERTINFO, 1);
292 curl_easy_setopt(conn, CURLOPT_POSTFIELDS, query);
293 curl_easy_setopt(conn, CURLOPT_POSTFIELDSIZE, strlen(query));
294 curl_easy_setopt(conn, CURLOPT_SSL_VERIFYHOST, 0);
295 curl_easy_setopt(conn, CURLOPT_SSL_VERIFYPEER, 0);
297 claconncode = (curl_easy_perform(conn));
303 if (MatchingCert == FALSE){
305 claconncode = CURLE_SSL_CACERT;
306 return ContactListFinal;
310 curl_easy_cleanup(sslerrconn);
314 // Sort out SSL error.
316 // When SSL cert error occurs, connect again and fetch certificates.
317 // Display a message to the user explaining that an invalid
318 // certificate has been given and let the user decide what
321 if (claconncode == CURLE_OK){
323 } else if (claconncode == CURLE_SSL_CACERT || claconncode == CURLE_PEER_FAILED_VERIFICATION){
326 sslerrconn = curl_easy_init();
327 CURLcode sslerrconncode;
329 wxString ServerAddressOnly = wxT("https://") + ServerAddress + wxT(":") + wxString::Format(wxT("%i"), ServerPort) + wxT("/");
331 // Replace conn with sslerrconn!
333 curl_easy_setopt(sslerrconn, CURLOPT_URL, (const char*)ServerAddressOnly.mb_str(wxConvUTF8));
334 curl_easy_setopt(sslerrconn, CURLOPT_NOPROGRESS, 0);
335 curl_easy_setopt(sslerrconn, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
336 curl_easy_setopt(sslerrconn, CURLOPT_TIMEOUT, 60);
337 curl_easy_setopt(sslerrconn, CURLOPT_FAILONERROR, TRUE);
338 curl_easy_setopt(sslerrconn, CURLOPT_USERAGENT, XSDAB_USERAGENT);
339 curl_easy_setopt(sslerrconn, CURLOPT_WRITEFUNCTION, WritebackFunc);
340 curl_easy_setopt(sslerrconn, CURLOPT_WRITEDATA, &PageData);
341 curl_easy_setopt(sslerrconn, CURLOPT_WRITEHEADER, &PageHeader);
342 curl_easy_setopt(sslerrconn, CURLOPT_PROGRESSDATA, this);
343 curl_easy_setopt(sslerrconn, CURLOPT_PROGRESSFUNCTION, ProgressFunc);
344 curl_easy_setopt(sslerrconn, CURLOPT_NOSIGNAL, 1);
345 curl_easy_setopt(sslerrconn, CURLOPT_SSL_VERIFYPEER, 0);
346 curl_easy_setopt(sslerrconn, CURLOPT_CERTINFO, 1);
348 sslerrconncode = (curl_easy_perform(sslerrconn));
350 SSLCertCol = BuildSSLCollection(sslerrconn);
351 SSLCertCol.SuccessCode = 1;
353 return ContactListFinal;
355 } else if (claconncode == CURLE_HTTP_RETURNED_ERROR){
357 fprintf(stderr, "curl_easy_perform() failed: %s\n",
358 curl_easy_strerror(claconncode));
360 curl_easy_getinfo(conn, CURLINFO_RESPONSE_CODE, &http_code);
361 fprintf(stderr, "Error code was: %d\n", http_code);
363 return ContactListFinal;
367 fprintf(stderr, "curl_easy_perform() failed: %s\n",
368 curl_easy_strerror(claconncode));
370 curl_easy_getinfo(conn, CURLINFO_RESPONSE_CODE, &http_code);
371 fprintf(stderr, "Error code was: %d\n", http_code);
373 return ContactListFinal;
377 SSLCertCol = BuildSSLCollection(conn);
383 wxString EmptyString;
385 curl_easy_setopt(conn, CURLOPT_URL, (const char*)ServerAddressNormal.mb_str(wxConvUTF8));
386 curl_easy_setopt(conn, CURLOPT_NOPROGRESS, 0);
387 curl_easy_setopt(conn, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
388 curl_easy_setopt(conn, CURLOPT_TIMEOUT, 60);
389 curl_easy_setopt(conn, CURLOPT_FAILONERROR, TRUE);
390 curl_easy_setopt(conn, CURLOPT_USERAGENT, XSDAB_USERAGENT);
391 curl_easy_setopt(conn, CURLOPT_USERPWD, (const char*)ServerAuth.mb_str(wxConvUTF8));
392 curl_easy_setopt(conn, CURLOPT_WRITEFUNCTION, WritebackFunc);
393 curl_easy_setopt(conn, CURLOPT_WRITEDATA, &PageData);
394 curl_easy_setopt(conn, CURLOPT_WRITEHEADER, &PageHeader);
395 curl_easy_setopt(conn, CURLOPT_PROGRESSDATA, this);
396 curl_easy_setopt(conn, CURLOPT_PROGRESSFUNCTION, ProgressFunc);
397 curl_easy_setopt(conn, CURLOPT_CUSTOMREQUEST, "REPORT");
398 curl_easy_setopt(conn, CURLOPT_NOSIGNAL, 1);
399 curl_easy_setopt(conn, CURLOPT_HTTPHEADER, slist);
400 curl_easy_setopt(conn, CURLOPT_POSTFIELDS, query);
401 curl_easy_setopt(conn, CURLOPT_POSTFIELDSIZE, strlen(query));
406 claconncode = (curl_easy_perform(conn));
408 if (claconncode == CURLE_OK){
412 } else if (claconncode == CURLE_HTTP_RETURNED_ERROR){
414 fprintf(stderr, "curl_easy_perform() failed: %s\n",
415 curl_easy_strerror(claconncode));
417 curl_easy_getinfo(conn, CURLINFO_RESPONSE_CODE, &http_code);
418 fprintf(stderr, "Error code was: %i\n", http_code);
420 return ContactListFinal;
424 fprintf(stderr, "curl_easy_perform() failed: %s\n",
425 curl_easy_strerror(claconncode));
427 curl_easy_getinfo(conn, CURLINFO_RESPONSE_CODE, &http_code);
428 fprintf(stderr, "Error code was: %i\n", http_code);
430 return ContactListFinal;
436 xmlDocPtr xmlCardDAVDoc;
437 xmlCardDAVDoc = xmlReadMemory(PageData.mb_str(wxConvUTF8), (int)PageData.Len(), "noname.xml", NULL, 0);
439 xmlNodePtr nodeLevel1;
440 xmlNodePtr nodeLevel2;
441 xmlNodePtr nodeLevel3;
442 xmlNodePtr nodeLevel4;
443 xmlNodePtr nodeLevel5;
444 xmlNodePtr nodeLevel6;
446 xmlNodePtr nodeStatusLv1;
447 xmlNodePtr nodeStatusLv2;
449 std::map<wxString,wxString> xmlDataMap;
450 std::map<wxString,wxString> ServerETagData;
452 wxString DataFilename;
453 wxString DataSyncToken;
456 bool SyncTokenFound = FALSE;
458 std::string xmlStringSafe;
460 // Tranverse through the catacombs of the response to get our ETag for the file and
461 // the server syncronisation token.
463 // Start by getting all the server ETag data.
465 for (nodeLevel1 = xmlCardDAVDoc->children;
467 nodeLevel1 = nodeLevel1->next)
470 for (nodeLevel2 = nodeLevel1->children;
472 nodeLevel2 = nodeLevel2->next)
475 for (nodeLevel3 = nodeLevel2->children;
477 nodeLevel3 = nodeLevel3->next)
481 bool HREFFound = FALSE;
482 bool ETagFound = FALSE;
483 bool HTTPStatus = FALSE;
485 if (!xmlStrcmp(nodeLevel3->name, (const xmlChar *)"href") ||
486 !xmlStrcmp(nodeLevel3->name, (const xmlChar *)"d:href") ||
487 !xmlStrcmp(nodeLevel3->name, (const xmlChar *)"D:href")
492 for (nodeLevel4 = nodeLevel3->children;
494 nodeLevel4 = nodeLevel4->next)
497 if (!xmlStrcmp(nodeLevel4->name, (const xmlChar *)"text") ||
498 !xmlStrcmp(nodeLevel4->name, (const xmlChar *)"d:text") ||
499 !xmlStrcmp(nodeLevel4->name, (const xmlChar *)"D:text")
502 DataFilename = wxString::FromUTF8((const char*)nodeLevel4->content);
503 wxStringTokenizer wSTDFilename(DataFilename, wxT("/"));
505 while (wSTDFilename.HasMoreTokens()){
507 DataFilename = wSTDFilename.GetNextToken();
522 for (nodeLevel4 = nodeLevel3->children;
524 nodeLevel4 = nodeLevel4->next)
527 for (nodeStatusLv1 = nodeLevel3->children;
528 nodeStatusLv1 != NULL;
529 nodeStatusLv1 = nodeStatusLv1->next)
532 if (wxString::FromUTF8((const char*)nodeStatusLv1->content) == wxT("HTTP/1.1 404 Not Found")){
540 if ((!xmlStrcmp(nodeStatusLv1->name, (const xmlChar *)"status") ||
541 !xmlStrcmp(nodeStatusLv1->name, (const xmlChar *)"d:status") ||
542 !xmlStrcmp(nodeStatusLv1->name, (const xmlChar *)"D:status")) && HTTPStatus == FALSE)
547 for (nodeStatusLv2 = nodeStatusLv1->children;
548 nodeStatusLv2 != NULL;
549 nodeStatusLv2 = nodeStatusLv2->next)
552 if (!xmlStrcmp(nodeStatusLv2->name, (const xmlChar *)"text") ||
553 !xmlStrcmp(nodeStatusLv2->name, (const xmlChar *)"d:text") ||
554 !xmlStrcmp(nodeStatusLv2->name, (const xmlChar *)"D:text")
557 if (wxString::FromUTF8((const char*)nodeStatusLv2->content) == wxT("HTTP/1.1 200 OK")){
563 // This is currently in a WebDAV draft and may hopefully be enabled when this changes.
565 //} else if (wxString::FromUTF8((const char*)nodeStatusLv2->content) == wxT("HTTP/1.1 201 Created")){
567 // DataFileStatus = 0;
582 for (nodeLevel5 = nodeLevel4->children;
584 nodeLevel5 = nodeLevel5->next)
587 if (!xmlStrcmp(nodeLevel5->name, (const xmlChar *)"getetag") ||
588 !xmlStrcmp(nodeLevel5->name, (const xmlChar *)"d:getetag") ||
589 !xmlStrcmp(nodeLevel5->name, (const xmlChar *)"D:getetag")
592 for (nodeLevel6 = nodeLevel5->children;
594 nodeLevel6 = nodeLevel6->next)
597 // Strip the quotes from the ETag.
599 ETagData = wxString::FromUTF8((const char*)nodeLevel6->content);
600 if (ETagData.Mid(0, 1) == wxT("\"") && ETagData.Mid((ETagData.Len() - 1), 1) == wxT("\"")){
602 ETagData.Remove(0, 1);
603 ETagData.RemoveLast();
619 if (HREFFound == TRUE && ETagFound == TRUE && HTTPStatus == TRUE){
621 // Add to the map data.
625 SData.ETagData = ETagData;
626 SData.DataFlag = DataFileStatus;
628 ContactListFinal.ListData.insert(std::make_pair(DataFilename, SData));
640 if ((!xmlStrcmp(nodeLevel2->name, (const xmlChar *)"sync-token") ||
641 !xmlStrcmp(nodeLevel2->name, (const xmlChar *)"d:sync-token") ||
642 !xmlStrcmp(nodeLevel2->name, (const xmlChar *)"D:sync-token")) &&
643 SyncTokenFound == FALSE
646 for (nodeLevel3 = nodeLevel2->children;
648 nodeLevel3 = nodeLevel3->next)
651 if (!xmlStrcmp(nodeLevel3->name, (const xmlChar *)"text") ||
652 !xmlStrcmp(nodeLevel3->name, (const xmlChar *)"d:text") ||
653 !xmlStrcmp(nodeLevel3->name, (const xmlChar *)"D:text")
656 DataSyncToken = wxString::FromUTF8((const char*)nodeLevel3->content);
658 SyncTokenFound = TRUE;
670 for (nodeLevel1 = xmlCardDAVDoc->children;
672 nodeLevel1 = nodeLevel1->next)
675 for (nodeLevel2 = nodeLevel1->children;
677 nodeLevel2 = nodeLevel2->next)
681 bool HREFFound = FALSE;
682 bool ETagFound = FALSE;
683 bool HTTPStatus = FALSE;
685 for (nodeLevel3 = nodeLevel2->children;
687 nodeLevel3 = nodeLevel3->next)
690 if (!xmlStrcmp(nodeLevel3->name, (const xmlChar *)"href") ||
691 !xmlStrcmp(nodeLevel3->name, (const xmlChar *)"d:href") ||
692 !xmlStrcmp(nodeLevel3->name, (const xmlChar *)"D:href")
697 for (nodeLevel4 = nodeLevel3->children;
699 nodeLevel4 = nodeLevel4->next)
702 if (!xmlStrcmp(nodeLevel4->name, (const xmlChar *)"text") ||
703 !xmlStrcmp(nodeLevel4->name, (const xmlChar *)"d:text") ||
704 !xmlStrcmp(nodeLevel4->name, (const xmlChar *)"D:text")
707 DataFilename = wxString::FromUTF8((const char*)nodeLevel4->content);
708 wxStringTokenizer wSTDFilename(DataFilename, wxT("/"));
710 while (wSTDFilename.HasMoreTokens()){
712 DataFilename = wSTDFilename.GetNextToken();
727 for (nodeLevel4 = nodeLevel3->children;
729 nodeLevel4 = nodeLevel4->next)
732 for (nodeStatusLv1 = nodeLevel3->children;
733 nodeStatusLv1 != NULL;
734 nodeStatusLv1 = nodeStatusLv1->next)
737 if (wxString::FromUTF8((const char*)nodeStatusLv1->content) == wxT("HTTP/1.1 404 Not Found")){
745 if ((!xmlStrcmp(nodeStatusLv1->name, (const xmlChar *)"status") ||
746 !xmlStrcmp(nodeStatusLv1->name, (const xmlChar *)"d:status") ||
747 !xmlStrcmp(nodeStatusLv1->name, (const xmlChar *)"D:status")) && HTTPStatus == FALSE)
752 for (nodeStatusLv2 = nodeStatusLv1->children;
753 nodeStatusLv2 != NULL;
754 nodeStatusLv2 = nodeStatusLv2->next)
757 if (!xmlStrcmp(nodeStatusLv2->name, (const xmlChar *)"text") ||
758 !xmlStrcmp(nodeStatusLv2->name, (const xmlChar *)"d:text") ||
759 !xmlStrcmp(nodeStatusLv2->name, (const xmlChar *)"D:text")
762 if (wxString::FromUTF8((const char*)nodeStatusLv2->content) == wxT("HTTP/1.1 200 OK")){
768 // This is currently in a WebDAV draft and may hopefully be enabled when this changes.
770 //} else if (wxString::FromUTF8((const char*)nodeStatusLv2->content) == wxT("HTTP/1.1 201 Created")){
772 // DataFileStatus = 0;
787 for (nodeLevel5 = nodeLevel4->children;
789 nodeLevel5 = nodeLevel5->next)
792 if (!xmlStrcmp(nodeLevel5->name, (const xmlChar *)"getetag") ||
793 !xmlStrcmp(nodeLevel5->name, (const xmlChar *)"d:getetag") ||
794 !xmlStrcmp(nodeLevel5->name, (const xmlChar *)"D:getetag")
797 for (nodeLevel6 = nodeLevel5->children;
799 nodeLevel6 = nodeLevel6->next)
802 // Strip the quotes from the ETag.
804 ETagData = wxString::FromUTF8((const char*)nodeLevel6->content);
805 if (ETagData.Mid(0, 1) == wxT("\"") && ETagData.Mid((ETagData.Len() - 1), 1) == wxT("\"")){
807 ETagData.Remove(0, 1);
808 ETagData.RemoveLast();
826 if (HREFFound == TRUE && HTTPStatus == TRUE && DataFileStatus == 2){
830 SData.ETagData = wxT("");
831 SData.DataFlag = DataFileStatus;
833 ContactListFinal.ListData.insert(std::make_pair(DataFilename, SData));
837 if (HREFFound == TRUE && ETagFound == TRUE && HTTPStatus == TRUE){
839 // Add to the map data.
843 SData.ETagData = ETagData;
844 SData.DataFlag = DataFileStatus;
846 ContactListFinal.ListData.insert(std::make_pair(DataFilename, SData));
855 DataFilename.Clear();
857 if ((!xmlStrcmp(nodeLevel2->name, (const xmlChar *)"sync-token") ||
858 !xmlStrcmp(nodeLevel2->name, (const xmlChar *)"d:sync-token") ||
859 !xmlStrcmp(nodeLevel2->name, (const xmlChar *)"D:sync-token")) &&
860 SyncTokenFound == FALSE
863 for (nodeLevel3 = nodeLevel2->children;
865 nodeLevel3 = nodeLevel3->next)
868 if (!xmlStrcmp(nodeLevel3->name, (const xmlChar *)"text") ||
869 !xmlStrcmp(nodeLevel3->name, (const xmlChar *)"d:text") ||
870 !xmlStrcmp(nodeLevel3->name, (const xmlChar *)"D:text")
873 DataSyncToken = wxString::FromUTF8((const char*)nodeLevel3->content);
875 SyncTokenFound = TRUE;
887 // Get the sync token.
889 if (SyncTokenFound == TRUE){
891 ContactListFinal.SyncToken = DataSyncToken;
897 SleepFor(2000000000);
899 xmlFreeDoc(xmlCardDAVDoc);
900 curl_easy_cleanup(conn);
902 SyncDataBuffer.reset();
904 // Get the first result.
906 return ContactListFinal;