// carddav-contactlist.cpp - CardDAV Object - Contact list subroutines. // // (c) 2012-2015 Xestia Software Development. // // This file is part of Xestia Address Book. // // Xestia Address Book is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by the // Free Software Foundation, version 3 of the license. // // Xestia Address Book is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License along // with Xestia Address Book. If not, see #include "carddav.h" #include "../version.h" #include #include #include #include #include #include #include #include "../vcard/vcard.h" #include "../common/dirs.h" ContactListData CardDAV::GetContactList(wxString SyncTokenInc){ ContactListData ContactListFinal; std::map ContactList; PageData.Clear(); PageHeader.Clear(); SSLStatus = TRUE; AuthPassed = TRUE; AbortConnection = FALSE; CURL *conn; wxString ServerAddressURL; wxString ServerAuth; wxString ServerAddressSSL; wxString ServerAddressNormal; conn = curl_easy_init(); struct CardDAVCURLPasser { CardDAV *Data; bool HeaderMode = TRUE; } CardDAVHeader, CardDAVFooter; CardDAVHeader.Data = this; CardDAVHeader.HeaderMode = TRUE; CardDAVFooter.Data = this; CardDAVFooter.HeaderMode = FALSE; wxString Data1; wxString Data2; ServerAddressURL = ServerAddress + wxT(":") + wxString::Format(wxT("%i"), ServerPort) + wxT("/") + ServerPrefix + wxT("/"); ServerAddressSSL = wxT("https://") + ServerAddressURL; ServerAddressNormal = wxT("http://") + ServerAddressURL; ServerAuth = ServerUser + wxT(":") + ServerPass; // Load the sync token file (if it exists). wxCharBuffer SyncDataBuffer; wxString SyncData; SyncData.Clear(); SyncTokenInc.Trim(); if (!SyncTokenInc.IsEmpty()){ SyncData = wxT("\n"); SyncData.Append(wxT("\n")); SyncData.Append(wxT("")); //SyncData.Trim(); //SyncData.Append(wxT("data:,00378c55-1f44-44a2-a255-84f6560b5cac_580")); SyncData.Append(SyncTokenInc); //SyncData.Trim(); SyncData.Append(wxT("\n")); SyncData.Append(wxT("1\n")); SyncData.Append(wxT("\n")); SyncData.Append(wxT(" \n")); SyncData.Append(wxT("\n")); SyncData.Append(wxT("")); SyncDataBuffer = SyncData.ToUTF8(); } else { SyncData = wxT("\n"); SyncData.Append(wxT("\n")); SyncData.Append(wxT("\n")); SyncData.Append(wxT("1\n")); SyncData.Append(wxT("\n")); SyncData.Append(wxT(" \n")); SyncData.Append(wxT("\n")); SyncData.Append(wxT("\n")); SyncDataBuffer = SyncData.ToUTF8(); } //static const char* query = SyncData.mb_str(); /*char *query = "\n\ \n\ data:,00378c55-1f44-44a2-a255-84f6560b5cac_580\n\ 1\n\ \n\ \n\ \n\ \n";*/ const char* query = SyncDataBuffer.data(); // Try SSL first. std::map::iterator ActIter; struct UploadDataStruc UploadData; ActIter = ActivityListPtr->find((int)ItemIndex); curl_slist *slist = NULL; slist = curl_slist_append(slist, "Depth: 1"); if (ServerSSL){ wxString ServerCertFilename; bool MatchingCert = FALSE; curl_easy_setopt(conn, CURLOPT_URL, (const char*)ServerAddressSSL.mb_str(wxConvUTF8)); curl_easy_setopt(conn, CURLOPT_NOPROGRESS, 0); curl_easy_setopt(conn, CURLOPT_HTTPAUTH, CURLAUTH_ANYSAFE); curl_easy_setopt(conn, CURLOPT_TIMEOUT, 60); curl_easy_setopt(conn, CURLOPT_FAILONERROR, TRUE); curl_easy_setopt(conn, CURLOPT_USERAGENT, XSDAB_USERAGENT); curl_easy_setopt(conn, CURLOPT_USERPWD, (const char*)ServerAuth.mb_str(wxConvUTF8)); curl_easy_setopt(conn, CURLOPT_WRITEFUNCTION, WritebackFunc); curl_easy_setopt(conn, CURLOPT_WRITEDATA, &PageData); curl_easy_setopt(conn, CURLOPT_WRITEHEADER, &PageHeader); curl_easy_setopt(conn, CURLOPT_PROGRESSDATA, this); curl_easy_setopt(conn, CURLOPT_PROGRESSFUNCTION, ProgressFunc); curl_easy_setopt(conn, CURLOPT_CUSTOMREQUEST, "REPORT"); curl_easy_setopt(conn, CURLOPT_NOSIGNAL, 1); curl_easy_setopt(conn, CURLOPT_HTTPHEADER, slist); curl_easy_setopt(conn, CURLOPT_CERTINFO, 1); ServerCertFilename = GetAccountDir(ServerAccount, TRUE); if (wxFile::Exists(ServerCertFilename) == TRUE){ curl_easy_setopt(conn, CURLOPT_SSL_VERIFYPEER, 1); curl_easy_setopt(conn, CURLOPT_SSL_VERIFYHOST, 2); curl_easy_setopt(conn, CURLOPT_CAINFO, (const char*)ServerCertFilename.mb_str(wxConvUTF8)); } //UploadData.readptr = &CardDAVDataQuery; //UploadData.sizeleft = CardDAVDataQuery.Len(); //curl_easy_setopt(conn, CURLOPT_UPLOAD, 1); //curl_easy_setopt(conn, CURLOPT_READDATA, &UploadData); //curl_easy_setopt(conn, CURLOPT_READFUNCTION, UploadReadFunc); //curl_easy_setopt(conn, CURLOPT_WRITEFUNCTION, writefunc); curl_easy_setopt(conn, CURLOPT_POSTFIELDS, query); curl_easy_setopt(conn, CURLOPT_POSTFIELDSIZE, strlen(query)); claconncode = (curl_easy_perform(conn)); // If CURLE_PEER_FAILED_VERIFICATION is returned, retry without // the local certificate in use. if (claconncode == CURLE_PEER_FAILED_VERIFICATION){ curl_easy_cleanup(conn); conn = curl_easy_init(); curl_easy_setopt(conn, CURLOPT_URL, (const char*)ServerAddressSSL.mb_str(wxConvUTF8)); curl_easy_setopt(conn, CURLOPT_NOPROGRESS, 0); curl_easy_setopt(conn, CURLOPT_HTTPAUTH, CURLAUTH_ANYSAFE); curl_easy_setopt(conn, CURLOPT_TIMEOUT, 60); curl_easy_setopt(conn, CURLOPT_FAILONERROR, TRUE); curl_easy_setopt(conn, CURLOPT_USERAGENT, XSDAB_USERAGENT); curl_easy_setopt(conn, CURLOPT_USERPWD, (const char*)ServerAuth.mb_str(wxConvUTF8)); curl_easy_setopt(conn, CURLOPT_WRITEFUNCTION, WritebackFunc); curl_easy_setopt(conn, CURLOPT_WRITEDATA, &PageData); curl_easy_setopt(conn, CURLOPT_WRITEHEADER, &PageHeader); curl_easy_setopt(conn, CURLOPT_PROGRESSDATA, this); curl_easy_setopt(conn, CURLOPT_PROGRESSFUNCTION, ProgressFunc); curl_easy_setopt(conn, CURLOPT_CUSTOMREQUEST, "REPORT"); curl_easy_setopt(conn, CURLOPT_NOSIGNAL, 1); curl_easy_setopt(conn, CURLOPT_HTTPHEADER, slist); curl_easy_setopt(conn, CURLOPT_CERTINFO, 1); curl_easy_setopt(conn, CURLOPT_POSTFIELDS, query); curl_easy_setopt(conn, CURLOPT_POSTFIELDSIZE, strlen(query)); claconncode = (curl_easy_perform(conn)); // If claconncode is CURLE_OK then delete the certificate file as that // is no longer needed. if (claconncode == CURLE_OK){ // Delete the certificate file. wxRemoveFile(ServerCertFilename); } } // Check if it fails with a CURLE_SSL_CACERT then compare // the certificates as PEM files. if (claconncode == CURLE_SSL_CACERT && wxFile::Exists(ServerCertFilename) == TRUE){ //curl_easy_cleanup(conn); //conn = curl_easy_init(); CURL *sslerrconn; sslerrconn = curl_easy_init(); CURLcode sslerrconncode; //claconncode = (curl_easy_perform(conn)); wxString ServerAddressOnly = wxT("https://") + ServerAddress + wxT(":") + wxString::Format(wxT("%i"), ServerPort) + wxT("/"); curl_easy_setopt(sslerrconn, CURLOPT_URL, (const char*)ServerAddressOnly.mb_str(wxConvUTF8)); curl_easy_setopt(sslerrconn, CURLOPT_NOPROGRESS, 0); curl_easy_setopt(sslerrconn, CURLOPT_HTTPAUTH, CURLAUTH_ANY); curl_easy_setopt(sslerrconn, CURLOPT_TIMEOUT, 60); curl_easy_setopt(sslerrconn, CURLOPT_FAILONERROR, TRUE); curl_easy_setopt(sslerrconn, CURLOPT_USERAGENT, XSDAB_USERAGENT); curl_easy_setopt(sslerrconn, CURLOPT_WRITEFUNCTION, WritebackFunc); curl_easy_setopt(sslerrconn, CURLOPT_WRITEDATA, &PageData); curl_easy_setopt(sslerrconn, CURLOPT_WRITEHEADER, &PageHeader); curl_easy_setopt(sslerrconn, CURLOPT_PROGRESSDATA, this); curl_easy_setopt(sslerrconn, CURLOPT_PROGRESSFUNCTION, ProgressFunc); curl_easy_setopt(sslerrconn, CURLOPT_NOSIGNAL, 1); curl_easy_setopt(sslerrconn, CURLOPT_SSL_VERIFYPEER, 0); curl_easy_setopt(sslerrconn, CURLOPT_CERTINFO, 1); wxString SSLLocalData; wxString SSLServerData; sslerrconncode = (curl_easy_perform(sslerrconn)); SSLCertCol = BuildSSLCollection(sslerrconn); std::map::iterator SSLCDIter = SSLCertCol.SSLCollection.find(0); std::multimap::iterator SSLDataIter = SSLCDIter->second.CertData.find(wxT("Cert")); wxFFile SSLLocalFile; #if wxABI_VERSION < 20900 SSLLocalFile.Open(ServerCertFilename.c_str(), wxT("r")); #else SSLLocalFile.Open(ServerCertFilename, wxT("r")); #endif // Load the recovery database for tasks not done. if (SSLLocalFile.IsOpened() == TRUE){ // Check if we are using wxWidgets version 2.8 or less and // execute the required command accordingly. SSLLocalFile.ReadAll(&SSLLocalData, wxConvAuto()); } SSLServerData = SSLDataIter->second; if (SSLLocalData == SSLServerData){ // Server key matches with local key so retry with CURLOPT_SSL_VERIFYPEER // and CURLOPT_SSL_VERIFYHOST off. curl_easy_cleanup(conn); conn = curl_easy_init(); PageHeader.clear(); PageData.clear(); curl_easy_setopt(conn, CURLOPT_URL, (const char*)ServerAddressSSL.mb_str(wxConvUTF8)); curl_easy_setopt(conn, CURLOPT_NOPROGRESS, 0); curl_easy_setopt(conn, CURLOPT_HTTPAUTH, CURLAUTH_ANY); curl_easy_setopt(conn, CURLOPT_TIMEOUT, 60); curl_easy_setopt(conn, CURLOPT_FAILONERROR, TRUE); curl_easy_setopt(conn, CURLOPT_USERAGENT, XSDAB_USERAGENT); curl_easy_setopt(conn, CURLOPT_USERPWD, (const char*)ServerAuth.mb_str(wxConvUTF8)); curl_easy_setopt(conn, CURLOPT_WRITEFUNCTION, WritebackFunc); curl_easy_setopt(conn, CURLOPT_WRITEDATA, &PageData); curl_easy_setopt(conn, CURLOPT_WRITEHEADER, &PageHeader); curl_easy_setopt(conn, CURLOPT_PROGRESSDATA, this); curl_easy_setopt(conn, CURLOPT_PROGRESSFUNCTION, ProgressFunc); curl_easy_setopt(conn, CURLOPT_CUSTOMREQUEST, "REPORT"); curl_easy_setopt(conn, CURLOPT_NOSIGNAL, 1); curl_easy_setopt(conn, CURLOPT_HTTPHEADER, slist); curl_easy_setopt(conn, CURLOPT_CERTINFO, 1); curl_easy_setopt(conn, CURLOPT_POSTFIELDS, query); curl_easy_setopt(conn, CURLOPT_POSTFIELDSIZE, strlen(query)); curl_easy_setopt(conn, CURLOPT_SSL_VERIFYHOST, 0); curl_easy_setopt(conn, CURLOPT_SSL_VERIFYPEER, 0); claconncode = (curl_easy_perform(conn)); MatchingCert = TRUE; } if (MatchingCert == FALSE){ claconncode = CURLE_SSL_CACERT; return ContactListFinal; } curl_easy_cleanup(sslerrconn); } // Sort out SSL error. // When SSL cert error occurs, connect again and fetch certificates. // Display a message to the user explaining that an invalid // certificate has been given and let the user decide what // to do next. if (claconncode == CURLE_OK){ } else if (claconncode == CURLE_SSL_CACERT || claconncode == CURLE_PEER_FAILED_VERIFICATION){ CURL *sslerrconn; sslerrconn = curl_easy_init(); CURLcode sslerrconncode; wxString ServerAddressOnly = wxT("https://") + ServerAddress + wxT(":") + wxString::Format(wxT("%i"), ServerPort) + wxT("/"); // Replace conn with sslerrconn! curl_easy_setopt(sslerrconn, CURLOPT_URL, (const char*)ServerAddressOnly.mb_str(wxConvUTF8)); curl_easy_setopt(sslerrconn, CURLOPT_NOPROGRESS, 0); curl_easy_setopt(sslerrconn, CURLOPT_HTTPAUTH, CURLAUTH_ANY); curl_easy_setopt(sslerrconn, CURLOPT_TIMEOUT, 60); curl_easy_setopt(sslerrconn, CURLOPT_FAILONERROR, TRUE); curl_easy_setopt(sslerrconn, CURLOPT_USERAGENT, XSDAB_USERAGENT); curl_easy_setopt(sslerrconn, CURLOPT_WRITEFUNCTION, WritebackFunc); curl_easy_setopt(sslerrconn, CURLOPT_WRITEDATA, &PageData); curl_easy_setopt(sslerrconn, CURLOPT_WRITEHEADER, &PageHeader); curl_easy_setopt(sslerrconn, CURLOPT_PROGRESSDATA, this); curl_easy_setopt(sslerrconn, CURLOPT_PROGRESSFUNCTION, ProgressFunc); curl_easy_setopt(sslerrconn, CURLOPT_NOSIGNAL, 1); curl_easy_setopt(sslerrconn, CURLOPT_SSL_VERIFYPEER, 0); curl_easy_setopt(sslerrconn, CURLOPT_CERTINFO, 1); sslerrconncode = (curl_easy_perform(sslerrconn)); SSLCertCol = BuildSSLCollection(sslerrconn); SSLCertCol.SuccessCode = 1; return ContactListFinal; } else if (claconncode == CURLE_HTTP_RETURNED_ERROR){ fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(claconncode)); int http_code = 0; curl_easy_getinfo(conn, CURLINFO_RESPONSE_CODE, &http_code); fprintf(stderr, "Error code was: %d\n", http_code); return ContactListFinal; } else { fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(claconncode)); int http_code = 0; curl_easy_getinfo(conn, CURLINFO_RESPONSE_CODE, &http_code); fprintf(stderr, "Error code was: %d\n", http_code); return ContactListFinal; } SSLCertCol = BuildSSLCollection(conn); } else { // No SSL. wxString EmptyString; curl_easy_setopt(conn, CURLOPT_URL, (const char*)ServerAddressNormal.mb_str(wxConvUTF8)); curl_easy_setopt(conn, CURLOPT_NOPROGRESS, 0); curl_easy_setopt(conn, CURLOPT_HTTPAUTH, CURLAUTH_ANY); curl_easy_setopt(conn, CURLOPT_TIMEOUT, 60); curl_easy_setopt(conn, CURLOPT_FAILONERROR, TRUE); curl_easy_setopt(conn, CURLOPT_USERAGENT, XSDAB_USERAGENT); curl_easy_setopt(conn, CURLOPT_USERPWD, (const char*)ServerAuth.mb_str(wxConvUTF8)); curl_easy_setopt(conn, CURLOPT_WRITEFUNCTION, WritebackFunc); curl_easy_setopt(conn, CURLOPT_WRITEDATA, &PageData); curl_easy_setopt(conn, CURLOPT_WRITEHEADER, &PageHeader); curl_easy_setopt(conn, CURLOPT_PROGRESSDATA, this); curl_easy_setopt(conn, CURLOPT_PROGRESSFUNCTION, ProgressFunc); curl_easy_setopt(conn, CURLOPT_CUSTOMREQUEST, "REPORT"); curl_easy_setopt(conn, CURLOPT_NOSIGNAL, 1); curl_easy_setopt(conn, CURLOPT_HTTPHEADER, slist); //UploadData.readptr = &CardDAVDataQuery; //UploadData.sizeleft = CardDAVDataQuery.Len(); //curl_easy_setopt(conn, CURLOPT_UPLOAD, 1); //curl_easy_setopt(conn, CURLOPT_READDATA, &UploadData); //curl_easy_setopt(conn, CURLOPT_READFUNCTION, UploadReadFunc); //curl_easy_setopt(conn, CURLOPT_WRITEFUNCTION, writefunc); curl_easy_setopt(conn, CURLOPT_POSTFIELDS, query); curl_easy_setopt(conn, CURLOPT_POSTFIELDSIZE, strlen(query)); PageData.Clear(); PageHeader.Clear(); claconncode = (curl_easy_perform(conn)); if (claconncode == CURLE_OK){ } else if (claconncode == CURLE_HTTP_RETURNED_ERROR){ fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(claconncode)); int http_code = 0; curl_easy_getinfo(conn, CURLINFO_RESPONSE_CODE, &http_code); fprintf(stderr, "Error code was: %i\n", http_code); return ContactListFinal; } else { fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(claconncode)); int http_code = 0; curl_easy_getinfo(conn, CURLINFO_RESPONSE_CODE, &http_code); fprintf(stderr, "Error code was: %i\n", http_code); return ContactListFinal; } } xmlDocPtr xmlCardDAVDoc; xmlCardDAVDoc = xmlReadMemory(PageData.mb_str(wxConvUTF8), (int)PageData.Len(), "noname.xml", NULL, 0); xmlNodePtr nodeLevel1; xmlNodePtr nodeLevel2; xmlNodePtr nodeLevel3; xmlNodePtr nodeLevel4; xmlNodePtr nodeLevel5; xmlNodePtr nodeLevel6; xmlNodePtr nodeStatusLv1; xmlNodePtr nodeStatusLv2; std::map xmlDataMap; std::map ServerETagData; wxString DataFilename; wxString DataSyncToken; int DataFileStatus; wxString ETagData; bool SyncTokenFound = FALSE; std::string xmlStringSafe; // Tranverse through the catacombs of the response to get our ETag for the file and // the server syncronisation token. // Start by getting all the server ETag data. for (nodeLevel1 = xmlCardDAVDoc->children; nodeLevel1 != NULL; nodeLevel1 = nodeLevel1->next) { for (nodeLevel2 = nodeLevel1->children; nodeLevel2 != NULL; nodeLevel2 = nodeLevel2->next) { for (nodeLevel3 = nodeLevel2->children; nodeLevel3 != NULL; nodeLevel3 = nodeLevel3->next) { DataFileStatus = 0; bool HREFFound = FALSE; bool ETagFound = FALSE; bool HTTPStatus = FALSE; if (!xmlStrcmp(nodeLevel3->name, (const xmlChar *)"href") || !xmlStrcmp(nodeLevel3->name, (const xmlChar *)"d:href") || !xmlStrcmp(nodeLevel3->name, (const xmlChar *)"D:href") ){ // Get the filename. for (nodeLevel4 = nodeLevel3->children; nodeLevel4 != NULL; nodeLevel4 = nodeLevel4->next) { if (!xmlStrcmp(nodeLevel4->name, (const xmlChar *)"text") || !xmlStrcmp(nodeLevel4->name, (const xmlChar *)"d:text") || !xmlStrcmp(nodeLevel4->name, (const xmlChar *)"D:text") ){ DataFilename = wxString::FromUTF8((const char*)nodeLevel4->content); wxStringTokenizer wSTDFilename(DataFilename, wxT("/")); while (wSTDFilename.HasMoreTokens()){ DataFilename = wSTDFilename.GetNextToken(); } HREFFound = TRUE; } } } else { for (nodeLevel4 = nodeLevel3->children; nodeLevel4 != NULL; nodeLevel4 = nodeLevel4->next) { for (nodeStatusLv1 = nodeLevel3->children; nodeStatusLv1 != NULL; nodeStatusLv1 = nodeStatusLv1->next) { if (wxString::FromUTF8((const char*)nodeStatusLv1->content) == wxT("HTTP/1.1 404 Not Found")){ DataFileStatus = 2; HTTPStatus = TRUE; } if ((!xmlStrcmp(nodeStatusLv1->name, (const xmlChar *)"status") || !xmlStrcmp(nodeStatusLv1->name, (const xmlChar *)"d:status") || !xmlStrcmp(nodeStatusLv1->name, (const xmlChar *)"D:status")) && HTTPStatus == FALSE) { // Get the filename. for (nodeStatusLv2 = nodeStatusLv1->children; nodeStatusLv2 != NULL; nodeStatusLv2 = nodeStatusLv2->next) { if (!xmlStrcmp(nodeStatusLv2->name, (const xmlChar *)"text") || !xmlStrcmp(nodeStatusLv2->name, (const xmlChar *)"d:text") || !xmlStrcmp(nodeStatusLv2->name, (const xmlChar *)"D:text") ){ if (wxString::FromUTF8((const char*)nodeStatusLv2->content) == wxT("HTTP/1.1 200 OK")){ DataFileStatus = 1; HTTPStatus = TRUE; // This is currently in a WebDAV draft and may hopefully be enabled when this changes. //} else if (wxString::FromUTF8((const char*)nodeStatusLv2->content) == wxT("HTTP/1.1 201 Created")){ // DataFileStatus = 0; } } } } } for (nodeLevel5 = nodeLevel4->children; nodeLevel5 != NULL; nodeLevel5 = nodeLevel5->next) { if (!xmlStrcmp(nodeLevel5->name, (const xmlChar *)"getetag") || !xmlStrcmp(nodeLevel5->name, (const xmlChar *)"d:getetag") || !xmlStrcmp(nodeLevel5->name, (const xmlChar *)"D:getetag") ){ for (nodeLevel6 = nodeLevel5->children; nodeLevel6 != NULL; nodeLevel6 = nodeLevel6->next) { // Strip the quotes from the ETag. ETagData = wxString::FromUTF8((const char*)nodeLevel6->content); if (ETagData.Mid(0, 1) == wxT("\"") && ETagData.Mid((ETagData.Len() - 1), 1) == wxT("\"")){ ETagData.Remove(0, 1); ETagData.RemoveLast(); } ETagFound = TRUE; } } } } } if (HREFFound == TRUE && ETagFound == TRUE && HTTPStatus == TRUE){ // Add to the map data. FileSyncData SData; SData.ETagData = ETagData; SData.DataFlag = DataFileStatus; ContactListFinal.ListData.insert(std::make_pair(DataFilename, SData)); } // Reset the values. HREFFound = FALSE; ETagFound = FALSE; HTTPStatus = FALSE; } if ((!xmlStrcmp(nodeLevel2->name, (const xmlChar *)"sync-token") || !xmlStrcmp(nodeLevel2->name, (const xmlChar *)"d:sync-token") || !xmlStrcmp(nodeLevel2->name, (const xmlChar *)"D:sync-token")) && SyncTokenFound == FALSE ){ for (nodeLevel3 = nodeLevel2->children; nodeLevel3 != NULL; nodeLevel3 = nodeLevel3->next) { if (!xmlStrcmp(nodeLevel3->name, (const xmlChar *)"text") || !xmlStrcmp(nodeLevel3->name, (const xmlChar *)"d:text") || !xmlStrcmp(nodeLevel3->name, (const xmlChar *)"D:text") ){ DataSyncToken = wxString::FromUTF8((const char*)nodeLevel3->content); SyncTokenFound = TRUE; } } } } } for (nodeLevel1 = xmlCardDAVDoc->children; nodeLevel1 != NULL; nodeLevel1 = nodeLevel1->next) { for (nodeLevel2 = nodeLevel1->children; nodeLevel2 != NULL; nodeLevel2 = nodeLevel2->next) { DataFileStatus = 0; bool HREFFound = FALSE; bool ETagFound = FALSE; bool HTTPStatus = FALSE; for (nodeLevel3 = nodeLevel2->children; nodeLevel3 != NULL; nodeLevel3 = nodeLevel3->next) { if (!xmlStrcmp(nodeLevel3->name, (const xmlChar *)"href") || !xmlStrcmp(nodeLevel3->name, (const xmlChar *)"d:href") || !xmlStrcmp(nodeLevel3->name, (const xmlChar *)"D:href") ){ // Get the filename. for (nodeLevel4 = nodeLevel3->children; nodeLevel4 != NULL; nodeLevel4 = nodeLevel4->next) { if (!xmlStrcmp(nodeLevel4->name, (const xmlChar *)"text") || !xmlStrcmp(nodeLevel4->name, (const xmlChar *)"d:text") || !xmlStrcmp(nodeLevel4->name, (const xmlChar *)"D:text") ){ DataFilename = wxString::FromUTF8((const char*)nodeLevel4->content); wxStringTokenizer wSTDFilename(DataFilename, wxT("/")); while (wSTDFilename.HasMoreTokens()){ DataFilename = wSTDFilename.GetNextToken(); } HREFFound = TRUE; } } } else { for (nodeLevel4 = nodeLevel3->children; nodeLevel4 != NULL; nodeLevel4 = nodeLevel4->next) { for (nodeStatusLv1 = nodeLevel3->children; nodeStatusLv1 != NULL; nodeStatusLv1 = nodeStatusLv1->next) { if (wxString::FromUTF8((const char*)nodeStatusLv1->content) == wxT("HTTP/1.1 404 Not Found")){ DataFileStatus = 2; HTTPStatus = TRUE; } if ((!xmlStrcmp(nodeStatusLv1->name, (const xmlChar *)"status") || !xmlStrcmp(nodeStatusLv1->name, (const xmlChar *)"d:status") || !xmlStrcmp(nodeStatusLv1->name, (const xmlChar *)"D:status")) && HTTPStatus == FALSE) { // Get the filename. for (nodeStatusLv2 = nodeStatusLv1->children; nodeStatusLv2 != NULL; nodeStatusLv2 = nodeStatusLv2->next) { if (!xmlStrcmp(nodeStatusLv2->name, (const xmlChar *)"text") || !xmlStrcmp(nodeStatusLv2->name, (const xmlChar *)"d:text") || !xmlStrcmp(nodeStatusLv2->name, (const xmlChar *)"D:text") ){ if (wxString::FromUTF8((const char*)nodeStatusLv2->content) == wxT("HTTP/1.1 200 OK")){ DataFileStatus = 1; HTTPStatus = TRUE; // This is currently in a WebDAV draft and may hopefully be enabled when this changes. //} else if (wxString::FromUTF8((const char*)nodeStatusLv2->content) == wxT("HTTP/1.1 201 Created")){ // DataFileStatus = 0; } } } } } for (nodeLevel5 = nodeLevel4->children; nodeLevel5 != NULL; nodeLevel5 = nodeLevel5->next) { if (!xmlStrcmp(nodeLevel5->name, (const xmlChar *)"getetag") || !xmlStrcmp(nodeLevel5->name, (const xmlChar *)"d:getetag") || !xmlStrcmp(nodeLevel5->name, (const xmlChar *)"D:getetag") ){ for (nodeLevel6 = nodeLevel5->children; nodeLevel6 != NULL; nodeLevel6 = nodeLevel6->next) { // Strip the quotes from the ETag. ETagData = wxString::FromUTF8((const char*)nodeLevel6->content); if (ETagData.Mid(0, 1) == wxT("\"") && ETagData.Mid((ETagData.Len() - 1), 1) == wxT("\"")){ ETagData.Remove(0, 1); ETagData.RemoveLast(); } ETagFound = TRUE; } } } } } } if (HREFFound == TRUE && HTTPStatus == TRUE && DataFileStatus == 2){ FileSyncData SData; SData.ETagData = wxT(""); SData.DataFlag = DataFileStatus; ContactListFinal.ListData.insert(std::make_pair(DataFilename, SData)); } if (HREFFound == TRUE && ETagFound == TRUE && HTTPStatus == TRUE){ // Add to the map data. FileSyncData SData; SData.ETagData = ETagData; SData.DataFlag = DataFileStatus; ContactListFinal.ListData.insert(std::make_pair(DataFilename, SData)); } // Reset the values. HREFFound = FALSE; ETagFound = FALSE; HTTPStatus = FALSE; DataFilename.Clear(); if ((!xmlStrcmp(nodeLevel2->name, (const xmlChar *)"sync-token") || !xmlStrcmp(nodeLevel2->name, (const xmlChar *)"d:sync-token") || !xmlStrcmp(nodeLevel2->name, (const xmlChar *)"D:sync-token")) && SyncTokenFound == FALSE ){ for (nodeLevel3 = nodeLevel2->children; nodeLevel3 != NULL; nodeLevel3 = nodeLevel3->next) { if (!xmlStrcmp(nodeLevel3->name, (const xmlChar *)"text") || !xmlStrcmp(nodeLevel3->name, (const xmlChar *)"d:text") || !xmlStrcmp(nodeLevel3->name, (const xmlChar *)"D:text") ){ DataSyncToken = wxString::FromUTF8((const char*)nodeLevel3->content); SyncTokenFound = TRUE; } } } } } // Get the sync token. if (SyncTokenFound == TRUE){ ContactListFinal.SyncToken = DataSyncToken; } else { } SleepFor(2000000000); /*timespec n1, n2; n1.tv_sec = 0; n1.tv_nsec = 2000000000L; nanosleep(&n1, &n2);*/ xmlFreeDoc(xmlCardDAVDoc); curl_easy_cleanup(conn); SyncDataBuffer.reset(); // Get the first result. return ContactListFinal; }