2 #include "../version.h"
4 #include <wx/tokenzr.h>
6 #include <libxml/parser.h>
7 #include <libxml/tree.h>
10 #include "../vcard/vcard.h"
11 #include "../common/dirs.h"
13 void CardDAV::GetServerETagValueThread()
21 AbortConnection = FALSE;
23 bool FilenameIsDirectory = FALSE;
26 wxString ServerAddressURL;
28 wxString ServerAddressSSL;
29 wxString ServerAddressNormal;
31 conn = curl_easy_init();
33 struct CardDAVCURLPasser {
36 bool HeaderMode = TRUE;
38 } CardDAVHeader, CardDAVFooter;
40 CardDAVHeader.Data = this;
41 CardDAVHeader.HeaderMode = TRUE;
43 CardDAVFooter.Data = this;
44 CardDAVFooter.HeaderMode = FALSE;
49 ServerAddressURL = ServerAddress + wxT(":") + wxString::Format(wxT("%i"), ServerPort) + wxT("/") + ServerPrefix + ServerFilenameLocation;
50 ServerAddressSSL = wxT("https://") + ServerAddressURL;
51 ServerAddressNormal = wxT("http://") + ServerAddressURL;
53 ServerAuth = ServerUser + wxT(":") + ServerPass;
55 // Workout if path is directory or filename.
58 FilenameIsDirectory = TRUE;
60 FilenameIsDirectory = FALSE;
67 char *ServerAdrSSLChar = new char[(ServerAddressSSL.Length() - 1)];
68 //memset(ServerAdrSSLChar, 0, ServerAddressSSL.Length());
69 strncpy(ServerAdrSSLChar, (const char*)ServerAddressSSL.mb_str(wxConvUTF8), (ServerAddressSSL.Length() - 1));
71 char *ServerAdrNorChar = new char[(ServerAddressNormal.Length() - 1)];
72 //memset(ServerAdrNorChar, 0, ServerAddressSSL.Length());
73 strncpy(ServerAdrNorChar, (const char*)ServerAddressNormal.mb_str(wxConvUTF8), (ServerAddressNormal.Length() - 1));
75 char *ServerAuthChar = new char[(ServerAuth.Length() - 1)];
76 //memset(ServerAuthChar, 0, ServerAddressSSL.Length());
77 strncpy(ServerAuthChar, (const char*)ServerAuth.mb_str(wxConvUTF8), (ServerAuth.Length() - 1));
81 //std::string WriteDataString = std::string(ServerUploadData.mb_str());
83 std::map<int,int>::iterator ActIter;
84 struct UploadDataStruc UploadData;
87 ActIter = ActivityListPtr->find((int)ItemIndex);
89 static const char* query =
90 "<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
91 "<C:addressbook-query xmlns:D=\"DAV:\""
92 " xmlns:C=\"urn:ietf:params:xml:ns:carddav\">"
93 "<D:prop><D:getetag/>"
96 //"</C:address-data></D:prop>"
99 "</C:addressbook-query>";
103 wxString ServerCertFilename;
104 bool MatchingCert = FALSE;
106 curl_easy_setopt(conn, CURLOPT_URL, (const char*)ServerAddressSSL.mb_str(wxConvUTF8));
107 curl_easy_setopt(conn, CURLOPT_NOPROGRESS, 0);
108 curl_easy_setopt(conn, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
109 curl_easy_setopt(conn, CURLOPT_TIMEOUT, 60);
110 curl_easy_setopt(conn, CURLOPT_FAILONERROR, TRUE);
111 curl_easy_setopt(conn, CURLOPT_USERAGENT, XSDAB_USERAGENT);
112 curl_easy_setopt(conn, CURLOPT_USERPWD, (const char*)ServerAuth.mb_str(wxConvUTF8));
113 curl_easy_setopt(conn, CURLOPT_WRITEFUNCTION, WritebackFunc);
114 curl_easy_setopt(conn, CURLOPT_WRITEDATA, &PageData);
115 curl_easy_setopt(conn, CURLOPT_WRITEHEADER, &PageHeader);
116 curl_easy_setopt(conn, CURLOPT_PROGRESSDATA, this);
117 curl_easy_setopt(conn, CURLOPT_PROGRESSFUNCTION, ProgressFunc);
118 curl_easy_setopt(conn, CURLOPT_CUSTOMREQUEST, "REPORT");
119 curl_easy_setopt(conn, CURLOPT_NOSIGNAL, 1);
121 //UploadData.readptr = &CardDAVDataQuery;
122 //UploadData.sizeleft = CardDAVDataQuery.Len();
123 //curl_easy_setopt(conn, CURLOPT_UPLOAD, 1);
124 //curl_easy_setopt(conn, CURLOPT_READDATA, &UploadData);
125 //curl_easy_setopt(conn, CURLOPT_READFUNCTION, UploadReadFunc);
127 //curl_easy_setopt(conn, CURLOPT_WRITEFUNCTION, writefunc);
128 curl_easy_setopt(conn, CURLOPT_POSTFIELDS, query);
129 curl_easy_setopt(conn, CURLOPT_POSTFIELDSIZE, strlen(query));
131 ServerCertFilename = GetAccountDir(ServerAccount, TRUE);
133 if (wxFile::Exists(ServerCertFilename) == TRUE){
135 curl_easy_setopt(conn, CURLOPT_SSL_VERIFYPEER, 1);
136 curl_easy_setopt(conn, CURLOPT_SSL_VERIFYHOST, 2);
137 curl_easy_setopt(conn, CURLOPT_CAINFO, (const char*)ServerCertFilename.mb_str(wxConvUTF8));
141 claconncode = (curl_easy_perform(conn));
143 // If CURLE_PEER_FAILED_VERIFICATION is returned, retry without
144 // the local certificate in use.
146 if (claconncode == CURLE_PEER_FAILED_VERIFICATION){
148 curl_easy_cleanup(conn);
149 conn = curl_easy_init();
151 curl_easy_setopt(conn, CURLOPT_URL, (const char*)ServerAddressSSL.mb_str(wxConvUTF8));
152 curl_easy_setopt(conn, CURLOPT_NOPROGRESS, 0);
153 curl_easy_setopt(conn, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
154 curl_easy_setopt(conn, CURLOPT_TIMEOUT, 60);
155 curl_easy_setopt(conn, CURLOPT_FAILONERROR, TRUE);
156 curl_easy_setopt(conn, CURLOPT_USERAGENT, XSDAB_USERAGENT);
157 curl_easy_setopt(conn, CURLOPT_USERPWD, (const char*)ServerAuth.mb_str(wxConvUTF8));
158 curl_easy_setopt(conn, CURLOPT_WRITEFUNCTION, WritebackFunc);
159 curl_easy_setopt(conn, CURLOPT_WRITEDATA, &PageData);
160 curl_easy_setopt(conn, CURLOPT_WRITEHEADER, &PageHeader);
161 curl_easy_setopt(conn, CURLOPT_PROGRESSDATA, this);
162 curl_easy_setopt(conn, CURLOPT_PROGRESSFUNCTION, ProgressFunc);
163 curl_easy_setopt(conn, CURLOPT_CUSTOMREQUEST, "REPORT");
164 curl_easy_setopt(conn, CURLOPT_NOSIGNAL, 1);
165 curl_easy_setopt(conn, CURLOPT_POSTFIELDS, query);
166 curl_easy_setopt(conn, CURLOPT_POSTFIELDSIZE, strlen(query));
168 claconncode = (curl_easy_perform(conn));
170 // If claconncode is CURLE_OK then delete the certificate file as that
171 // is no longer needed.
173 if (claconncode == CURLE_OK){
175 // Delete the certificate file.
177 wxRemoveFile(ServerCertFilename);
183 // Check if it fails with a CURLE_SSL_CACERT then compare
184 // the certificates as PEM files.
186 if (claconncode == CURLE_SSL_CACERT && wxFile::Exists(ServerCertFilename) == TRUE){
188 //curl_easy_cleanup(conn);
189 //conn = curl_easy_init();
192 sslerrconn = curl_easy_init();
193 CURLcode sslerrconncode;
195 //claconncode = (curl_easy_perform(conn));
197 wxString ServerAddressOnly = wxT("https://") + ServerAddress + wxT(":") + wxString::Format(wxT("%i"), ServerPort) + wxT("/");
202 curl_easy_setopt(sslerrconn, CURLOPT_URL, (const char*)ServerAddressOnly.mb_str(wxConvUTF8));
203 curl_easy_setopt(sslerrconn, CURLOPT_NOPROGRESS, 0);
204 curl_easy_setopt(sslerrconn, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
205 curl_easy_setopt(sslerrconn, CURLOPT_TIMEOUT, 60);
206 curl_easy_setopt(sslerrconn, CURLOPT_FAILONERROR, TRUE);
207 curl_easy_setopt(sslerrconn, CURLOPT_USERAGENT, XSDAB_USERAGENT);
208 curl_easy_setopt(sslerrconn, CURLOPT_WRITEFUNCTION, WritebackFunc);
209 curl_easy_setopt(sslerrconn, CURLOPT_WRITEDATA, &PageData);
210 curl_easy_setopt(sslerrconn, CURLOPT_WRITEHEADER, &PageHeader);
211 curl_easy_setopt(sslerrconn, CURLOPT_PROGRESSDATA, this);
212 curl_easy_setopt(sslerrconn, CURLOPT_PROGRESSFUNCTION, ProgressFunc);
213 curl_easy_setopt(sslerrconn, CURLOPT_NOSIGNAL, 1);
214 curl_easy_setopt(sslerrconn, CURLOPT_SSL_VERIFYPEER, 0);
215 curl_easy_setopt(sslerrconn, CURLOPT_CERTINFO, 1);
216 curl_easy_setopt(sslerrconn, CURLOPT_SSL_VERIFYPEER, 1);
217 curl_easy_setopt(sslerrconn, CURLOPT_SSL_VERIFYHOST, 2);
218 curl_easy_setopt(sslerrconn, CURLOPT_CAINFO, (const char*)ServerCertFilename.mb_str(wxConvUTF8));
220 wxString SSLLocalData;
221 wxString SSLServerData;
223 sslerrconncode = (curl_easy_perform(sslerrconn));
225 SSLCertCol = BuildSSLCollection(sslerrconn);
226 std::map<int, SSLCertData>::iterator SSLCDIter = SSLCertCol.SSLCollection.find(0);
227 std::multimap<wxString,wxString>::iterator SSLDataIter = SSLCDIter->second.CertData.find(wxT("Cert"));
229 wxFFile SSLLocalFile;
231 #if wxABI_VERSION < 20900
232 SSLLocalFile.Open(ServerCertFilename.c_str(), wxT("r"));
234 SSLLocalFile.Open(ServerCertFilename, wxT("r"));
237 // Load the recovery database for tasks not done.
239 if (SSLLocalFile.IsOpened() == TRUE){
241 // Check if we are using wxWidgets version 2.8 or less and
242 // execute the required command accordingly.
244 SSLLocalFile.ReadAll(&SSLLocalData, wxConvAuto());
249 SSLServerData = SSLDataIter->second;
251 if (SSLLocalData == SSLServerData){
253 // Server key matches with local key so retry with CURLOPT_SSL_VERIFYPEER
254 // and CURLOPT_SSL_VERIFYHOST off.
256 curl_easy_cleanup(conn);
257 conn = curl_easy_init();
262 curl_easy_setopt(conn, CURLOPT_URL, (const char*)ServerAddressSSL.mb_str(wxConvUTF8));
263 curl_easy_setopt(conn, CURLOPT_NOPROGRESS, 0);
264 curl_easy_setopt(conn, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
265 curl_easy_setopt(conn, CURLOPT_TIMEOUT, 60);
266 curl_easy_setopt(conn, CURLOPT_FAILONERROR, TRUE);
267 curl_easy_setopt(conn, CURLOPT_USERAGENT, XSDAB_USERAGENT);
268 curl_easy_setopt(conn, CURLOPT_USERPWD, (const char*)ServerAuth.mb_str(wxConvUTF8));
269 curl_easy_setopt(conn, CURLOPT_WRITEFUNCTION, WritebackFunc);
270 curl_easy_setopt(conn, CURLOPT_WRITEDATA, &PageData);
271 curl_easy_setopt(conn, CURLOPT_WRITEHEADER, &PageHeader);
272 curl_easy_setopt(conn, CURLOPT_PROGRESSDATA, this);
273 curl_easy_setopt(conn, CURLOPT_PROGRESSFUNCTION, ProgressFunc);
274 curl_easy_setopt(conn, CURLOPT_CUSTOMREQUEST, "REPORT");
275 curl_easy_setopt(conn, CURLOPT_NOSIGNAL, 1);
276 curl_easy_setopt(conn, CURLOPT_POSTFIELDS, query);
277 curl_easy_setopt(conn, CURLOPT_POSTFIELDSIZE, strlen(query));
278 curl_easy_setopt(conn, CURLOPT_SSL_VERIFYPEER, 0);
279 curl_easy_setopt(conn, CURLOPT_SSL_VERIFYHOST, 0);
281 claconncode = (curl_easy_perform(conn));
287 if (MatchingCert == FALSE){
289 claconncode = CURLE_SSL_CACERT;
294 curl_easy_cleanup(sslerrconn);
298 // Sort out SSL error.
300 // When SSL cert error occurs, connect again and fetch certificates.
301 // Display a message to the user explaining that an invalid
302 // certificate has been given and let the user decide what
305 if (claconncode == CURLE_OK){
307 } else if (claconncode == CURLE_SSL_CACERT || claconncode == CURLE_PEER_FAILED_VERIFICATION){
310 sslerrconn = curl_easy_init();
311 CURLcode sslerrconncode;
313 wxString ServerAddressOnly = wxT("https://") + ServerAddress + wxT(":") + wxString::Format(wxT("%i"), ServerPort) + wxT("/");
315 // Replace conn with sslerrconn!
317 curl_easy_setopt(sslerrconn, CURLOPT_URL, (const char*)ServerAddressOnly.mb_str(wxConvUTF8));
318 curl_easy_setopt(sslerrconn, CURLOPT_NOPROGRESS, 0);
319 curl_easy_setopt(sslerrconn, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
320 curl_easy_setopt(sslerrconn, CURLOPT_TIMEOUT, 60);
321 curl_easy_setopt(sslerrconn, CURLOPT_FAILONERROR, TRUE);
322 curl_easy_setopt(sslerrconn, CURLOPT_USERAGENT, XSDAB_USERAGENT);
323 curl_easy_setopt(sslerrconn, CURLOPT_WRITEFUNCTION, WritebackFunc);
324 curl_easy_setopt(sslerrconn, CURLOPT_WRITEDATA, &PageData);
325 curl_easy_setopt(sslerrconn, CURLOPT_WRITEHEADER, &PageHeader);
326 curl_easy_setopt(sslerrconn, CURLOPT_PROGRESSDATA, this);
327 curl_easy_setopt(sslerrconn, CURLOPT_PROGRESSFUNCTION, ProgressFunc);
328 curl_easy_setopt(sslerrconn, CURLOPT_NOSIGNAL, 1);
329 curl_easy_setopt(sslerrconn, CURLOPT_SSL_VERIFYPEER, 0);
330 curl_easy_setopt(sslerrconn, CURLOPT_CERTINFO, 1);
332 sslerrconncode = (curl_easy_perform(sslerrconn));
334 SSLCertCol = BuildSSLCollection(sslerrconn);
335 SSLCertCol.SuccessCode = 1;
337 curl_easy_cleanup(conn);
338 curl_easy_cleanup(sslerrconn);
342 } else if (claconncode == CURLE_HTTP_RETURNED_ERROR){
344 fprintf(stderr, "curl_easy_perform() failed: %s\n",
345 curl_easy_strerror(claconncode));
347 curl_easy_getinfo(conn, CURLINFO_RESPONSE_CODE, &http_code);
348 fprintf(stderr, "Error code was: %d\n", http_code);
350 curl_easy_cleanup(conn);
356 fprintf(stderr, "curl_easy_perform() failed: %s\n",
357 curl_easy_strerror(claconncode));
359 curl_easy_getinfo(conn, CURLINFO_RESPONSE_CODE, &http_code);
360 fprintf(stderr, "Error code was: %d\n", http_code);
362 curl_easy_cleanup(conn);
372 wxString EmptyString;
374 curl_easy_setopt(conn, CURLOPT_URL, (const char*)ServerAddressNormal.mb_str(wxConvUTF8));
375 curl_easy_setopt(conn, CURLOPT_NOPROGRESS, 0);
376 curl_easy_setopt(conn, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
377 curl_easy_setopt(conn, CURLOPT_TIMEOUT, 60);
378 curl_easy_setopt(conn, CURLOPT_FAILONERROR, TRUE);
379 curl_easy_setopt(conn, CURLOPT_USERAGENT, XSDAB_USERAGENT);
380 curl_easy_setopt(conn, CURLOPT_USERPWD, (const char*)ServerAuth.mb_str(wxConvUTF8));
381 curl_easy_setopt(conn, CURLOPT_WRITEFUNCTION, WritebackFunc);
382 curl_easy_setopt(conn, CURLOPT_WRITEDATA, &PageData);
383 curl_easy_setopt(conn, CURLOPT_WRITEHEADER, &PageHeader);
384 curl_easy_setopt(conn, CURLOPT_PROGRESSDATA, this);
385 curl_easy_setopt(conn, CURLOPT_PROGRESSFUNCTION, ProgressFunc);
386 curl_easy_setopt(conn, CURLOPT_CUSTOMREQUEST, "REPORT");
387 curl_easy_setopt(conn, CURLOPT_NOSIGNAL, 1);
389 //UploadData.readptr = &CardDAVDataQuery;
390 //UploadData.sizeleft = CardDAVDataQuery.Len();
391 //curl_easy_setopt(conn, CURLOPT_UPLOAD, 1);
392 //curl_easy_setopt(conn, CURLOPT_READDATA, &UploadData);
393 //curl_easy_setopt(conn, CURLOPT_READFUNCTION, UploadReadFunc);
395 //curl_easy_setopt(conn, CURLOPT_WRITEFUNCTION, writefunc);
396 curl_easy_setopt(conn, CURLOPT_POSTFIELDS, query);
397 curl_easy_setopt(conn, CURLOPT_POSTFIELDSIZE, strlen(query));
402 conncode = (curl_easy_perform(conn));
404 if (conncode == CURLE_OK){
406 } else if (conncode == CURLE_HTTP_RETURNED_ERROR){
408 fprintf(stderr, "curl_easy_perform() failed: %s\n",
409 curl_easy_strerror(conncode));
415 fprintf(stderr, "curl_easy_perform() failed: %s\n",
416 curl_easy_strerror(conncode));
424 xmlDocPtr xmlCardDAVDoc;
426 xmlCardDAVDoc = xmlReadMemory(PageData.mb_str(wxConvUTF8), (int)PageData.Len(), "noname.xml", NULL, 0);
428 xmlNodePtr nodeLevel1;
429 xmlNodePtr nodeLevel2;
430 xmlNodePtr nodeLevel3;
431 xmlNodePtr nodeLevel4;
432 xmlNodePtr nodeLevel5;
433 xmlNodePtr nodeLevel6;
435 std::map<wxString,wxString> xmlDataMap;
437 wxString DataFilename;
440 std::string xmlStringSafe;
442 // Tranverse through the catacombs of the response to get our ETag for the file.
444 for (nodeLevel1 = xmlCardDAVDoc->children;
446 nodeLevel1 = nodeLevel1->next)
449 bool HREFFound = FALSE;
450 bool ETagFound = FALSE;
452 for (nodeLevel2 = nodeLevel1->children;
454 nodeLevel2 = nodeLevel2->next)
457 for (nodeLevel3 = nodeLevel2->children;
459 nodeLevel3 = nodeLevel3->next)
462 if (!xmlStrcmp(nodeLevel3->name, (const xmlChar *)"href") ||
463 !xmlStrcmp(nodeLevel3->name, (const xmlChar *)"d:href") ||
464 !xmlStrcmp(nodeLevel3->name, (const xmlChar *)"D:href")
469 for (nodeLevel4 = nodeLevel3->children;
471 nodeLevel4 = nodeLevel4->next)
474 if (!xmlStrcmp(nodeLevel4->name, (const xmlChar *)"text") ||
475 !xmlStrcmp(nodeLevel4->name, (const xmlChar *)"d:text") ||
476 !xmlStrcmp(nodeLevel4->name, (const xmlChar *)"D:text")
479 DataFilename = wxString::FromUTF8((const char*)nodeLevel4->content);
480 wxStringTokenizer wSTDFilename(DataFilename, wxT("/"));
482 while (wSTDFilename.HasMoreTokens()){
484 DataFilename = wSTDFilename.GetNextToken();
498 for (nodeLevel4 = nodeLevel3->children;
500 nodeLevel4 = nodeLevel4->next)
503 for (nodeLevel5 = nodeLevel4->children;
505 nodeLevel5 = nodeLevel5->next)
508 if (!xmlStrcmp(nodeLevel5->name, (const xmlChar *)"getetag") ||
509 !xmlStrcmp(nodeLevel5->name, (const xmlChar *)"d:getetag") ||
510 !xmlStrcmp(nodeLevel5->name, (const xmlChar *)"D:getetag")
513 for (nodeLevel6 = nodeLevel5->children;
515 nodeLevel6 = nodeLevel6->next)
518 // Strip the quotes from the ETag.
520 ETagData = wxString::FromUTF8((const char*)nodeLevel6->content);
521 if (ETagData.Mid(0, 1) == wxT("\"") && ETagData.Mid((ETagData.Len() - 1), 1) == wxT("\"")){
523 ETagData.Remove(0, 1);
524 ETagData.RemoveLast();
544 if (HREFFound == TRUE && ETagFound == TRUE){
546 // Add to the map data.
548 xmlDataMap.insert(std::make_pair(DataFilename, ETagData));
558 xmlFreeDoc(xmlCardDAVDoc);
560 // Get the first result.
562 for (std::map<wxString,wxString>::iterator iter = xmlDataMap.begin();
563 iter != xmlDataMap.end(); ++iter){
565 ETagResult = iter->second;
570 if (ETagResult.IsEmpty()){
580 void CardDAV::GetServerETagValue(){
582 std::thread ConnectThread(&CardDAV::GetServerETagValueThread, this);
583 ConnectThread.detach();