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;
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 //ActIter->second = 1;
105 /*wxString CardDAVDataQuery = wxT("<?xml version=\"1.0\" encoding=\"utf-8\" ?>\r\n");
106 CardDAVDataQuery.Append(wxT("<C:addressbook-multiget xmlns:D=\"DAV:\"\r\n"));
107 CardDAVDataQuery.Append(wxT(" xmlns:C=\"urn:ietf:params:xml:ns:carddav\">\r\n"));
108 CardDAVDataQuery.Append(wxT("<D:prop><D:getetag/>\r\n"));
109 CardDAVDataQuery.Append(wxT("<C:address-data>\r\n"));
110 CardDAVDataQuery.Append(wxT(" <C:allprop/>\r\n"));
111 CardDAVDataQuery.Append(wxT("</C:address-data></D:prop>\r\n"));
112 CardDAVDataQuery.Append(wxT("</C:addressbook-multiget>"));*/
116 curl_easy_setopt(conn, CURLOPT_URL, (const char*)ServerAddressSSL.mb_str(wxConvUTF8));
117 curl_easy_setopt(conn, CURLOPT_NOPROGRESS, 1L);
118 curl_easy_setopt(conn, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
119 curl_easy_setopt(conn, CURLOPT_TIMEOUT, 60);
120 curl_easy_setopt(conn, CURLOPT_FAILONERROR, TRUE);
121 curl_easy_setopt(conn, CURLOPT_USERAGENT, XSDAB_USERAGENT);
122 curl_easy_setopt(conn, CURLOPT_USERPWD, (const char*)ServerAuth.mb_str(wxConvUTF8));
123 curl_easy_setopt(conn, CURLOPT_WRITEFUNCTION, WritebackFunc);
124 curl_easy_setopt(conn, CURLOPT_WRITEDATA, &PageData);
125 curl_easy_setopt(conn, CURLOPT_WRITEHEADER, &PageHeader);
126 curl_easy_setopt(conn, CURLOPT_NOSIGNAL, 1);
128 //UploadData.readptr = &CardDAVDataQuery;
129 //UploadData.sizeleft = CardDAVDataQuery.Len();
130 //curl_easy_setopt(conn, CURLOPT_UPLOAD, 1);
131 //curl_easy_setopt(conn, CURLOPT_READDATA, &UploadData);
132 //curl_easy_setopt(conn, CURLOPT_READFUNCTION, UploadReadFunc);
134 ServerCertFilename = GetAccountDir(ServerAccount, TRUE);
136 if (wxFile::Exists(ServerCertFilename) == TRUE){
138 curl_easy_setopt(conn, CURLOPT_SSL_VERIFYPEER, 1);
139 curl_easy_setopt(conn, CURLOPT_SSL_VERIFYHOST, 2);
140 curl_easy_setopt(conn, CURLOPT_CAINFO, (const char*)ServerCertFilename.mb_str(wxConvUTF8));
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){
151 curl_easy_cleanup(conn);
152 conn = curl_easy_init();
154 curl_easy_setopt(conn, CURLOPT_URL, (const char*)ServerAddressSSL.mb_str(wxConvUTF8));
155 curl_easy_setopt(conn, CURLOPT_NOPROGRESS, 1L);
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_NOSIGNAL, 1);
166 //UploadData.readptr = &CardDAVDataQuery;
167 //UploadData.sizeleft = CardDAVDataQuery.Len();
169 claconncode = (curl_easy_perform(conn));
171 // If claconncode is CURLE_OK then delete the certificate file as that
172 // is no longer needed.
174 if (claconncode == CURLE_OK){
176 // Delete the certificate file.
178 wxRemoveFile(ServerCertFilename);
184 // Check if it fails with a CURLE_SSL_CACERT then compare
185 // the certificates as PEM files.
187 if (claconncode == CURLE_SSL_CACERT && wxFile::Exists(ServerCertFilename) == TRUE){
189 //curl_easy_cleanup(conn);
190 //conn = curl_easy_init();
193 sslerrconn = curl_easy_init();
194 CURLcode sslerrconncode;
196 //claconncode = (curl_easy_perform(conn));
198 wxString ServerAddressOnly = wxT("https://") + ServerAddress + wxT(":") + wxString::Format(wxT("%i"), ServerPort) + wxT("/");
200 curl_easy_setopt(sslerrconn, CURLOPT_URL, (const char*)ServerAddressOnly.mb_str(wxConvUTF8));
201 curl_easy_setopt(sslerrconn, CURLOPT_NOPROGRESS, 1L);
202 curl_easy_setopt(sslerrconn, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
203 curl_easy_setopt(sslerrconn, CURLOPT_TIMEOUT, 60);
204 curl_easy_setopt(sslerrconn, CURLOPT_FAILONERROR, TRUE);
205 curl_easy_setopt(sslerrconn, CURLOPT_USERAGENT, XSDAB_USERAGENT);
206 curl_easy_setopt(sslerrconn, CURLOPT_USERPWD, (const char*)ServerAuth.mb_str(wxConvUTF8));
207 curl_easy_setopt(sslerrconn, CURLOPT_WRITEFUNCTION, WritebackFunc);
208 curl_easy_setopt(sslerrconn, CURLOPT_WRITEDATA, &PageData);
209 curl_easy_setopt(sslerrconn, CURLOPT_WRITEHEADER, &PageHeader);
210 curl_easy_setopt(sslerrconn, CURLOPT_NOSIGNAL, 1);
212 //UploadData.readptr = &CardDAVDataQuery;
213 //UploadData.sizeleft = CardDAVDataQuery.Len();
214 curl_easy_setopt(sslerrconn, CURLOPT_SSL_VERIFYPEER, 0);
215 curl_easy_setopt(sslerrconn, CURLOPT_SSL_VERIFYHOST, 0);
216 curl_easy_setopt(sslerrconn, CURLOPT_CERTINFO, 1);
218 wxString SSLLocalData;
219 wxString SSLServerData;
221 sslerrconncode = (curl_easy_perform(sslerrconn));
223 SSLCertCol = BuildSSLCollection(sslerrconn);
224 std::map<int, SSLCertData>::iterator SSLCDIter = SSLCertCol.SSLCollection.find(0);
225 std::multimap<wxString,wxString>::iterator SSLDataIter = SSLCDIter->second.CertData.find(wxT("Cert"));
227 wxFFile SSLLocalFile;
229 #if wxABI_VERSION < 20900
230 SSLLocalFile.Open(ServerCertFilename.c_str(), wxT("r"));
232 SSLLocalFile.Open(ServerCertFilename, wxT("r"));
235 // Load the recovery database for tasks not done.
237 if (SSLLocalFile.IsOpened() == TRUE){
239 SSLLocalFile.ReadAll(&SSLLocalData, wxConvAuto());
244 SSLServerData = SSLDataIter->second;
246 if (SSLLocalData == SSLServerData){
248 // Server key matches with local key so retry with CURLOPT_SSL_VERIFYPEER
249 // and CURLOPT_SSL_VERIFYHOST off.
251 curl_easy_cleanup(conn);
252 conn = curl_easy_init();
257 curl_easy_setopt(conn, CURLOPT_URL, (const char*)ServerAddressSSL.mb_str(wxConvUTF8));
258 curl_easy_setopt(conn, CURLOPT_NOPROGRESS, 1L);
259 curl_easy_setopt(conn, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
260 curl_easy_setopt(conn, CURLOPT_TIMEOUT, 60);
261 curl_easy_setopt(conn, CURLOPT_FAILONERROR, TRUE);
262 curl_easy_setopt(conn, CURLOPT_USERAGENT, XSDAB_USERAGENT);
263 curl_easy_setopt(conn, CURLOPT_USERPWD, (const char*)ServerAuth.mb_str(wxConvUTF8));
264 curl_easy_setopt(conn, CURLOPT_WRITEFUNCTION, WritebackFunc);
265 curl_easy_setopt(conn, CURLOPT_WRITEDATA, &PageData);
266 curl_easy_setopt(conn, CURLOPT_WRITEHEADER, &PageHeader);
267 curl_easy_setopt(conn, CURLOPT_NOSIGNAL, 1);
269 //UploadData.readptr = &CardDAVDataQuery;
270 //UploadData.sizeleft = CardDAVDataQuery.Len();
271 curl_easy_setopt(conn, CURLOPT_SSL_VERIFYHOST, 0);
272 curl_easy_setopt(conn, CURLOPT_SSL_VERIFYPEER, 0);
274 claconncode = (curl_easy_perform(conn));
280 if (MatchingCert == FALSE){
282 claconncode = CURLE_SSL_CACERT;
287 curl_easy_cleanup(sslerrconn);
291 // Sort out SSL error.
293 // When SSL cert error occurs, connect again and fetch certificates.
294 // Display a message to the user explaining that an invalid
295 // certificate has been given and let the user decide what
298 if (claconncode == CURLE_OK){
300 } else if (claconncode == CURLE_SSL_CACERT || claconncode == CURLE_PEER_FAILED_VERIFICATION){
303 sslerrconn = curl_easy_init();
304 CURLcode sslerrconncode;
306 wxString ServerAddressOnly = wxT("https://") + ServerAddress + wxT(":") + wxString::Format(wxT("%i"), ServerPort) + wxT("/");
308 // Replace conn with sslerrconn!
310 curl_easy_setopt(sslerrconn, CURLOPT_URL, (const char*)ServerAddressOnly.mb_str(wxConvUTF8));
311 curl_easy_setopt(sslerrconn, CURLOPT_NOPROGRESS, 0);
312 curl_easy_setopt(sslerrconn, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
313 curl_easy_setopt(sslerrconn, CURLOPT_TIMEOUT, 60);
314 curl_easy_setopt(sslerrconn, CURLOPT_FAILONERROR, TRUE);
315 curl_easy_setopt(sslerrconn, CURLOPT_USERAGENT, XSDAB_USERAGENT);
316 curl_easy_setopt(sslerrconn, CURLOPT_WRITEFUNCTION, WritebackFunc);
317 curl_easy_setopt(sslerrconn, CURLOPT_WRITEDATA, &PageData);
318 curl_easy_setopt(sslerrconn, CURLOPT_WRITEHEADER, &PageHeader);
319 curl_easy_setopt(sslerrconn, CURLOPT_PROGRESSDATA, this);
320 curl_easy_setopt(sslerrconn, CURLOPT_PROGRESSFUNCTION, ProgressFunc);
321 curl_easy_setopt(sslerrconn, CURLOPT_NOSIGNAL, 1);
322 curl_easy_setopt(sslerrconn, CURLOPT_SSL_VERIFYPEER, 0);
323 curl_easy_setopt(sslerrconn, CURLOPT_CERTINFO, 1);
325 sslerrconncode = (curl_easy_perform(sslerrconn));
327 SSLCertCol = BuildSSLCollection(sslerrconn);
328 SSLCertCol.SuccessCode = 1;
332 } else if (claconncode == CURLE_HTTP_RETURNED_ERROR){
334 fprintf(stderr, "curl_easy_perform() failed: %s\n",
335 curl_easy_strerror(claconncode));
337 curl_easy_getinfo(conn, CURLINFO_RESPONSE_CODE, &http_code);
338 fprintf(stderr, "Error code was: %d\n", http_code);
344 fprintf(stderr, "curl_easy_perform() failed: %s\n",
345 curl_easy_strerror(claconncode));
347 curl_easy_getinfo(conn, CURLINFO_RESPONSE_CODE, &http_code);
348 fprintf(stderr, "Error code was: %d\n", http_code);
358 wxString EmptyString;
360 curl_easy_setopt(conn, CURLOPT_URL, (const char*)ServerAddressNormal.mb_str(wxConvUTF8));
361 curl_easy_setopt(conn, CURLOPT_NOPROGRESS, 1L);
362 curl_easy_setopt(conn, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
363 curl_easy_setopt(conn, CURLOPT_TIMEOUT, 60);
364 curl_easy_setopt(conn, CURLOPT_FAILONERROR, TRUE);
365 curl_easy_setopt(conn, CURLOPT_USERAGENT, XSDAB_USERAGENT);
366 curl_easy_setopt(conn, CURLOPT_USERPWD, (const char*)ServerAuth.mb_str(wxConvUTF8));
367 curl_easy_setopt(conn, CURLOPT_WRITEFUNCTION, WritebackFunc);
368 curl_easy_setopt(conn, CURLOPT_WRITEDATA, &PageData);
369 curl_easy_setopt(conn, CURLOPT_WRITEHEADER, &PageHeader);
370 curl_easy_setopt(conn, CURLOPT_NOSIGNAL, 1);
372 //UploadData.readptr = &CardDAVDataQuery;
373 //UploadData.sizeleft = CardDAVDataQuery.Len();
374 //curl_easy_setopt(conn, CURLOPT_UPLOAD, 1);
375 //curl_easy_setopt(conn, CURLOPT_READDATA, &UploadData);
376 //curl_easy_setopt(conn, CURLOPT_READFUNCTION, UploadReadFunc);
378 //UploadData.readptr = &CardDAVDataQuery;
379 //UploadData.sizeleft = CardDAVDataQuery.Len();
380 //curl_easy_setopt(conn, CURLOPT_UPLOAD, 1);
381 //curl_easy_setopt(conn, CURLOPT_READDATA, &UploadData);
382 //curl_easy_setopt(conn, CURLOPT_READFUNCTION, UploadReadFunc);
384 //curl_easy_setopt(conn, CURLOPT_WRITEFUNCTION, writefunc);
389 conncode = (curl_easy_perform(conn));
391 if (conncode == CURLE_OK){
393 } else if (conncode == CURLE_HTTP_RETURNED_ERROR){
395 fprintf(stderr, "curl_easy_perform() failed: %s\n",
396 curl_easy_strerror(conncode));
398 fprintf(stderr, "curl_easy_perform() HTTP code was: %i\n",
405 fprintf(stderr, "curl_easy_perform() failed: %s\n",
406 curl_easy_strerror(conncode));