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 struct CardDAVCURLPasser {
58 bool HeaderMode = TRUE;
60 } CardDAVHeader, CardDAVFooter;
62 CardDAVHeader.Data = this;
63 CardDAVHeader.HeaderMode = TRUE;
65 CardDAVFooter.Data = this;
66 CardDAVFooter.HeaderMode = FALSE;
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;
77 std::map<int,int>::iterator ActIter;
78 struct UploadDataStruc UploadData;
80 ActIter = ActivityListPtr->find((int)ItemIndex);
86 curl_easy_setopt(conn, CURLOPT_URL, (const char*)ServerAddressSSL.mb_str(wxConvUTF8));
87 curl_easy_setopt(conn, CURLOPT_NOPROGRESS, 1L);
88 curl_easy_setopt(conn, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
89 curl_easy_setopt(conn, CURLOPT_TIMEOUT, 60);
90 curl_easy_setopt(conn, CURLOPT_FAILONERROR, TRUE);
91 curl_easy_setopt(conn, CURLOPT_USERAGENT, XSDAB_USERAGENT);
92 curl_easy_setopt(conn, CURLOPT_USERPWD, (const char*)ServerAuth.mb_str(wxConvUTF8));
93 curl_easy_setopt(conn, CURLOPT_WRITEFUNCTION, WritebackFunc);
94 curl_easy_setopt(conn, CURLOPT_WRITEDATA, &PageData);
95 curl_easy_setopt(conn, CURLOPT_WRITEHEADER, &PageHeader);
96 curl_easy_setopt(conn, CURLOPT_NOSIGNAL, 1);
98 ServerCertFilename = GetAccountDir(ServerAccount, TRUE);
100 if (wxFile::Exists(ServerCertFilename) == TRUE){
102 curl_easy_setopt(conn, CURLOPT_SSL_VERIFYPEER, 1);
103 curl_easy_setopt(conn, CURLOPT_SSL_VERIFYHOST, 2);
104 curl_easy_setopt(conn, CURLOPT_CAINFO, (const char*)ServerCertFilename.mb_str(wxConvUTF8));
108 claconncode = (curl_easy_perform(conn));
110 // If CURLE_PEER_FAILED_VERIFICATION is returned, retry without
111 // the local certificate in use.
113 if (claconncode == CURLE_PEER_FAILED_VERIFICATION){
115 curl_easy_cleanup(conn);
116 conn = curl_easy_init();
118 curl_easy_setopt(conn, CURLOPT_URL, (const char*)ServerAddressSSL.mb_str(wxConvUTF8));
119 curl_easy_setopt(conn, CURLOPT_NOPROGRESS, 1L);
120 curl_easy_setopt(conn, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
121 curl_easy_setopt(conn, CURLOPT_TIMEOUT, 60);
122 curl_easy_setopt(conn, CURLOPT_FAILONERROR, TRUE);
123 curl_easy_setopt(conn, CURLOPT_USERAGENT, XSDAB_USERAGENT);
124 curl_easy_setopt(conn, CURLOPT_USERPWD, (const char*)ServerAuth.mb_str(wxConvUTF8));
125 curl_easy_setopt(conn, CURLOPT_WRITEFUNCTION, WritebackFunc);
126 curl_easy_setopt(conn, CURLOPT_WRITEDATA, &PageData);
127 curl_easy_setopt(conn, CURLOPT_WRITEHEADER, &PageHeader);
128 curl_easy_setopt(conn, CURLOPT_NOSIGNAL, 1);
130 claconncode = (curl_easy_perform(conn));
132 // If claconncode is CURLE_OK then delete the certificate file as that
133 // is no longer needed.
135 if (claconncode == CURLE_OK){
137 // Delete the certificate file.
139 wxRemoveFile(ServerCertFilename);
145 // Check if it fails with a CURLE_SSL_CACERT then compare
146 // the certificates as PEM files.
148 if (claconncode == CURLE_SSL_CACERT && wxFile::Exists(ServerCertFilename) == TRUE){
151 sslerrconn = curl_easy_init();
152 CURLcode sslerrconncode;
154 wxString ServerAddressOnly = wxT("https://") + ServerAddress + wxT(":") + wxString::Format(wxT("%i"), ServerPort) + wxT("/");
156 curl_easy_setopt(sslerrconn, CURLOPT_URL, (const char*)ServerAddressOnly.mb_str(wxConvUTF8));
157 curl_easy_setopt(sslerrconn, CURLOPT_NOPROGRESS, 1L);
158 curl_easy_setopt(sslerrconn, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
159 curl_easy_setopt(sslerrconn, CURLOPT_TIMEOUT, 60);
160 curl_easy_setopt(sslerrconn, CURLOPT_FAILONERROR, TRUE);
161 curl_easy_setopt(sslerrconn, CURLOPT_USERAGENT, XSDAB_USERAGENT);
162 curl_easy_setopt(sslerrconn, CURLOPT_USERPWD, (const char*)ServerAuth.mb_str(wxConvUTF8));
163 curl_easy_setopt(sslerrconn, CURLOPT_WRITEFUNCTION, WritebackFunc);
164 curl_easy_setopt(sslerrconn, CURLOPT_WRITEDATA, &PageData);
165 curl_easy_setopt(sslerrconn, CURLOPT_WRITEHEADER, &PageHeader);
166 curl_easy_setopt(sslerrconn, CURLOPT_NOSIGNAL, 1);
167 curl_easy_setopt(sslerrconn, CURLOPT_SSL_VERIFYPEER, 0);
168 curl_easy_setopt(sslerrconn, CURLOPT_SSL_VERIFYHOST, 0);
169 curl_easy_setopt(sslerrconn, CURLOPT_CERTINFO, 1);
171 wxString SSLLocalData;
172 wxString SSLServerData;
174 sslerrconncode = (curl_easy_perform(sslerrconn));
176 SSLCertCol = BuildSSLCollection(sslerrconn);
177 std::map<int, SSLCertData>::iterator SSLCDIter = SSLCertCol.SSLCollection.find(0);
178 std::multimap<wxString,wxString>::iterator SSLDataIter = SSLCDIter->second.CertData.find(wxT("Cert"));
180 wxFFile SSLLocalFile;
182 #if wxABI_VERSION < 20900
183 SSLLocalFile.Open(ServerCertFilename.c_str(), wxT("r"));
185 SSLLocalFile.Open(ServerCertFilename, wxT("r"));
188 // Load the recovery database for tasks not done.
190 if (SSLLocalFile.IsOpened() == TRUE){
192 SSLLocalFile.ReadAll(&SSLLocalData, wxConvAuto());
197 SSLServerData = SSLDataIter->second;
199 if (SSLLocalData == SSLServerData){
201 // Server key matches with local key so retry with CURLOPT_SSL_VERIFYPEER
202 // and CURLOPT_SSL_VERIFYHOST off.
204 curl_easy_cleanup(conn);
205 conn = curl_easy_init();
210 curl_easy_setopt(conn, CURLOPT_URL, (const char*)ServerAddressSSL.mb_str(wxConvUTF8));
211 curl_easy_setopt(conn, CURLOPT_NOPROGRESS, 1L);
212 curl_easy_setopt(conn, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
213 curl_easy_setopt(conn, CURLOPT_TIMEOUT, 60);
214 curl_easy_setopt(conn, CURLOPT_FAILONERROR, TRUE);
215 curl_easy_setopt(conn, CURLOPT_USERAGENT, XSDAB_USERAGENT);
216 curl_easy_setopt(conn, CURLOPT_USERPWD, (const char*)ServerAuth.mb_str(wxConvUTF8));
217 curl_easy_setopt(conn, CURLOPT_WRITEFUNCTION, WritebackFunc);
218 curl_easy_setopt(conn, CURLOPT_WRITEDATA, &PageData);
219 curl_easy_setopt(conn, CURLOPT_WRITEHEADER, &PageHeader);
220 curl_easy_setopt(conn, CURLOPT_NOSIGNAL, 1);
221 curl_easy_setopt(conn, CURLOPT_SSL_VERIFYHOST, 0);
222 curl_easy_setopt(conn, CURLOPT_SSL_VERIFYPEER, 0);
224 claconncode = (curl_easy_perform(conn));
230 if (MatchingCert == FALSE){
232 claconncode = CURLE_SSL_CACERT;
237 curl_easy_cleanup(sslerrconn);
241 // Sort out SSL error.
243 // When SSL cert error occurs, connect again and fetch certificates.
244 // Display a message to the user explaining that an invalid
245 // certificate has been given and let the user decide what
248 if (claconncode == CURLE_OK){
250 } else if (claconncode == CURLE_SSL_CACERT || claconncode == CURLE_PEER_FAILED_VERIFICATION){
253 sslerrconn = curl_easy_init();
254 CURLcode sslerrconncode;
256 wxString ServerAddressOnly = wxT("https://") + ServerAddress + wxT(":") + wxString::Format(wxT("%i"), ServerPort) + wxT("/");
258 // Replace conn with sslerrconn!
260 curl_easy_setopt(sslerrconn, CURLOPT_URL, (const char*)ServerAddressOnly.mb_str(wxConvUTF8));
261 curl_easy_setopt(sslerrconn, CURLOPT_NOPROGRESS, 0);
262 curl_easy_setopt(sslerrconn, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
263 curl_easy_setopt(sslerrconn, CURLOPT_TIMEOUT, 60);
264 curl_easy_setopt(sslerrconn, CURLOPT_FAILONERROR, TRUE);
265 curl_easy_setopt(sslerrconn, CURLOPT_USERAGENT, XSDAB_USERAGENT);
266 curl_easy_setopt(sslerrconn, CURLOPT_WRITEFUNCTION, WritebackFunc);
267 curl_easy_setopt(sslerrconn, CURLOPT_WRITEDATA, &PageData);
268 curl_easy_setopt(sslerrconn, CURLOPT_WRITEHEADER, &PageHeader);
269 curl_easy_setopt(sslerrconn, CURLOPT_PROGRESSDATA, this);
270 curl_easy_setopt(sslerrconn, CURLOPT_PROGRESSFUNCTION, ProgressFunc);
271 curl_easy_setopt(sslerrconn, CURLOPT_NOSIGNAL, 1);
272 curl_easy_setopt(sslerrconn, CURLOPT_SSL_VERIFYPEER, 0);
273 curl_easy_setopt(sslerrconn, CURLOPT_CERTINFO, 1);
275 sslerrconncode = (curl_easy_perform(sslerrconn));
277 SSLCertCol = BuildSSLCollection(sslerrconn);
278 SSLCertCol.SuccessCode = 1;
282 } else if (claconncode == CURLE_HTTP_RETURNED_ERROR){
284 fprintf(stderr, "curl_easy_perform() failed: %s\n",
285 curl_easy_strerror(claconncode));
287 curl_easy_getinfo(conn, CURLINFO_RESPONSE_CODE, &http_code);
288 fprintf(stderr, "Error code was: %d\n", http_code);
294 fprintf(stderr, "curl_easy_perform() failed: %s\n",
295 curl_easy_strerror(claconncode));
297 curl_easy_getinfo(conn, CURLINFO_RESPONSE_CODE, &http_code);
298 fprintf(stderr, "Error code was: %d\n", http_code);
308 wxString EmptyString;
310 curl_easy_setopt(conn, CURLOPT_URL, (const char*)ServerAddressNormal.mb_str(wxConvUTF8));
311 curl_easy_setopt(conn, CURLOPT_NOPROGRESS, 1L);
312 curl_easy_setopt(conn, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
313 curl_easy_setopt(conn, CURLOPT_TIMEOUT, 60);
314 curl_easy_setopt(conn, CURLOPT_FAILONERROR, TRUE);
315 curl_easy_setopt(conn, CURLOPT_USERAGENT, XSDAB_USERAGENT);
316 curl_easy_setopt(conn, CURLOPT_USERPWD, (const char*)ServerAuth.mb_str(wxConvUTF8));
317 curl_easy_setopt(conn, CURLOPT_WRITEFUNCTION, WritebackFunc);
318 curl_easy_setopt(conn, CURLOPT_WRITEDATA, &PageData);
319 curl_easy_setopt(conn, CURLOPT_WRITEHEADER, &PageHeader);
320 curl_easy_setopt(conn, CURLOPT_NOSIGNAL, 1);
325 conncode = (curl_easy_perform(conn));
327 if (conncode == CURLE_OK){
329 } else if (conncode == CURLE_HTTP_RETURNED_ERROR){
331 fprintf(stderr, "curl_easy_perform() failed: %s\n",
332 curl_easy_strerror(conncode));
334 fprintf(stderr, "curl_easy_perform() HTTP code was: %i\n",
341 fprintf(stderr, "curl_easy_perform() failed: %s\n",
342 curl_easy_strerror(conncode));