Home | News | Projects | Releases
Bugs | RFE | Repositories | Help
cf323387d84ec45a995ddd7c70992f8a8cd4b731
[xestiaab/.git] / source / carddav / carddav-serveretag.cpp
1 // carddav-serveretag.cpp - CardDAV Object - Server ETag subroutines.
2 //
3 // (c) 2012-2015 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 "carddav.h"
20 #include "../version.h"
21 #include <wx/wx.h>
22 #include <wx/tokenzr.h>
23 #include <wx/ffile.h>
24 #include <libxml/parser.h>
25 #include <libxml/tree.h>
26 #include <map>
27 #include <thread>
28 #include "../vcard/vcard.h"
29 #include "../common/dirs.h"
31 void CardDAV::GetServerETagValueThread()
32 {
33         
34         // Get the server etag value (threaded).
36         PageData.Clear();
37         PageHeader.Clear();
39         SSLStatus = TRUE;
40         AuthPassed = TRUE;
41         AbortConnection = FALSE;
42         
43         bool FilenameIsDirectory = FALSE;
44         CURL *conn;
45         CURLcode conncode;
46         wxString ServerAddressURL;
47         wxString ServerAuth;
48         wxString ServerAddressSSL;
49         wxString ServerAddressNormal;   
51         conn = curl_easy_init();
52         
53         struct CardDAVCURLPasser {
54         
55                 CardDAV *Data;
56                 bool HeaderMode = TRUE;
57         
58         } CardDAVHeader, CardDAVFooter;
60         CardDAVHeader.Data = this;
61         CardDAVHeader.HeaderMode = TRUE;
62         
63         CardDAVFooter.Data = this;
64         CardDAVFooter.HeaderMode = FALSE;
66         wxString Data1;
67         wxString Data2;
68         
69         ServerAddressURL = ServerAddress + wxT(":") + wxString::Format(wxT("%i"), ServerPort) + wxT("/") + ServerPrefix + ServerFilenameLocation;
70         ServerAddressSSL = wxT("https://") + ServerAddressURL;
71         ServerAddressNormal = wxT("http://") + ServerAddressURL;
72         
73         ServerAuth = ServerUser + wxT(":") + ServerPass;
75         std::map<int,int>::iterator ActIter;
76         struct UploadDataStruc UploadData;
77         
78         
79         ActIter = ActivityListPtr->find((int)ItemIndex);
80         
81         static const char* query =
82         "<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
83         "<C:addressbook-query xmlns:D=\"DAV:\""
84         "       xmlns:C=\"urn:ietf:params:xml:ns:carddav\">"
85         "<D:prop><D:getetag/>"
86         "</D:prop>"
87         "<C:filter/>"
88         "</C:addressbook-query>";
90         if (ServerSSL){
92                 wxString ServerCertFilename;
93                 bool MatchingCert = FALSE;
95                 curl_easy_setopt(conn, CURLOPT_URL, (const char*)ServerAddressSSL.mb_str(wxConvUTF8));
96                 curl_easy_setopt(conn, CURLOPT_NOPROGRESS, 0);
97                 curl_easy_setopt(conn, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
98                 curl_easy_setopt(conn, CURLOPT_TIMEOUT, 60);
99                 curl_easy_setopt(conn, CURLOPT_FAILONERROR, TRUE);
100                 curl_easy_setopt(conn, CURLOPT_USERAGENT, XSDAB_USERAGENT);
101                 curl_easy_setopt(conn, CURLOPT_USERPWD, (const char*)ServerAuth.mb_str(wxConvUTF8));
102                 curl_easy_setopt(conn, CURLOPT_WRITEFUNCTION, WritebackFunc);
103                 curl_easy_setopt(conn, CURLOPT_WRITEDATA, &PageData);
104                 curl_easy_setopt(conn, CURLOPT_WRITEHEADER, &PageHeader);
105                 curl_easy_setopt(conn, CURLOPT_PROGRESSDATA, this);
106                 curl_easy_setopt(conn, CURLOPT_PROGRESSFUNCTION, ProgressFunc);
107                 curl_easy_setopt(conn, CURLOPT_CUSTOMREQUEST, "REPORT");
108                 curl_easy_setopt(conn, CURLOPT_NOSIGNAL, 1);
109                 curl_easy_setopt(conn, CURLOPT_POSTFIELDS, query);
110                 curl_easy_setopt(conn, CURLOPT_POSTFIELDSIZE, strlen(query));
112                 ServerCertFilename = GetAccountDir(ServerAccount, TRUE);
114                 if (wxFile::Exists(ServerCertFilename) == TRUE){
115                 
116                         curl_easy_setopt(conn, CURLOPT_SSL_VERIFYPEER, 1);
117                         curl_easy_setopt(conn, CURLOPT_SSL_VERIFYHOST, 2);
118                         curl_easy_setopt(conn, CURLOPT_CAINFO, (const char*)ServerCertFilename.mb_str(wxConvUTF8));
119                 
120                 }
122                 claconncode = (curl_easy_perform(conn));
124                 // If CURLE_PEER_FAILED_VERIFICATION is returned, retry without
125                 // the local certificate in use.
127                 if (claconncode == CURLE_PEER_FAILED_VERIFICATION){
128                         
129                         curl_easy_cleanup(conn);
130                         conn = curl_easy_init();
131                         
132                         curl_easy_setopt(conn, CURLOPT_URL, (const char*)ServerAddressSSL.mb_str(wxConvUTF8));
133                         curl_easy_setopt(conn, CURLOPT_NOPROGRESS, 0);
134                         curl_easy_setopt(conn, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
135                         curl_easy_setopt(conn, CURLOPT_TIMEOUT, 60);
136                         curl_easy_setopt(conn, CURLOPT_FAILONERROR, TRUE);
137                         curl_easy_setopt(conn, CURLOPT_USERAGENT, XSDAB_USERAGENT);
138                         curl_easy_setopt(conn, CURLOPT_USERPWD, (const char*)ServerAuth.mb_str(wxConvUTF8));
139                         curl_easy_setopt(conn, CURLOPT_WRITEFUNCTION, WritebackFunc);
140                         curl_easy_setopt(conn, CURLOPT_WRITEDATA, &PageData);
141                         curl_easy_setopt(conn, CURLOPT_WRITEHEADER, &PageHeader);
142                         curl_easy_setopt(conn, CURLOPT_PROGRESSDATA, this);
143                         curl_easy_setopt(conn, CURLOPT_PROGRESSFUNCTION, ProgressFunc);
144                         curl_easy_setopt(conn, CURLOPT_CUSTOMREQUEST, "REPORT");
145                         curl_easy_setopt(conn, CURLOPT_NOSIGNAL, 1);
146                         curl_easy_setopt(conn, CURLOPT_POSTFIELDS, query);
147                         curl_easy_setopt(conn, CURLOPT_POSTFIELDSIZE, strlen(query));
148                         
149                         claconncode = (curl_easy_perform(conn));
150                         
151                         // If claconncode is CURLE_OK then delete the certificate file as that
152                         // is no longer needed.
153                         
154                         if (claconncode == CURLE_OK){
155                         
156                                 // Delete the certificate file.
157                                 
158                                 wxRemoveFile(ServerCertFilename);
159                         
160                         }
161                 
162                 }
164                 // Check if it fails with a CURLE_SSL_CACERT then compare
165                 // the certificates as PEM files.
166                 
167                 if (claconncode == CURLE_SSL_CACERT && wxFile::Exists(ServerCertFilename) == TRUE){
169                         CURL *sslerrconn;
170                         sslerrconn = curl_easy_init();
171                         CURLcode sslerrconncode;
173                         wxString ServerAddressOnly = wxT("https://") + ServerAddress + wxT(":") + wxString::Format(wxT("%i"), ServerPort) + wxT("/");
175                         PageData.clear();
176                         PageHeader.clear();
178                         curl_easy_setopt(sslerrconn, CURLOPT_URL, (const char*)ServerAddressOnly.mb_str(wxConvUTF8));
179                         curl_easy_setopt(sslerrconn, CURLOPT_NOPROGRESS, 0);
180                         curl_easy_setopt(sslerrconn, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
181                         curl_easy_setopt(sslerrconn, CURLOPT_TIMEOUT, 60);
182                         curl_easy_setopt(sslerrconn, CURLOPT_FAILONERROR, TRUE);
183                         curl_easy_setopt(sslerrconn, CURLOPT_USERAGENT, XSDAB_USERAGENT);
184                         curl_easy_setopt(sslerrconn, CURLOPT_WRITEFUNCTION, WritebackFunc);
185                         curl_easy_setopt(sslerrconn, CURLOPT_WRITEDATA, &PageData);
186                         curl_easy_setopt(sslerrconn, CURLOPT_WRITEHEADER, &PageHeader);
187                         curl_easy_setopt(sslerrconn, CURLOPT_PROGRESSDATA, this);
188                         curl_easy_setopt(sslerrconn, CURLOPT_PROGRESSFUNCTION, ProgressFunc);
189                         curl_easy_setopt(sslerrconn, CURLOPT_NOSIGNAL, 1);
190                         curl_easy_setopt(sslerrconn, CURLOPT_SSL_VERIFYPEER, 0);
191                         curl_easy_setopt(sslerrconn, CURLOPT_CERTINFO, 1);
192                         curl_easy_setopt(sslerrconn, CURLOPT_SSL_VERIFYPEER, 1);
193                         curl_easy_setopt(sslerrconn, CURLOPT_SSL_VERIFYHOST, 2);
194                         curl_easy_setopt(sslerrconn, CURLOPT_CAINFO, (const char*)ServerCertFilename.mb_str(wxConvUTF8));
195                 
196                         wxString SSLLocalData;
197                         wxString SSLServerData;
198                 
199                         sslerrconncode = (curl_easy_perform(sslerrconn));
200                 
201                         SSLCertCol = BuildSSLCollection(sslerrconn);
202                         std::map<int, SSLCertData>::iterator SSLCDIter = SSLCertCol.SSLCollection.find(0);
203                         std::multimap<wxString,wxString>::iterator SSLDataIter = SSLCDIter->second.CertData.find(wxT("Cert"));
204                         
205                         wxFFile SSLLocalFile;
206                         
207 #if wxABI_VERSION < 20900
208                         SSLLocalFile.Open(ServerCertFilename.c_str(), wxT("r"));
209 #else
210                         SSLLocalFile.Open(ServerCertFilename, wxT("r"));
211 #endif  
213                         // Load the recovery database for tasks not done.
214         
215                         if (SSLLocalFile.IsOpened() == TRUE){
217                         // Check if we are using wxWidgets version 2.8 or less and
218                         // execute the required command accordingly.
219         
220                                 SSLLocalFile.ReadAll(&SSLLocalData, wxConvAuto());
221                 
222         
223                         }
224                         
225                         SSLServerData = SSLDataIter->second;
226                         
227                         if (SSLLocalData == SSLServerData){
228                         
229                                 // Server key matches with local key so retry with CURLOPT_SSL_VERIFYPEER
230                                 // and CURLOPT_SSL_VERIFYHOST off.
231                         
232                                 curl_easy_cleanup(conn);
233                                 conn = curl_easy_init();
234                                 
235                                 PageData.clear();
236                                 PageHeader.clear();
237                         
238                                 curl_easy_setopt(conn, CURLOPT_URL, (const char*)ServerAddressSSL.mb_str(wxConvUTF8));
239                                 curl_easy_setopt(conn, CURLOPT_NOPROGRESS, 0);
240                                 curl_easy_setopt(conn, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
241                                 curl_easy_setopt(conn, CURLOPT_TIMEOUT, 60);
242                                 curl_easy_setopt(conn, CURLOPT_FAILONERROR, TRUE);
243                                 curl_easy_setopt(conn, CURLOPT_USERAGENT, XSDAB_USERAGENT);
244                                 curl_easy_setopt(conn, CURLOPT_USERPWD, (const char*)ServerAuth.mb_str(wxConvUTF8));
245                                 curl_easy_setopt(conn, CURLOPT_WRITEFUNCTION, WritebackFunc);
246                                 curl_easy_setopt(conn, CURLOPT_WRITEDATA, &PageData);
247                                 curl_easy_setopt(conn, CURLOPT_WRITEHEADER, &PageHeader);
248                                 curl_easy_setopt(conn, CURLOPT_PROGRESSDATA, this);
249                                 curl_easy_setopt(conn, CURLOPT_PROGRESSFUNCTION, ProgressFunc);
250                                 curl_easy_setopt(conn, CURLOPT_CUSTOMREQUEST, "REPORT");
251                                 curl_easy_setopt(conn, CURLOPT_NOSIGNAL, 1);
252                                 curl_easy_setopt(conn, CURLOPT_POSTFIELDS, query);
253                                 curl_easy_setopt(conn, CURLOPT_POSTFIELDSIZE, strlen(query));
254                                 curl_easy_setopt(conn, CURLOPT_SSL_VERIFYPEER, 0);
255                                 curl_easy_setopt(conn, CURLOPT_SSL_VERIFYHOST, 0);              
256                         
257                                 claconncode = (curl_easy_perform(conn));
258                                 
259                                 MatchingCert = TRUE;
260                         
261                         }
262                         
263                         if (MatchingCert == FALSE){
264                 
265                                 claconncode = CURLE_SSL_CACERT;
266                                 return;
267                 
268                         }
269                         
270                         curl_easy_cleanup(sslerrconn);
271                 
272                 }
274                 // Sort out SSL error.
275                 
276                 // When SSL cert error occurs, connect again and fetch certificates.
277                 // Display a message to the user explaining that an invalid
278                 // certificate has been given and let the user decide what
279                 // to do next.
281                 if (claconncode == CURLE_OK){
283                 } else if (claconncode == CURLE_SSL_CACERT || claconncode == CURLE_PEER_FAILED_VERIFICATION){
284                 
285                         CURL *sslerrconn;
286                         sslerrconn = curl_easy_init();
287                         CURLcode sslerrconncode;
288                 
289                         wxString ServerAddressOnly = wxT("https://") + ServerAddress + wxT(":") + wxString::Format(wxT("%i"), ServerPort) + wxT("/");
290                 
291                         // Replace conn with sslerrconn!
292                 
293                         curl_easy_setopt(sslerrconn, CURLOPT_URL, (const char*)ServerAddressOnly.mb_str(wxConvUTF8));
294                         curl_easy_setopt(sslerrconn, CURLOPT_NOPROGRESS, 0);
295                         curl_easy_setopt(sslerrconn, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
296                         curl_easy_setopt(sslerrconn, CURLOPT_TIMEOUT, 60);
297                         curl_easy_setopt(sslerrconn, CURLOPT_FAILONERROR, TRUE);
298                         curl_easy_setopt(sslerrconn, CURLOPT_USERAGENT, XSDAB_USERAGENT);
299                         curl_easy_setopt(sslerrconn, CURLOPT_WRITEFUNCTION, WritebackFunc);
300                         curl_easy_setopt(sslerrconn, CURLOPT_WRITEDATA, &PageData);
301                         curl_easy_setopt(sslerrconn, CURLOPT_WRITEHEADER, &PageHeader);
302                         curl_easy_setopt(sslerrconn, CURLOPT_PROGRESSDATA, this);
303                         curl_easy_setopt(sslerrconn, CURLOPT_PROGRESSFUNCTION, ProgressFunc);
304                         curl_easy_setopt(sslerrconn, CURLOPT_NOSIGNAL, 1);
305                         curl_easy_setopt(sslerrconn, CURLOPT_SSL_VERIFYPEER, 0);
306                         curl_easy_setopt(sslerrconn, CURLOPT_CERTINFO, 1);
307                                         
308                         sslerrconncode = (curl_easy_perform(sslerrconn));
310                         SSLCertCol = BuildSSLCollection(sslerrconn);
311                         SSLCertCol.SuccessCode = 1;
313                         curl_easy_cleanup(conn);
314                         curl_easy_cleanup(sslerrconn);
316                         return;
317                 
318                 } else if (claconncode == CURLE_HTTP_RETURNED_ERROR){
319                 
320                         fprintf(stderr, "curl_easy_perform() failed: %s\n",
321                                         curl_easy_strerror(claconncode));
322                         int http_code = 0;
323                         curl_easy_getinfo(conn, CURLINFO_RESPONSE_CODE, &http_code);
324                         fprintf(stderr, "Error code was: %d\n", http_code);
326                         curl_easy_cleanup(conn);
327                                         
328                         return;
329                 
330                 } else {
332                         fprintf(stderr, "curl_easy_perform() failed: %s\n",
333                                         curl_easy_strerror(claconncode));
334                         int http_code = 0;
335                         curl_easy_getinfo(conn, CURLINFO_RESPONSE_CODE, &http_code);
336                         fprintf(stderr, "Error code was: %d\n", http_code);
338                         curl_easy_cleanup(conn);
340                         return;
342                 }
344         } else {
345         
346                 // No SSL.
347         
348                 wxString EmptyString;
349                 
350                 curl_easy_setopt(conn, CURLOPT_URL, (const char*)ServerAddressNormal.mb_str(wxConvUTF8));
351                 curl_easy_setopt(conn, CURLOPT_NOPROGRESS, 0);
352                 curl_easy_setopt(conn, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
353                 curl_easy_setopt(conn, CURLOPT_TIMEOUT, 60);
354                 curl_easy_setopt(conn, CURLOPT_FAILONERROR, TRUE);
355                 curl_easy_setopt(conn, CURLOPT_USERAGENT, XSDAB_USERAGENT);
356                 curl_easy_setopt(conn, CURLOPT_USERPWD, (const char*)ServerAuth.mb_str(wxConvUTF8));
357                 curl_easy_setopt(conn, CURLOPT_WRITEFUNCTION, WritebackFunc);
358                 curl_easy_setopt(conn, CURLOPT_WRITEDATA, &PageData);
359                 curl_easy_setopt(conn, CURLOPT_WRITEHEADER, &PageHeader);
360                 curl_easy_setopt(conn, CURLOPT_PROGRESSDATA, this);
361                 curl_easy_setopt(conn, CURLOPT_PROGRESSFUNCTION, ProgressFunc);
362                 curl_easy_setopt(conn, CURLOPT_CUSTOMREQUEST, "REPORT");
363                 curl_easy_setopt(conn, CURLOPT_NOSIGNAL, 1);
364                 curl_easy_setopt(conn, CURLOPT_POSTFIELDS, query);
365                 curl_easy_setopt(conn, CURLOPT_POSTFIELDSIZE, strlen(query));           
366                 
367                 PageData.Clear();
368                 PageHeader.Clear();
369                 
370                 conncode = (curl_easy_perform(conn));
372                 if (conncode == CURLE_OK){
374                 } else if (conncode == CURLE_HTTP_RETURNED_ERROR){
375                 
376                         fprintf(stderr, "curl_easy_perform() failed: %s\n",
377                                         curl_easy_strerror(conncode));
378                                 
379                         return;
380                 
381                 } else {
383                         fprintf(stderr, "curl_easy_perform() failed: %s\n",
384                                         curl_easy_strerror(conncode));
385                                 
386                         return;
388                 }
389                 
390         }
391         
392         xmlDocPtr xmlCardDAVDoc;
394         xmlCardDAVDoc = xmlReadMemory(PageData.mb_str(wxConvUTF8), (int)PageData.Len(), "noname.xml", NULL, 0);
396         xmlNodePtr nodeLevel1;
397         xmlNodePtr nodeLevel2;
398         xmlNodePtr nodeLevel3;
399         xmlNodePtr nodeLevel4;
400         xmlNodePtr nodeLevel5;
401         xmlNodePtr nodeLevel6;
403         std::map<wxString,wxString> xmlDataMap;
405         wxString DataFilename;
406         wxString ETagData;
408         std::string xmlStringSafe;
410         // Tranverse through the catacombs of the response to get our ETag for the file.
412         for (nodeLevel1 = xmlCardDAVDoc->children;
413                 nodeLevel1 != NULL;
414                 nodeLevel1 = nodeLevel1->next)
415         {
417                 bool HREFFound = FALSE;
418                 bool ETagFound = FALSE;
420                 for (nodeLevel2 = nodeLevel1->children;
421                         nodeLevel2 != NULL;
422                         nodeLevel2 = nodeLevel2->next)
423                 {
425                         for (nodeLevel3 = nodeLevel2->children;
426                         nodeLevel3 != NULL;
427                         nodeLevel3 = nodeLevel3->next)
428                         {
430                                 if (!xmlStrcmp(nodeLevel3->name, (const xmlChar *)"href") ||
431                                 !xmlStrcmp(nodeLevel3->name, (const xmlChar *)"d:href") ||
432                                 !xmlStrcmp(nodeLevel3->name, (const xmlChar *)"D:href")
433                                 ){
435                                         // Get the filename.
436                                         
437                                         for (nodeLevel4 = nodeLevel3->children;
438                                         nodeLevel4 != NULL;
439                                         nodeLevel4 = nodeLevel4->next)
440                                         {
441                                         
442                                                 if (!xmlStrcmp(nodeLevel4->name, (const xmlChar *)"text") ||
443                                                 !xmlStrcmp(nodeLevel4->name, (const xmlChar *)"d:text") ||
444                                                 !xmlStrcmp(nodeLevel4->name, (const xmlChar *)"D:text")
445                                                 ){
447                                                         DataFilename = wxString::FromUTF8((const char*)nodeLevel4->content);
448                                                         wxStringTokenizer wSTDFilename(DataFilename, wxT("/"));
449                                                 
450                                                         while (wSTDFilename.HasMoreTokens()){
451                                                         
452                                                                 DataFilename = wSTDFilename.GetNextToken();
453                                                         
454                                                         }
455                                                         
456                                                         HREFFound = TRUE;
457                                                 
458                                                 }
459                                                 
460         
461                                         
462                                         }
464                                 } else {
466                                         for (nodeLevel4 = nodeLevel3->children;
467                                         nodeLevel4 != NULL;
468                                         nodeLevel4 = nodeLevel4->next)
469                                         {
470                                                         
471                                                         for (nodeLevel5 = nodeLevel4->children;
472                                                         nodeLevel5 != NULL;
473                                                         nodeLevel5 = nodeLevel5->next)
474                                                         {
476                                                                 if (!xmlStrcmp(nodeLevel5->name, (const xmlChar *)"getetag") ||
477                                                                 !xmlStrcmp(nodeLevel5->name, (const xmlChar *)"d:getetag") ||
478                                                                 !xmlStrcmp(nodeLevel5->name, (const xmlChar *)"D:getetag")
479                                                                 ){
481                                                                         for (nodeLevel6 = nodeLevel5->children;
482                                                                         nodeLevel6 != NULL;
483                                                                         nodeLevel6 = nodeLevel6->next)
484                                                                         {
485                                                         
486                                                                                 // Strip the quotes from the ETag.
487                                                         
488                                                                                 ETagData = wxString::FromUTF8((const char*)nodeLevel6->content);
489                                                                                 if (ETagData.Mid(0, 1) == wxT("\"") && ETagData.Mid((ETagData.Len() - 1), 1) == wxT("\"")){
490                                                         
491                                                                                         ETagData.Remove(0, 1);
492                                                                                         ETagData.RemoveLast();
493                                                         
494                                                                                 }
495                                                                         
496                                                                                 ETagFound = TRUE;
498                                                                         }
499                                                                         
500                                                                 }
502                                                         }       
504                                         }
506                                 }
508                         }
510                 }
511                 
512                 if (HREFFound == TRUE && ETagFound == TRUE){
513                                 
514                         // Add to the map data.
515                                         
516                         xmlDataMap.insert(std::make_pair(DataFilename, ETagData));
517                                 
518                         HREFFound = FALSE;
519                         ETagFound = FALSE;
520                                 
521                 }
524         }
526         xmlFreeDoc(xmlCardDAVDoc);
528         // Get the first result.
530         for (std::map<wxString,wxString>::iterator iter = xmlDataMap.begin(); 
531                 iter != xmlDataMap.end(); ++iter){
532         
533                 ETagResult = iter->second;
534                 break;
535                 
536         }
537         
538         if (ETagResult.IsEmpty()){
539         
540                 return;
541         
542         }
543         
544         return;
545         
548 void CardDAV::GetServerETagValue(){
550         // Get the server etag value.
551         
552         std::thread ConnectThread(&CardDAV::GetServerETagValueThread, this);
553         ConnectThread.detach();
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