Home | News | Projects | Releases
Bugs | RFE | Repositories | Help
Altered CardDAV object to accommodate for SSL support for OS X (and other OSes in...
[xestiaab/.git] / source / carddav / carddav-processdata.cpp
1 // carddav-processdata.cpp - CardDAV Object - Process Data 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::ProcessDataThread(){
33         // Process the data (threaded).
34         
35         PageData.Clear();
36         PageHeader.Clear();
38         SSLStatus = TRUE;
39         AuthPassed = TRUE;
40         AbortConnection = FALSE;
42         CURL *conn;
43         CURLcode conncode;
44         wxString ServerAddressURL;
45         wxString ServerAuth;
46         wxString ServerAddressSSL;
47         wxString ServerAddressNormal;
48         
49         conn = curl_easy_init();
50         
51         SetConnectionObject(conn);
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         wxString ETag;
70         wxString ETagOriginal;
71         wxString ETagServer;
72                 
73         ServerAddressURL = ServerAddress + wxT(":") + wxString::Format(wxT("%i"), ServerPort) + ServerPrefix + ServerFilenameLocation;
74         ServerAddressSSL = wxT("https://") + ServerAddressURL;
75         ServerAddressNormal = wxT("http://") + ServerAddressURL;
76         
77         ServerAuth = ServerUser + wxT(":") + ServerPass;
79         std::map<int,int>::iterator ActIter;
80         struct UploadDataStruc UploadData;
81         
82         
83         ActIter = ActivityListPtr->find((int)ItemIndex);
84         
85         // Update result flag.
87         ActIter->second = 1;
88         
89         // Setup the request mode if it is not empty.
90         
91         if (!ServerMethod.IsEmpty()){
92         
93                 curl_easy_setopt(conn, CURLOPT_CUSTOMREQUEST, (const char*)ServerMethod.mb_str(wxConvUTF8));
95         }
96         
97         // Try SSL first.
99         if (ServerSSL){
101                 wxString ServerCertFilename;
102                 bool MatchingCert = FALSE;
104                 curl_easy_setopt(conn, CURLOPT_URL, (const char*)ServerAddressSSL.mb_str(wxConvUTF8));
105                 curl_easy_setopt(conn, CURLOPT_NOPROGRESS, 0);
106                 curl_easy_setopt(conn, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
107                 curl_easy_setopt(conn, CURLOPT_TIMEOUT, 60);
108                 curl_easy_setopt(conn, CURLOPT_FAILONERROR, TRUE);
109                 curl_easy_setopt(conn, CURLOPT_USERAGENT, XSDAB_USERAGENT);
110                 curl_easy_setopt(conn, CURLOPT_USERPWD, (const char*)ServerAuth.mb_str(wxConvUTF8));
111                 curl_easy_setopt(conn, CURLOPT_WRITEFUNCTION, WritebackFunc);
112                 curl_easy_setopt(conn, CURLOPT_WRITEDATA, &PageData);
113                 curl_easy_setopt(conn, CURLOPT_WRITEHEADER, &PageHeader);
114                 curl_easy_setopt(conn, CURLOPT_PROGRESSDATA, this);
115                 curl_easy_setopt(conn, CURLOPT_PROGRESSFUNCTION, ProgressFunc);
116                 curl_easy_setopt(conn, CURLOPT_NOSIGNAL, 1);
117                 
118                 if (UploadMode == TRUE){
119                         
120                         UploadData.readptr = &ServerUploadData;
121                         UploadData.sizeleft = ServerUploadData.Len();
122                         curl_easy_setopt(conn, CURLOPT_UPLOAD, 1);
123                         curl_easy_setopt(conn, CURLOPT_READDATA, &UploadData);
124                         curl_easy_setopt(conn, CURLOPT_READFUNCTION, UploadReadFunc);
125                 
126                 }
128 #if defined(__APPLE__)
129                 
130 #else
131                 
132                 ServerCertFilename = GetAccountDir(ServerAccount, TRUE);
134                 if (wxFile::Exists(ServerCertFilename) == TRUE){
135                 
136                         curl_easy_setopt(conn, CURLOPT_SSL_VERIFYPEER, 1);
137                         curl_easy_setopt(conn, CURLOPT_SSL_VERIFYHOST, 2);
138                         curl_easy_setopt(conn, CURLOPT_CAINFO, (const char*)ServerCertFilename.mb_str(wxConvUTF8));
139                 
140                 }
141         
142 #endif
143                 
144                 claconncode = (curl_easy_perform(conn));
146                 // If CURLE_PEER_FAILED_VERIFICATION is returned, retry without
147                 // the local certificate in use.
149                 if (claconncode == CURLE_PEER_FAILED_VERIFICATION){
150                         
151                         curl_easy_cleanup(conn);
152                         conn = curl_easy_init();
153                         
154                         curl_easy_setopt(conn, CURLOPT_URL, (const char*)ServerAddressSSL.mb_str(wxConvUTF8));
155                         curl_easy_setopt(conn, CURLOPT_NOPROGRESS, 0);
156                         curl_easy_setopt(conn, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
157                         curl_easy_setopt(conn, CURLOPT_TIMEOUT, 60);
158                         curl_easy_setopt(conn, CURLOPT_FAILONERROR, TRUE);
159                         curl_easy_setopt(conn, CURLOPT_USERAGENT, XSDAB_USERAGENT);
160                         curl_easy_setopt(conn, CURLOPT_USERPWD, (const char*)ServerAuth.mb_str(wxConvUTF8));
161                         curl_easy_setopt(conn, CURLOPT_WRITEFUNCTION, WritebackFunc);
162                         curl_easy_setopt(conn, CURLOPT_WRITEDATA, &PageData);
163                         curl_easy_setopt(conn, CURLOPT_WRITEHEADER, &PageHeader);
164                         curl_easy_setopt(conn, CURLOPT_PROGRESSDATA, this);
165                         curl_easy_setopt(conn, CURLOPT_PROGRESSFUNCTION, ProgressFunc);
166                         curl_easy_setopt(conn, CURLOPT_NOSIGNAL, 1);
168                         if (UploadMode == TRUE){
170                                 UploadData.readptr = &ServerUploadData;
171                                 UploadData.sizeleft = ServerUploadData.Len();
172                                 curl_easy_setopt(conn, CURLOPT_UPLOAD, 1);
173                                 curl_easy_setopt(conn, CURLOPT_READDATA, &UploadData);
174                                 curl_easy_setopt(conn, CURLOPT_READFUNCTION, UploadReadFunc);
175                 
176                         }
177                         
178                         claconncode = (curl_easy_perform(conn));
179                         
180                         // If claconncode is CURLE_OK then delete the certificate file as that
181                         // is no longer needed.
182                         
183                         if (claconncode == CURLE_OK){
184                         
185                                 // Delete the certificate file.
186                                 
187                                 wxRemoveFile(ServerCertFilename);
188                         
189                         }
190                 
191                 }
193                 // Check if it fails with a CURLE_SSL_CACERT then compare
194                 // the certificates as PEM files.
195                 
196 #if defined(__APPLE__)
197                 
198 #else
199                 
200                 if (claconncode == CURLE_SSL_CACERT && wxFile::Exists(ServerCertFilename) == TRUE){
202                         CURL *sslerrconn;
203                         sslerrconn = curl_easy_init();
204                         CURLcode sslerrconncode;
206                         wxString ServerAddressOnly = wxT("https://") + ServerAddress + wxT(":") + wxString::Format(wxT("%i"), ServerPort) + wxT("/");
208                         curl_easy_setopt(sslerrconn, CURLOPT_URL, (const char*)ServerAddressOnly.mb_str(wxConvUTF8));
209                         curl_easy_setopt(sslerrconn, CURLOPT_NOPROGRESS, 0);
210                         curl_easy_setopt(sslerrconn, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
211                         curl_easy_setopt(sslerrconn, CURLOPT_TIMEOUT, 60);
212                         curl_easy_setopt(sslerrconn, CURLOPT_FAILONERROR, TRUE);
213                         curl_easy_setopt(sslerrconn, CURLOPT_USERAGENT, XSDAB_USERAGENT);
214                         curl_easy_setopt(sslerrconn, CURLOPT_WRITEFUNCTION, WritebackFunc);
215                         curl_easy_setopt(sslerrconn, CURLOPT_WRITEDATA, &PageData);
216                         curl_easy_setopt(sslerrconn, CURLOPT_WRITEHEADER, &PageHeader);
217                         curl_easy_setopt(sslerrconn, CURLOPT_PROGRESSDATA, this);
218                         curl_easy_setopt(sslerrconn, CURLOPT_PROGRESSFUNCTION, ProgressFunc);
219                         curl_easy_setopt(sslerrconn, CURLOPT_NOSIGNAL, 1);
220                         curl_easy_setopt(sslerrconn, CURLOPT_SSL_VERIFYPEER, 0);
221                         curl_easy_setopt(sslerrconn, CURLOPT_CERTINFO, 1);
222                 
223                         wxString SSLLocalData;
224                         wxString SSLServerData;
225                         
226                         sslerrconncode = (curl_easy_perform(sslerrconn));
227                         
228                         SSLCertCol = BuildSSLCollection(sslerrconn);
229                         std::map<int, SSLCertData>::iterator SSLCDIter = SSLCertCol.SSLCollection.find(0);
230                         std::multimap<wxString,wxString>::iterator SSLDataIter = SSLCDIter->second.CertData.find(wxT("Cert"));
231                         
232                         wxFFile SSLLocalFile;
233                         
234 #if wxABI_VERSION < 20900
235                         SSLLocalFile.Open(ServerCertFilename.c_str(), wxT("r"));
236 #else
237                         SSLLocalFile.Open(ServerCertFilename, wxT("r"));
238 #endif  
239         
240                         // Load the recovery database for tasks not done.
241         
242                         if (SSLLocalFile.IsOpened() == TRUE){
244                         // Check if we are using wxWidgets version 2.8 or less and
245                         // execute the required command accordingly.
246         
247                                 SSLLocalFile.ReadAll(&SSLLocalData, wxConvAuto());
248                 
249         
250                         }
251                         
252                         SSLServerData = SSLDataIter->second;
253                         
254                         if (SSLLocalData == SSLServerData){
255                         
256                                 // Server key matches with local key so retry with CURLOPT_SSL_VERIFYPEER
257                                 // and CURLOPT_SSL_VERIFYHOST off.
258                         
259                                 curl_easy_cleanup(conn);
260                                 conn = curl_easy_init();
261                                 
262                                 PageData.clear();
263                                 PageHeader.clear();
264                         
265                                 curl_easy_setopt(conn, CURLOPT_URL, (const char*)ServerAddressSSL.mb_str(wxConvUTF8));
266                                 curl_easy_setopt(conn, CURLOPT_NOPROGRESS, 0);
267                                 curl_easy_setopt(conn, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
268                                 curl_easy_setopt(conn, CURLOPT_TIMEOUT, 60);
269                                 curl_easy_setopt(conn, CURLOPT_FAILONERROR, TRUE);
270                                 curl_easy_setopt(conn, CURLOPT_USERAGENT, XSDAB_USERAGENT);
271                                 curl_easy_setopt(conn, CURLOPT_USERPWD, (const char*)ServerAuth.mb_str(wxConvUTF8));
272                                 curl_easy_setopt(conn, CURLOPT_WRITEFUNCTION, WritebackFunc);
273                                 curl_easy_setopt(conn, CURLOPT_WRITEDATA, &PageData);
274                                 curl_easy_setopt(conn, CURLOPT_WRITEHEADER, &PageHeader);
275                                 curl_easy_setopt(conn, CURLOPT_PROGRESSDATA, this);
276                                 curl_easy_setopt(conn, CURLOPT_PROGRESSFUNCTION, ProgressFunc);
277                                 curl_easy_setopt(conn, CURLOPT_NOSIGNAL, 1);
279                                 if (UploadMode == TRUE){
281                                         UploadData.readptr = &ServerUploadData;
282                                         UploadData.sizeleft = ServerUploadData.Len();
283                                         curl_easy_setopt(conn, CURLOPT_UPLOAD, 1);
284                                         curl_easy_setopt(conn, CURLOPT_READDATA, &UploadData);
285                                         curl_easy_setopt(conn, CURLOPT_READFUNCTION, UploadReadFunc);
286                 
287                                 }
288                                 
289                                 curl_easy_setopt(conn, CURLOPT_SSL_VERIFYHOST, 0);
290                                 curl_easy_setopt(conn, CURLOPT_SSL_VERIFYPEER, 0);
291                         
292                                 claconncode = (curl_easy_perform(conn));
293                                 
294                                 MatchingCert = TRUE;
295                         
296                         }
297                         
298                         if (MatchingCert == FALSE){
299                 
300                                 claconncode = CURLE_SSL_CACERT;
301                                 return;
302                 
303                         }
304                         
305                         curl_easy_cleanup(sslerrconn);
306                 
307                 }
308                 
309 #endif
311                 // Sort out SSL error.
312                 
313                 // When SSL cert error occurs, connect again and fetch certificates.
314                 // Display a message to the user explaining that an invalid
315                 // certificate has been given and let the user decide what
316                 // to do next.
318                 if (claconncode == CURLE_OK){
320                 } else if (claconncode == CURLE_SSL_CACERT || claconncode == CURLE_PEER_FAILED_VERIFICATION){
321                 
322                         CURL *sslerrconn;
323                         sslerrconn = curl_easy_init();
324                         CURLcode sslerrconncode;
325                 
326                         wxString ServerAddressOnly = wxT("https://") + ServerAddress + wxT(":") + wxString::Format(wxT("%i"), ServerPort) + wxT("/");
327                 
328                         // Replace conn with sslerrconn!
329                 
330                         curl_easy_setopt(sslerrconn, CURLOPT_URL, (const char*)ServerAddressOnly.mb_str(wxConvUTF8));
331                         curl_easy_setopt(sslerrconn, CURLOPT_NOPROGRESS, 0);
332                         curl_easy_setopt(sslerrconn, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
333                         curl_easy_setopt(sslerrconn, CURLOPT_TIMEOUT, 60);
334                         curl_easy_setopt(sslerrconn, CURLOPT_FAILONERROR, TRUE);
335                         curl_easy_setopt(sslerrconn, CURLOPT_USERAGENT, XSDAB_USERAGENT);
336                         curl_easy_setopt(sslerrconn, CURLOPT_WRITEFUNCTION, WritebackFunc);
337                         curl_easy_setopt(sslerrconn, CURLOPT_WRITEDATA, &PageData);
338                         curl_easy_setopt(sslerrconn, CURLOPT_WRITEHEADER, &PageHeader);
339                         curl_easy_setopt(sslerrconn, CURLOPT_PROGRESSDATA, this);
340                         curl_easy_setopt(sslerrconn, CURLOPT_PROGRESSFUNCTION, ProgressFunc);
341                         curl_easy_setopt(sslerrconn, CURLOPT_NOSIGNAL, 1);
342                         curl_easy_setopt(sslerrconn, CURLOPT_SSL_VERIFYPEER, 0);
343                         curl_easy_setopt(sslerrconn, CURLOPT_CERTINFO, 1);
344                         
345                         SetConnectionObject(sslerrconn);
346                         
347                         sslerrconncode = (curl_easy_perform(sslerrconn));
349 #if defined(__APPLE__)
350                         
351 #else
352                         
353                         SSLCertCol = BuildSSLCollection(sslerrconn);
354                         SSLCertCol.SuccessCode = 1;
356 #endif
357                         
358                         return;
359                 
360                 } else if (claconncode == CURLE_HTTP_RETURNED_ERROR){
361                 
362                         fprintf(stderr, "ProcessDataThrad(): curl_easy_perform() failed: %s\n",
363                                         curl_easy_strerror(claconncode));
364                         int http_code = 0;
365                         curl_easy_getinfo(conn, CURLINFO_RESPONSE_CODE, &http_code);
366                         fprintf(stderr, "Error code was: %d\n", http_code);
367                                         
368                         return;
369                 
370                 } else {
372                         fprintf(stderr, "curl_easy_perform() failed: %s\n",
373                                         curl_easy_strerror(claconncode));
374                         int http_code = 0;
375                         curl_easy_getinfo(conn, CURLINFO_RESPONSE_CODE, &http_code);
376                         fprintf(stderr, "Error code was: %d\n", http_code);
378                         return;
380                 }
382         } else {
383         
384         // No SSL.
385                 
386                 curl_easy_setopt(conn, CURLOPT_URL, (const char*)ServerAddressNormal.mb_str(wxConvUTF8));
387                 curl_easy_setopt(conn, CURLOPT_NOPROGRESS, 0);
388                 curl_easy_setopt(conn, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
389                 curl_easy_setopt(conn, CURLOPT_TIMEOUT, 60);
390                 curl_easy_setopt(conn, CURLOPT_FAILONERROR, TRUE);
391                 curl_easy_setopt(conn, CURLOPT_USERAGENT, XSDAB_USERAGENT);
392                 curl_easy_setopt(conn, CURLOPT_USERPWD, (const char*)ServerAuth.mb_str(wxConvUTF8));
393                 curl_easy_setopt(conn, CURLOPT_WRITEFUNCTION, WritebackFunc);
394                 curl_easy_setopt(conn, CURLOPT_WRITEDATA, &PageData);
395                 curl_easy_setopt(conn, CURLOPT_WRITEHEADER, &PageHeader);
396                 curl_easy_setopt(conn, CURLOPT_PROGRESSDATA, this);
397                 curl_easy_setopt(conn, CURLOPT_PROGRESSFUNCTION, ProgressFunc);
398                 curl_easy_setopt(conn, CURLOPT_NOSIGNAL, 1);
399                 
400                 if (UploadMode == TRUE){
401                         
402                         UploadData.readptr = &ServerUploadData;
403                         UploadData.sizeleft = ServerUploadData.Len();
404                         curl_easy_setopt(conn, CURLOPT_UPLOAD, 1);
405                         curl_easy_setopt(conn, CURLOPT_READDATA, &UploadData);
406                         curl_easy_setopt(conn, CURLOPT_READFUNCTION, UploadReadFunc);
407                 
408                 }
409                 
410                 conncode = (curl_easy_perform(conn));
412                 if (conncode == CURLE_OK){
414                         // Process the server header response and look for
415                         // 'addressbook' within the DAV header.
416                         
417                         wxStringTokenizer wxSHeaderLines(PageHeader, wxT("\r\n"));
418                         wxString wxSHeaderLine;
419                         std::map<int, wxString> DAVHeaderLines;
420                         
421                         while (wxSHeaderLines.HasMoreTokens()){
422                         
423                                 wxSHeaderLine = wxSHeaderLines.GetNextToken();
424                                 
425                                 if (wxSHeaderLine.Mid(0, 5) == wxT("ETag:")){
426                                 
427                                         ETagData = wxSHeaderLine.Mid(5);
428                                         ETagData.Trim();
429                                         ETagData.Trim(FALSE);
430                                         
431                                         // Check for commas.
432                                         
433                                         if (ETagData.Mid(0, 1) == wxT("\"") && ETagData.Mid((ETagData.Len() - 1), 1) == wxT("\"")){
434                                                         
435                                                 ETagData.Remove(0, 1);
436                                                 ETagData.RemoveLast();
437                                                         
438                                         }
439                                 
440                                 }
441                                 
442                                 if (wxSHeaderLine.Mid(0, 4) == wxT("DAV:")){
443                                 
444                                         // Look for address book in the line.
445                                         
446                                         if (wxSHeaderLine.Find(wxT("addressbook")) != wxNOT_FOUND){
447                                         
448                                                 HasCalDAVSupport = TRUE;
449                                         
450                                         }
451                                 
452                                 }
453                         
454                         }
455                         
456                         // Get the ETag from the header.
457                         
458                         if (UploadMode == TRUE){
459                 
460                                 wxString PageHeaderLine;
461                 
462                                 wxStringTokenizer PageHeaderSplit(PageHeader, wxT("\r\n"));
463                                 
464                                 if (PageHeaderSplit.HasMoreTokens()){
465                                 
466                                         PageHeaderLine = PageHeaderSplit.GetNextToken();
467                                 
468                                 }
469                 
470                         }
472                         ActIter->second = 4;
473                         return;
475                 } else if (conncode == CURLE_HTTP_RETURNED_ERROR){
477                         curl_easy_getinfo(conn, CURLINFO_RESPONSE_CODE, &HTTPErrorCode);
478                 
479                         fprintf(stderr, "curl_easy_perform() failed: %s\n",
480                                         curl_easy_strerror(conncode));
482                         fprintf(stderr, "curl_easy_perform() HTTP code was: %i\n",
483                                         GetHTTPCode());
485                         ActIter->second = 2;
486                         return;
487                 
488                 } else {
490                         fprintf(stderr, "curl_easy_perform() failed: %s\n",
491                                         curl_easy_strerror(conncode));
492                                 
493                         ActIter->second = 2;
494                         return;
496                 }
497                 
498         }
499         
500         // Catch all.
501         
502         *ServerResult = TRUE;
503         return;
507 void CardDAV::ProcessData(){
509         // Process the data.
510         
511         std::thread ConnectThread(&CardDAV::ProcessDataThread, this);
512         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