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