1 // carddav-servercontact.cpp - CardDAV Object - Server Contact 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::GetServerContactData()
34 // Get the server contact data.
41 AbortConnection = FALSE;
43 wxString ServerCertFilename;
44 bool MatchingCert = FALSE;
48 wxString ServerAddressURL;
50 wxString ServerAddressSSL;
51 wxString ServerAddressNormal;
53 conn = curl_easy_init();
55 #if defined(__APPLE__)
57 SetConnectionObject(conn);
61 struct CardDAVCURLPasser {
64 bool HeaderMode = TRUE;
66 } CardDAVHeader, CardDAVFooter;
68 CardDAVHeader.Data = this;
69 CardDAVHeader.HeaderMode = TRUE;
71 CardDAVFooter.Data = this;
72 CardDAVFooter.HeaderMode = FALSE;
77 ServerAddressURL = ServerAddress + wxT(":") + wxString::Format(wxT("%i"), ServerPort) + wxT("/") + ServerPrefix + ServerFilenameLocation;
78 ServerAddressSSL = wxT("https://") + ServerAddressURL;
79 ServerAddressNormal = wxT("http://") + ServerAddressURL;
81 ServerAuth = ServerUser + wxT(":") + ServerPass;
83 std::map<int,int>::iterator ActIter;
84 struct UploadDataStruc UploadData;
86 ActIter = ActivityListPtr->find((int)ItemIndex);
92 curl_easy_setopt(conn, CURLOPT_URL, (const char*)ServerAddressSSL.mb_str(wxConvUTF8));
93 curl_easy_setopt(conn, CURLOPT_NOPROGRESS, 1L);
94 curl_easy_setopt(conn, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
95 curl_easy_setopt(conn, CURLOPT_TIMEOUT, 60);
96 curl_easy_setopt(conn, CURLOPT_FAILONERROR, TRUE);
97 curl_easy_setopt(conn, CURLOPT_USERAGENT, XSDAB_USERAGENT);
98 curl_easy_setopt(conn, CURLOPT_USERPWD, (const char*)ServerAuth.mb_str(wxConvUTF8));
99 curl_easy_setopt(conn, CURLOPT_WRITEFUNCTION, WritebackFunc);
100 curl_easy_setopt(conn, CURLOPT_WRITEDATA, &PageData);
101 curl_easy_setopt(conn, CURLOPT_WRITEHEADER, &PageHeader);
102 curl_easy_setopt(conn, CURLOPT_NOSIGNAL, 1);
104 #if defined(__APPLE__)
108 ServerCertFilename = GetAccountDir(ServerAccount, TRUE);
110 if (wxFile::Exists(ServerCertFilename) == TRUE){
112 curl_easy_setopt(conn, CURLOPT_SSL_VERIFYPEER, 1);
113 curl_easy_setopt(conn, CURLOPT_SSL_VERIFYHOST, 2);
114 curl_easy_setopt(conn, CURLOPT_CAINFO, (const char*)ServerCertFilename.mb_str(wxConvUTF8));
120 claconncode = (curl_easy_perform(conn));
122 // If CURLE_PEER_FAILED_VERIFICATION is returned, retry without
123 // the local certificate in use.
125 if (claconncode == CURLE_PEER_FAILED_VERIFICATION){
127 curl_easy_cleanup(conn);
128 conn = curl_easy_init();
130 curl_easy_setopt(conn, CURLOPT_URL, (const char*)ServerAddressSSL.mb_str(wxConvUTF8));
131 curl_easy_setopt(conn, CURLOPT_NOPROGRESS, 1L);
132 curl_easy_setopt(conn, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
133 curl_easy_setopt(conn, CURLOPT_TIMEOUT, 60);
134 curl_easy_setopt(conn, CURLOPT_FAILONERROR, TRUE);
135 curl_easy_setopt(conn, CURLOPT_USERAGENT, XSDAB_USERAGENT);
136 curl_easy_setopt(conn, CURLOPT_USERPWD, (const char*)ServerAuth.mb_str(wxConvUTF8));
137 curl_easy_setopt(conn, CURLOPT_WRITEFUNCTION, WritebackFunc);
138 curl_easy_setopt(conn, CURLOPT_WRITEDATA, &PageData);
139 curl_easy_setopt(conn, CURLOPT_WRITEHEADER, &PageHeader);
140 curl_easy_setopt(conn, CURLOPT_NOSIGNAL, 1);
142 claconncode = (curl_easy_perform(conn));
144 // If claconncode is CURLE_OK then delete the certificate file as that
145 // is no longer needed.
147 if (claconncode == CURLE_OK){
149 // Delete the certificate file.
151 wxRemoveFile(ServerCertFilename);
157 // Check if it fails with a CURLE_SSL_CACERT then compare
158 // the certificates as PEM files.
160 #if defined(__APPLE__)
164 if (claconncode == CURLE_SSL_CACERT && wxFile::Exists(ServerCertFilename) == TRUE){
167 sslerrconn = curl_easy_init();
168 CURLcode sslerrconncode;
170 wxString ServerAddressOnly = wxT("https://") + ServerAddress + wxT(":") + wxString::Format(wxT("%i"), ServerPort) + wxT("/");
172 curl_easy_setopt(sslerrconn, CURLOPT_URL, (const char*)ServerAddressOnly.mb_str(wxConvUTF8));
173 curl_easy_setopt(sslerrconn, CURLOPT_NOPROGRESS, 1L);
174 curl_easy_setopt(sslerrconn, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
175 curl_easy_setopt(sslerrconn, CURLOPT_TIMEOUT, 60);
176 curl_easy_setopt(sslerrconn, CURLOPT_FAILONERROR, TRUE);
177 curl_easy_setopt(sslerrconn, CURLOPT_USERAGENT, XSDAB_USERAGENT);
178 curl_easy_setopt(sslerrconn, CURLOPT_USERPWD, (const char*)ServerAuth.mb_str(wxConvUTF8));
179 curl_easy_setopt(sslerrconn, CURLOPT_WRITEFUNCTION, WritebackFunc);
180 curl_easy_setopt(sslerrconn, CURLOPT_WRITEDATA, &PageData);
181 curl_easy_setopt(sslerrconn, CURLOPT_WRITEHEADER, &PageHeader);
182 curl_easy_setopt(sslerrconn, CURLOPT_NOSIGNAL, 1);
183 curl_easy_setopt(sslerrconn, CURLOPT_SSL_VERIFYPEER, 0);
184 curl_easy_setopt(sslerrconn, CURLOPT_SSL_VERIFYHOST, 0);
185 curl_easy_setopt(sslerrconn, CURLOPT_CERTINFO, 1);
187 wxString SSLLocalData;
188 wxString SSLServerData;
190 sslerrconncode = (curl_easy_perform(sslerrconn));
192 SSLCertCol = BuildSSLCollection(sslerrconn);
193 std::map<int, SSLCertData>::iterator SSLCDIter = SSLCertCol.SSLCollection.find(0);
194 std::multimap<wxString,wxString>::iterator SSLDataIter = SSLCDIter->second.CertData.find(wxT("Cert"));
196 wxFFile SSLLocalFile;
198 #if wxABI_VERSION < 20900
199 SSLLocalFile.Open(ServerCertFilename.c_str(), wxT("r"));
201 SSLLocalFile.Open(ServerCertFilename, wxT("r"));
204 // Load the recovery database for tasks not done.
206 if (SSLLocalFile.IsOpened() == TRUE){
208 SSLLocalFile.ReadAll(&SSLLocalData, wxConvAuto());
213 SSLServerData = SSLDataIter->second;
215 if (SSLLocalData == SSLServerData){
217 // Server key matches with local key so retry with CURLOPT_SSL_VERIFYPEER
218 // and CURLOPT_SSL_VERIFYHOST off.
220 curl_easy_cleanup(conn);
221 conn = curl_easy_init();
226 curl_easy_setopt(conn, CURLOPT_URL, (const char*)ServerAddressSSL.mb_str(wxConvUTF8));
227 curl_easy_setopt(conn, CURLOPT_NOPROGRESS, 1L);
228 curl_easy_setopt(conn, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
229 curl_easy_setopt(conn, CURLOPT_TIMEOUT, 60);
230 curl_easy_setopt(conn, CURLOPT_FAILONERROR, TRUE);
231 curl_easy_setopt(conn, CURLOPT_USERAGENT, XSDAB_USERAGENT);
232 curl_easy_setopt(conn, CURLOPT_USERPWD, (const char*)ServerAuth.mb_str(wxConvUTF8));
233 curl_easy_setopt(conn, CURLOPT_WRITEFUNCTION, WritebackFunc);
234 curl_easy_setopt(conn, CURLOPT_WRITEDATA, &PageData);
235 curl_easy_setopt(conn, CURLOPT_WRITEHEADER, &PageHeader);
236 curl_easy_setopt(conn, CURLOPT_NOSIGNAL, 1);
237 curl_easy_setopt(conn, CURLOPT_SSL_VERIFYHOST, 0);
238 curl_easy_setopt(conn, CURLOPT_SSL_VERIFYPEER, 0);
240 claconncode = (curl_easy_perform(conn));
246 if (MatchingCert == FALSE){
248 claconncode = CURLE_SSL_CACERT;
253 curl_easy_cleanup(sslerrconn);
259 // Sort out SSL error.
261 // When SSL cert error occurs, connect again and fetch certificates.
262 // Display a message to the user explaining that an invalid
263 // certificate has been given and let the user decide what
266 if (claconncode == CURLE_OK){
268 } else if (claconncode == CURLE_SSL_CACERT || claconncode == CURLE_PEER_FAILED_VERIFICATION){
271 sslerrconn = curl_easy_init();
272 CURLcode sslerrconncode;
274 wxString ServerAddressOnly = wxT("https://") + ServerAddress + wxT(":") + wxString::Format(wxT("%i"), ServerPort) + wxT("/");
276 // Replace conn with sslerrconn!
278 curl_easy_setopt(sslerrconn, CURLOPT_URL, (const char*)ServerAddressOnly.mb_str(wxConvUTF8));
279 curl_easy_setopt(sslerrconn, CURLOPT_NOPROGRESS, 0);
280 curl_easy_setopt(sslerrconn, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
281 curl_easy_setopt(sslerrconn, CURLOPT_TIMEOUT, 60);
282 curl_easy_setopt(sslerrconn, CURLOPT_FAILONERROR, TRUE);
283 curl_easy_setopt(sslerrconn, CURLOPT_USERAGENT, XSDAB_USERAGENT);
284 curl_easy_setopt(sslerrconn, CURLOPT_WRITEFUNCTION, WritebackFunc);
285 curl_easy_setopt(sslerrconn, CURLOPT_WRITEDATA, &PageData);
286 curl_easy_setopt(sslerrconn, CURLOPT_WRITEHEADER, &PageHeader);
287 curl_easy_setopt(sslerrconn, CURLOPT_PROGRESSDATA, this);
288 curl_easy_setopt(sslerrconn, CURLOPT_PROGRESSFUNCTION, ProgressFunc);
289 curl_easy_setopt(sslerrconn, CURLOPT_NOSIGNAL, 1);
290 curl_easy_setopt(sslerrconn, CURLOPT_SSL_VERIFYPEER, 0);
291 curl_easy_setopt(sslerrconn, CURLOPT_CERTINFO, 1);
293 #if defined(__APPLE__)
295 SetConnectionObject(sslerrconn);
299 sslerrconncode = (curl_easy_perform(sslerrconn));
301 SSLCertCol = BuildSSLCollection(sslerrconn);
302 SSLCertCol.SuccessCode = 1;
306 } else if (claconncode == CURLE_HTTP_RETURNED_ERROR){
308 fprintf(stderr, "curl_easy_perform() failed: %s\n",
309 curl_easy_strerror(claconncode));
311 curl_easy_getinfo(conn, CURLINFO_RESPONSE_CODE, &http_code);
312 fprintf(stderr, "Error code was: %d\n", http_code);
318 fprintf(stderr, "curl_easy_perform() failed: %s\n",
319 curl_easy_strerror(claconncode));
321 curl_easy_getinfo(conn, CURLINFO_RESPONSE_CODE, &http_code);
322 fprintf(stderr, "Error code was: %d\n", http_code);
332 wxString EmptyString;
334 curl_easy_setopt(conn, CURLOPT_URL, (const char*)ServerAddressNormal.mb_str(wxConvUTF8));
335 curl_easy_setopt(conn, CURLOPT_NOPROGRESS, 1L);
336 curl_easy_setopt(conn, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
337 curl_easy_setopt(conn, CURLOPT_TIMEOUT, 60);
338 curl_easy_setopt(conn, CURLOPT_FAILONERROR, TRUE);
339 curl_easy_setopt(conn, CURLOPT_USERAGENT, XSDAB_USERAGENT);
340 curl_easy_setopt(conn, CURLOPT_USERPWD, (const char*)ServerAuth.mb_str(wxConvUTF8));
341 curl_easy_setopt(conn, CURLOPT_WRITEFUNCTION, WritebackFunc);
342 curl_easy_setopt(conn, CURLOPT_WRITEDATA, &PageData);
343 curl_easy_setopt(conn, CURLOPT_WRITEHEADER, &PageHeader);
344 curl_easy_setopt(conn, CURLOPT_NOSIGNAL, 1);
349 conncode = (curl_easy_perform(conn));
351 if (conncode == CURLE_OK){
353 } else if (conncode == CURLE_HTTP_RETURNED_ERROR){
355 fprintf(stderr, "curl_easy_perform() failed: %s\n",
356 curl_easy_strerror(conncode));
358 fprintf(stderr, "curl_easy_perform() HTTP code was: %i\n",
365 fprintf(stderr, "curl_easy_perform() failed: %s\n",
366 curl_easy_strerror(conncode));