1 // carddav-processdata.cpp - CardDAV Object - Process Data 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 void CardDAV::ProcessDataThread(){
33 // Process the data (threaded).
40 AbortConnection = FALSE;
44 wxString ServerAddressURL;
46 wxString ServerAddressSSL;
47 wxString ServerAddressNormal;
49 conn = curl_easy_init();
51 struct CardDAVCURLPasser {
54 bool HeaderMode = TRUE;
56 } CardDAVHeader, CardDAVFooter;
58 CardDAVHeader.Data = this;
59 CardDAVHeader.HeaderMode = TRUE;
61 CardDAVFooter.Data = this;
62 CardDAVFooter.HeaderMode = FALSE;
68 wxString ETagOriginal;
71 ServerAddressURL = ServerAddress + wxT(":") + wxString::Format(wxT("%i"), ServerPort) + wxT("/") + ServerPrefix + ServerFilenameLocation;
72 ServerAddressSSL = wxT("https://") + ServerAddressURL;
73 ServerAddressNormal = wxT("http://") + ServerAddressURL;
75 ServerAuth = ServerUser + wxT(":") + ServerPass;
81 char *ServerAdrSSLChar = new char[(ServerAddressSSL.Length() - 1)];
82 //memset(ServerAdrSSLChar, 0, ServerAddressSSL.Length());
83 strncpy(ServerAdrSSLChar, (const char*)ServerAddressSSL.mb_str(wxConvUTF8), (ServerAddressSSL.Length() - 1));
85 char *ServerAdrNorChar = new char[(ServerAddressNormal.Length() - 1)];
86 //memset(ServerAdrNorChar, 0, ServerAddressSSL.Length());
87 strncpy(ServerAdrNorChar, (const char*)ServerAddressNormal.mb_str(wxConvUTF8), (ServerAddressNormal.Length() - 1));
89 char *ServerAuthChar = new char[(ServerAuth.Length() - 1)];
90 //memset(ServerAuthChar, 0, ServerAddressSSL.Length());
91 strncpy(ServerAuthChar, (const char*)ServerAuth.mb_str(wxConvUTF8), (ServerAuth.Length() - 1));
95 //std::string WriteDataString = std::string(ServerUploadData.mb_str());
97 std::map<int,int>::iterator ActIter;
98 struct UploadDataStruc UploadData;
101 ActIter = ActivityListPtr->find((int)ItemIndex);
103 // Update result flag.
107 // Setup the request mode if it is not empty.
109 if (!ServerMethod.IsEmpty()){
111 curl_easy_setopt(conn, CURLOPT_CUSTOMREQUEST, (const char*)ServerMethod.mb_str(wxConvUTF8));
117 wxString ServerCertFilename;
118 bool MatchingCert = FALSE;
120 curl_easy_setopt(conn, CURLOPT_URL, (const char*)ServerAddressSSL.mb_str(wxConvUTF8));
121 curl_easy_setopt(conn, CURLOPT_NOPROGRESS, 0);
122 curl_easy_setopt(conn, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
123 curl_easy_setopt(conn, CURLOPT_TIMEOUT, 60);
124 curl_easy_setopt(conn, CURLOPT_FAILONERROR, TRUE);
125 curl_easy_setopt(conn, CURLOPT_USERAGENT, XSDAB_USERAGENT);
126 curl_easy_setopt(conn, CURLOPT_USERPWD, (const char*)ServerAuth.mb_str(wxConvUTF8));
127 curl_easy_setopt(conn, CURLOPT_WRITEFUNCTION, WritebackFunc);
128 curl_easy_setopt(conn, CURLOPT_WRITEDATA, &PageData);
129 curl_easy_setopt(conn, CURLOPT_WRITEHEADER, &PageHeader);
130 curl_easy_setopt(conn, CURLOPT_PROGRESSDATA, this);
131 curl_easy_setopt(conn, CURLOPT_PROGRESSFUNCTION, ProgressFunc);
132 curl_easy_setopt(conn, CURLOPT_NOSIGNAL, 1);
134 if (UploadMode == TRUE){
136 UploadData.readptr = &ServerUploadData;
137 UploadData.sizeleft = ServerUploadData.Len();
138 curl_easy_setopt(conn, CURLOPT_UPLOAD, 1);
139 curl_easy_setopt(conn, CURLOPT_READDATA, &UploadData);
140 curl_easy_setopt(conn, CURLOPT_READFUNCTION, UploadReadFunc);
144 ServerCertFilename = GetAccountDir(ServerAccount, TRUE);
146 if (wxFile::Exists(ServerCertFilename) == TRUE){
148 curl_easy_setopt(conn, CURLOPT_SSL_VERIFYPEER, 1);
149 curl_easy_setopt(conn, CURLOPT_SSL_VERIFYHOST, 2);
150 curl_easy_setopt(conn, CURLOPT_CAINFO, (const char*)ServerCertFilename.mb_str(wxConvUTF8));
154 //UploadData.readptr = &CardDAVDataQuery;
155 //UploadData.sizeleft = CardDAVDataQuery.Len();
156 //curl_easy_setopt(conn, CURLOPT_UPLOAD, 1);
157 //curl_easy_setopt(conn, CURLOPT_READDATA, &UploadData);
158 //curl_easy_setopt(conn, CURLOPT_READFUNCTION, UploadReadFunc);
160 //curl_easy_setopt(conn, CURLOPT_WRITEFUNCTION, writefunc);
162 claconncode = (curl_easy_perform(conn));
164 // If CURLE_PEER_FAILED_VERIFICATION is returned, retry without
165 // the local certificate in use.
167 if (claconncode == CURLE_PEER_FAILED_VERIFICATION){
169 curl_easy_cleanup(conn);
170 conn = curl_easy_init();
172 curl_easy_setopt(conn, CURLOPT_URL, (const char*)ServerAddressSSL.mb_str(wxConvUTF8));
173 curl_easy_setopt(conn, CURLOPT_NOPROGRESS, 0);
174 curl_easy_setopt(conn, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
175 curl_easy_setopt(conn, CURLOPT_TIMEOUT, 60);
176 curl_easy_setopt(conn, CURLOPT_FAILONERROR, TRUE);
177 curl_easy_setopt(conn, CURLOPT_USERAGENT, XSDAB_USERAGENT);
178 curl_easy_setopt(conn, CURLOPT_USERPWD, (const char*)ServerAuth.mb_str(wxConvUTF8));
179 curl_easy_setopt(conn, CURLOPT_WRITEFUNCTION, WritebackFunc);
180 curl_easy_setopt(conn, CURLOPT_WRITEDATA, &PageData);
181 curl_easy_setopt(conn, CURLOPT_WRITEHEADER, &PageHeader);
182 curl_easy_setopt(conn, CURLOPT_PROGRESSDATA, this);
183 curl_easy_setopt(conn, CURLOPT_PROGRESSFUNCTION, ProgressFunc);
184 curl_easy_setopt(conn, CURLOPT_NOSIGNAL, 1);
186 if (UploadMode == TRUE){
188 UploadData.readptr = &ServerUploadData;
189 UploadData.sizeleft = ServerUploadData.Len();
190 curl_easy_setopt(conn, CURLOPT_UPLOAD, 1);
191 curl_easy_setopt(conn, CURLOPT_READDATA, &UploadData);
192 curl_easy_setopt(conn, CURLOPT_READFUNCTION, UploadReadFunc);
196 claconncode = (curl_easy_perform(conn));
198 // If claconncode is CURLE_OK then delete the certificate file as that
199 // is no longer needed.
201 if (claconncode == CURLE_OK){
203 // Delete the certificate file.
205 wxRemoveFile(ServerCertFilename);
211 // Check if it fails with a CURLE_SSL_CACERT then compare
212 // the certificates as PEM files.
214 if (claconncode == CURLE_SSL_CACERT && wxFile::Exists(ServerCertFilename) == TRUE){
216 //curl_easy_cleanup(conn);
217 //conn = curl_easy_init();
220 sslerrconn = curl_easy_init();
221 CURLcode sslerrconncode;
223 //claconncode = (curl_easy_perform(conn));
225 wxString ServerAddressOnly = wxT("https://") + ServerAddress + wxT(":") + wxString::Format(wxT("%i"), ServerPort) + wxT("/");
227 curl_easy_setopt(sslerrconn, CURLOPT_URL, (const char*)ServerAddressOnly.mb_str(wxConvUTF8));
228 curl_easy_setopt(sslerrconn, CURLOPT_NOPROGRESS, 0);
229 curl_easy_setopt(sslerrconn, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
230 curl_easy_setopt(sslerrconn, CURLOPT_TIMEOUT, 60);
231 curl_easy_setopt(sslerrconn, CURLOPT_FAILONERROR, TRUE);
232 curl_easy_setopt(sslerrconn, CURLOPT_USERAGENT, XSDAB_USERAGENT);
233 curl_easy_setopt(sslerrconn, CURLOPT_WRITEFUNCTION, WritebackFunc);
234 curl_easy_setopt(sslerrconn, CURLOPT_WRITEDATA, &PageData);
235 curl_easy_setopt(sslerrconn, CURLOPT_WRITEHEADER, &PageHeader);
236 curl_easy_setopt(sslerrconn, CURLOPT_PROGRESSDATA, this);
237 curl_easy_setopt(sslerrconn, CURLOPT_PROGRESSFUNCTION, ProgressFunc);
238 curl_easy_setopt(sslerrconn, CURLOPT_NOSIGNAL, 1);
239 curl_easy_setopt(sslerrconn, CURLOPT_SSL_VERIFYPEER, 0);
240 curl_easy_setopt(sslerrconn, CURLOPT_CERTINFO, 1);
242 wxString SSLLocalData;
243 wxString SSLServerData;
245 sslerrconncode = (curl_easy_perform(sslerrconn));
247 SSLCertCol = BuildSSLCollection(sslerrconn);
248 std::map<int, SSLCertData>::iterator SSLCDIter = SSLCertCol.SSLCollection.find(0);
249 std::multimap<wxString,wxString>::iterator SSLDataIter = SSLCDIter->second.CertData.find(wxT("Cert"));
251 wxFFile SSLLocalFile;
253 #if wxABI_VERSION < 20900
254 SSLLocalFile.Open(ServerCertFilename.c_str(), wxT("r"));
256 SSLLocalFile.Open(ServerCertFilename, wxT("r"));
259 // Load the recovery database for tasks not done.
261 if (SSLLocalFile.IsOpened() == TRUE){
263 // Check if we are using wxWidgets version 2.8 or less and
264 // execute the required command accordingly.
266 SSLLocalFile.ReadAll(&SSLLocalData, wxConvAuto());
271 SSLServerData = SSLDataIter->second;
273 if (SSLLocalData == SSLServerData){
275 // Server key matches with local key so retry with CURLOPT_SSL_VERIFYPEER
276 // and CURLOPT_SSL_VERIFYHOST off.
278 curl_easy_cleanup(conn);
279 conn = curl_easy_init();
284 curl_easy_setopt(conn, CURLOPT_URL, (const char*)ServerAddressSSL.mb_str(wxConvUTF8));
285 curl_easy_setopt(conn, CURLOPT_NOPROGRESS, 0);
286 curl_easy_setopt(conn, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
287 curl_easy_setopt(conn, CURLOPT_TIMEOUT, 60);
288 curl_easy_setopt(conn, CURLOPT_FAILONERROR, TRUE);
289 curl_easy_setopt(conn, CURLOPT_USERAGENT, XSDAB_USERAGENT);
290 curl_easy_setopt(conn, CURLOPT_USERPWD, (const char*)ServerAuth.mb_str(wxConvUTF8));
291 curl_easy_setopt(conn, CURLOPT_WRITEFUNCTION, WritebackFunc);
292 curl_easy_setopt(conn, CURLOPT_WRITEDATA, &PageData);
293 curl_easy_setopt(conn, CURLOPT_WRITEHEADER, &PageHeader);
294 curl_easy_setopt(conn, CURLOPT_PROGRESSDATA, this);
295 curl_easy_setopt(conn, CURLOPT_PROGRESSFUNCTION, ProgressFunc);
296 curl_easy_setopt(conn, CURLOPT_NOSIGNAL, 1);
298 if (UploadMode == TRUE){
300 UploadData.readptr = &ServerUploadData;
301 UploadData.sizeleft = ServerUploadData.Len();
302 curl_easy_setopt(conn, CURLOPT_UPLOAD, 1);
303 curl_easy_setopt(conn, CURLOPT_READDATA, &UploadData);
304 curl_easy_setopt(conn, CURLOPT_READFUNCTION, UploadReadFunc);
308 curl_easy_setopt(conn, CURLOPT_SSL_VERIFYHOST, 0);
309 curl_easy_setopt(conn, CURLOPT_SSL_VERIFYPEER, 0);
311 claconncode = (curl_easy_perform(conn));
317 if (MatchingCert == FALSE){
319 claconncode = CURLE_SSL_CACERT;
324 curl_easy_cleanup(sslerrconn);
328 // Sort out SSL error.
330 // When SSL cert error occurs, connect again and fetch certificates.
331 // Display a message to the user explaining that an invalid
332 // certificate has been given and let the user decide what
335 if (claconncode == CURLE_OK){
337 } else if (claconncode == CURLE_SSL_CACERT || claconncode == CURLE_PEER_FAILED_VERIFICATION){
340 sslerrconn = curl_easy_init();
341 CURLcode sslerrconncode;
343 wxString ServerAddressOnly = wxT("https://") + ServerAddress + wxT(":") + wxString::Format(wxT("%i"), ServerPort) + wxT("/");
345 // Replace conn with sslerrconn!
347 curl_easy_setopt(sslerrconn, CURLOPT_URL, (const char*)ServerAddressOnly.mb_str(wxConvUTF8));
348 curl_easy_setopt(sslerrconn, CURLOPT_NOPROGRESS, 0);
349 curl_easy_setopt(sslerrconn, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
350 curl_easy_setopt(sslerrconn, CURLOPT_TIMEOUT, 60);
351 curl_easy_setopt(sslerrconn, CURLOPT_FAILONERROR, TRUE);
352 curl_easy_setopt(sslerrconn, CURLOPT_USERAGENT, XSDAB_USERAGENT);
353 curl_easy_setopt(sslerrconn, CURLOPT_WRITEFUNCTION, WritebackFunc);
354 curl_easy_setopt(sslerrconn, CURLOPT_WRITEDATA, &PageData);
355 curl_easy_setopt(sslerrconn, CURLOPT_WRITEHEADER, &PageHeader);
356 curl_easy_setopt(sslerrconn, CURLOPT_PROGRESSDATA, this);
357 curl_easy_setopt(sslerrconn, CURLOPT_PROGRESSFUNCTION, ProgressFunc);
358 curl_easy_setopt(sslerrconn, CURLOPT_NOSIGNAL, 1);
359 curl_easy_setopt(sslerrconn, CURLOPT_SSL_VERIFYPEER, 0);
360 curl_easy_setopt(sslerrconn, CURLOPT_CERTINFO, 1);
362 sslerrconncode = (curl_easy_perform(sslerrconn));
364 SSLCertCol = BuildSSLCollection(sslerrconn);
365 SSLCertCol.SuccessCode = 1;
369 } else if (claconncode == CURLE_HTTP_RETURNED_ERROR){
371 fprintf(stderr, "curl_easy_perform() failed: %s\n",
372 curl_easy_strerror(claconncode));
374 curl_easy_getinfo(conn, CURLINFO_RESPONSE_CODE, &http_code);
375 fprintf(stderr, "Error code was: %d\n", http_code);
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);
395 curl_easy_setopt(conn, CURLOPT_URL, (const char*)ServerAddressNormal.mb_str(wxConvUTF8));
396 curl_easy_setopt(conn, CURLOPT_NOPROGRESS, 0);
397 curl_easy_setopt(conn, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
398 curl_easy_setopt(conn, CURLOPT_TIMEOUT, 60);
399 curl_easy_setopt(conn, CURLOPT_FAILONERROR, TRUE);
400 curl_easy_setopt(conn, CURLOPT_USERAGENT, XSDAB_USERAGENT);
401 curl_easy_setopt(conn, CURLOPT_USERPWD, (const char*)ServerAuth.mb_str(wxConvUTF8));
402 curl_easy_setopt(conn, CURLOPT_WRITEFUNCTION, WritebackFunc);
403 curl_easy_setopt(conn, CURLOPT_WRITEDATA, &PageData);
404 curl_easy_setopt(conn, CURLOPT_WRITEHEADER, &PageHeader);
405 curl_easy_setopt(conn, CURLOPT_PROGRESSDATA, this);
406 curl_easy_setopt(conn, CURLOPT_PROGRESSFUNCTION, ProgressFunc);
407 curl_easy_setopt(conn, CURLOPT_NOSIGNAL, 1);
409 if (UploadMode == TRUE){
411 UploadData.readptr = &ServerUploadData;
412 UploadData.sizeleft = ServerUploadData.Len();
413 curl_easy_setopt(conn, CURLOPT_UPLOAD, 1);
414 curl_easy_setopt(conn, CURLOPT_READDATA, &UploadData);
415 curl_easy_setopt(conn, CURLOPT_READFUNCTION, UploadReadFunc);
419 conncode = (curl_easy_perform(conn));
421 if (conncode == CURLE_OK){
423 // Process the server header response and look for
424 // 'addressbook' within the DAV header.
426 wxStringTokenizer wxSHeaderLines(PageHeader, wxT("\r\n"));
427 wxString wxSHeaderLine;
428 std::map<int, wxString> DAVHeaderLines;
430 while (wxSHeaderLines.HasMoreTokens()){
432 wxSHeaderLine = wxSHeaderLines.GetNextToken();
434 if (wxSHeaderLine.Mid(0, 5) == wxT("ETag:")){
436 ETagData = wxSHeaderLine.Mid(5);
438 ETagData.Trim(FALSE);
442 if (ETagData.Mid(0, 1) == wxT("\"") && ETagData.Mid((ETagData.Len() - 1), 1) == wxT("\"")){
444 ETagData.Remove(0, 1);
445 ETagData.RemoveLast();
451 if (wxSHeaderLine.Mid(0, 4) == wxT("DAV:")){
453 // Look for address book in the line.
455 if (wxSHeaderLine.Find(wxT("addressbook")) != wxNOT_FOUND){
457 HasCalDAVSupport = TRUE;
465 // Get the ETag from the header.
467 if (UploadMode == TRUE){
469 wxString PageHeaderLine;
471 wxStringTokenizer PageHeaderSplit(PageHeader, wxT("\r\n"));
473 if (PageHeaderSplit.HasMoreTokens()){
475 PageHeaderLine = PageHeaderSplit.GetNextToken();
484 } else if (conncode == CURLE_HTTP_RETURNED_ERROR){
486 curl_easy_getinfo(conn, CURLINFO_RESPONSE_CODE, &HTTPErrorCode);
488 fprintf(stderr, "curl_easy_perform() failed: %s\n",
489 curl_easy_strerror(conncode));
491 fprintf(stderr, "curl_easy_perform() HTTP code was: %i\n",
499 fprintf(stderr, "curl_easy_perform() failed: %s\n",
500 curl_easy_strerror(conncode));
511 //ActIter->second = 1;
512 *ServerResult = TRUE;
517 void CardDAV::ProcessData(){
521 std::thread ConnectThread(&CardDAV::ProcessDataThread, this);
522 ConnectThread.detach();