1 // carddav-connect.cpp - CardDAV Object - Connect 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 bool CardDAV::Connect(){
33 // Connect to the CardDAV server.
40 AbortConnection = FALSE;
44 wxString ServerAddressURL;
46 wxString ServerAddressSSL;
47 wxString ServerAddressNormal;
49 conn = curl_easy_init();
51 struct CardDAVCURLPasser {
54 bool HeaderMode = TRUE;
56 } CardDAVHeader, CardDAVFooter;
58 CardDAVHeader.Data = this;
59 CardDAVHeader.HeaderMode = TRUE;
61 CardDAVFooter.Data = this;
62 CardDAVFooter.HeaderMode = FALSE;
67 ServerAddressURL = ServerAddress + wxT(":") + wxString::Format(wxT("%i"), ServerPort) + wxT("/");
68 ServerAddressSSL = wxT("https://") + ServerAddressURL;
69 ServerAddressNormal = wxT("http://") + ServerAddressURL;
71 ServerAuth = ServerUser + wxT(":") + ServerPass;
78 struct curl_slist *certdata;
79 struct curl_certinfo *certinfo;
84 // Setup two initial connections and attempt to get the certificate data.
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_WRITEFUNCTION, WritebackFunc);
93 curl_easy_setopt(conn, CURLOPT_WRITEDATA, &PageData);
94 curl_easy_setopt(conn, CURLOPT_WRITEHEADER, &PageHeader);
95 curl_easy_setopt(conn, CURLOPT_NOSIGNAL, 1);
96 curl_easy_setopt(conn, CURLOPT_CERTINFO, 1);
98 conncode = (curl_easy_perform(conn));
100 // Check if the SSL certificate is valid or self-signed or some other
103 if (conncode == CURLE_OK){
105 // Connection is OK. Do nothing.
107 } else if (conncode == CURLE_SSL_CACERT){
109 // Post message saying SSL certificate is invalid.
111 curl_easy_getinfo(conn, CURLINFO_CERTINFO, &ptr.certdata);
115 fprintf(stderr, "curl_easy_perform() failed: %s\n",
116 curl_easy_strerror(conncode));
118 ErrorMessage = wxString::Format(wxT("%s"), curl_easy_strerror(conncode));
120 *ServerResult = FALSE;
125 ServerAddressSSL.append("principals/");
127 curl_easy_setopt(conn, CURLOPT_URL, (const char*)ServerAddressSSL.mb_str(wxConvUTF8));
128 curl_easy_setopt(conn, CURLOPT_NOPROGRESS, 1L);
129 curl_easy_setopt(conn, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
130 curl_easy_setopt(conn, CURLOPT_TIMEOUT, 60);
131 curl_easy_setopt(conn, CURLOPT_FAILONERROR, TRUE);
132 curl_easy_setopt(conn, CURLOPT_USERAGENT, XSDAB_USERAGENT);
133 curl_easy_setopt(conn, CURLOPT_USERPWD, (const char*)ServerAuth.mb_str(wxConvUTF8));
134 curl_easy_setopt(conn, CURLOPT_WRITEFUNCTION, WritebackFunc);
135 curl_easy_setopt(conn, CURLOPT_WRITEDATA, &PageData);
136 curl_easy_setopt(conn, CURLOPT_WRITEHEADER, &PageHeader);
137 curl_easy_setopt(conn, CURLOPT_CUSTOMREQUEST, "OPTIONS");
138 curl_easy_setopt(conn, CURLOPT_NOSIGNAL, 1);
139 curl_easy_setopt(conn, CURLOPT_CERTINFO, 1);
141 if (AllowSelfSign == TRUE){
142 curl_easy_setopt(conn, CURLOPT_SSL_VERIFYPEER, 0L);
143 curl_easy_setopt(conn, CURLOPT_SSL_VERIFYHOST, 0L);
146 #if defined(__APPLE__) || defined(__WIN32__)
148 SetConnectionObject(conn);
152 conncode = (curl_easy_perform(conn));
156 curl_easy_getinfo(conn, CURLINFO_CERTINFO, &ptr.certdata);
158 if (conncode == CURLE_OK){
160 // Process the server header response and look for
161 // 'addressbook' within the DAV header.
163 wxStringTokenizer wxSHeaderLines(PageHeader, wxT("\r\n"));
164 wxString wxSHeaderLine;
165 std::map<int, wxString> DAVHeaderLines;
167 while (wxSHeaderLines.HasMoreTokens()){
169 wxSHeaderLine = wxSHeaderLines.GetNextToken();
171 if (wxSHeaderLine.Mid(0, 4) == wxT("DAV:")){
173 // Look for address book in the line.
175 if (wxSHeaderLine.Find(wxT("addressbook")) != wxNOT_FOUND){
177 HasCalDAVSupport = TRUE;
185 *ServerResult = TRUE;
186 ValidResponse = TRUE;
191 } else if (conncode == CURLE_HTTP_RETURNED_ERROR){
193 fprintf(stderr, "curl_easy_perform() failed: %s\n",
194 curl_easy_strerror(conncode));
196 ErrorMessage = wxString::Format(wxT("%s"), curl_easy_strerror(conncode));
198 *ServerResult = TRUE;
199 ValidResponse = FALSE;
206 fprintf(stderr, "curl_easy_perform() failed: %s\n",
207 curl_easy_strerror(conncode));
209 ErrorMessage = wxString::Format(wxT("%s"), curl_easy_strerror(conncode));
211 *ServerResult = FALSE;
220 curl_easy_setopt(conn, CURLOPT_URL, (const char*)ServerAddressNormal.mb_str(wxConvUTF8));
221 curl_easy_setopt(conn, CURLOPT_NOPROGRESS, 1L);
222 curl_easy_setopt(conn, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
223 curl_easy_setopt(conn, CURLOPT_TIMEOUT, 60);
224 curl_easy_setopt(conn, CURLOPT_FAILONERROR, TRUE);
225 curl_easy_setopt(conn, CURLOPT_USERAGENT, XSDAB_USERAGENT);
226 curl_easy_setopt(conn, CURLOPT_USERPWD, (const char*)ServerAuth.mb_str(wxConvUTF8));
227 curl_easy_setopt(conn, CURLOPT_WRITEFUNCTION, WritebackFunc);
228 curl_easy_setopt(conn, CURLOPT_WRITEDATA, &PageData);
229 curl_easy_setopt(conn, CURLOPT_WRITEHEADER, &PageHeader);
230 curl_easy_setopt(conn, CURLOPT_NOSIGNAL, 1);
232 conncode = (curl_easy_perform(conn));
234 if (conncode == CURLE_OK){
236 // Process the server header response and look for
237 // 'addressbook' within the DAV header.
239 wxStringTokenizer wxSHeaderLines(PageHeader, wxT("\r\n"));
240 wxString wxSHeaderLine;
241 std::map<int, wxString> DAVHeaderLines;
243 while (wxSHeaderLines.HasMoreTokens()){
245 wxSHeaderLine = wxSHeaderLines.GetNextToken();
247 if (wxSHeaderLine.Mid(0, 4) == wxT("DAV:")){
249 // Look for address book in the line.
251 if (wxSHeaderLine.Find(wxT("addressbook")) != wxNOT_FOUND){
253 HasCalDAVSupport = TRUE;
261 *ServerResult = TRUE;
262 ValidResponse = TRUE;
267 } else if (conncode == CURLE_HTTP_RETURNED_ERROR){
269 fprintf(stderr, "curl_easy_perform() failed: %s\n",
270 curl_easy_strerror(conncode));
272 *ServerResult = TRUE;
273 ValidResponse = FALSE;
280 fprintf(stderr, "curl_easy_perform() failed: %s\n",
281 curl_easy_strerror(conncode));
283 *ServerResult = FALSE;
288 // TODO: Double check and make sure HTTP Authentication is possible.
292 *ServerResult = TRUE;