2 #include "../version.h"
4 #include <wx/tokenzr.h>
6 #include <libxml/parser.h>
7 #include <libxml/tree.h>
10 #include "../vcard/vcard.h"
11 #include "../common/dirs.h"
13 wxString CardDAV::GetDefaultAddressBookURL(){
15 // First: Get the principal UID address.
22 AbortConnection = FALSE;
26 wxString ServerAddressURL;
28 wxString ServerAddressSSL;
29 wxString ServerAddressNormal;
31 conn = curl_easy_init();
33 struct curl_slist *connhd = NULL;
34 struct curl_slist *connhd2 = NULL;
35 struct curl_slist *connhd3 = NULL;
37 connhd = curl_slist_append(connhd, "Depth: 0");
38 connhd = curl_slist_append(connhd, "Prefer: return-minimal");
39 connhd = curl_slist_append(connhd, "Content-Type: application/xml; charset=utf-8");
41 connhd2 = curl_slist_append(connhd2, "Depth: 0");
42 connhd2 = curl_slist_append(connhd2, "Prefer: return-minimal");
43 connhd2 = curl_slist_append(connhd2, "Content-Type: application/xml; charset=utf-8");
45 connhd3 = curl_slist_append(connhd3, "Depth: 1");
46 connhd3 = curl_slist_append(connhd3, "Prefer: return-minimal");
47 connhd3 = curl_slist_append(connhd3, "Content-Type: application/xml; charset=utf-8");
49 struct CardDAVCURLPasser {
52 bool HeaderMode = TRUE;
54 } CardDAVHeader, CardDAVFooter;
56 CardDAVHeader.Data = this;
57 CardDAVHeader.HeaderMode = TRUE;
59 CardDAVFooter.Data = this;
60 CardDAVFooter.HeaderMode = FALSE;
66 wxString ETagOriginal;
69 ServerAddressURL = ServerAddress + wxT(":") + wxString::Format(wxT("%i"), ServerPort) + wxT("/");
70 ServerAddressSSL = wxT("https://") + ServerAddressURL;
71 ServerAddressNormal = wxT("http://") + ServerAddressURL;
73 ServerAuth = ServerUser + wxT(":") + ServerPass;
75 wxString SAURLPrincipals;
76 wxString SAURLPrincipalURL;
77 wxString SAURLAddressURL;
81 SAURLPrincipals = ServerAddressSSL + wxT("principals/");
82 SAURLPrincipalURL = ServerAddressSSL;
83 SAURLAddressURL = ServerAddressSSL;
87 SAURLPrincipals = ServerAddressNormal + wxT("principals/");
88 SAURLPrincipalURL = ServerAddressNormal;
89 SAURLAddressURL = ServerAddressNormal;
95 struct UploadDataStruc UploadData;
97 // Setup the first query finding out where the principal URL is.
99 const char* query = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"
100 "<D:propfind xmlns:D=\"DAV:\">\n"
102 " <D:current-user-principal/>\n"
106 // Setup the second query finding out where the address book home URL is.
108 const char* query2 = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"
109 "<D:propfind xmlns:D=\"DAV:\""
110 " xmlns:C=\"urn:ietf:params:xml:ns:carddav\">\n"
112 " <C:addressbook-home-set/>\n"
116 // Setup the third query finding out where the default address book URL is.
118 const char* query3 = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"
119 "<D:propfind xmlns:D=\"DAV:\""
120 " xmlns:C=\"urn:ietf:params:xml:ns:carddav\">\n"
122 " <C:default-addressbook-URL/>\n"
128 curl_easy_setopt(conn, CURLOPT_URL, (const char*)SAURLPrincipals.mb_str(wxConvUTF8));
129 curl_easy_setopt(conn, CURLOPT_NOPROGRESS, 1L);
130 curl_easy_setopt(conn, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
131 curl_easy_setopt(conn, CURLOPT_TIMEOUT, 60);
132 curl_easy_setopt(conn, CURLOPT_FAILONERROR, TRUE);
133 curl_easy_setopt(conn, CURLOPT_USERAGENT, XSDAB_USERAGENT);
134 curl_easy_setopt(conn, CURLOPT_USERPWD, (const char*)ServerAuth.mb_str(wxConvUTF8));
135 curl_easy_setopt(conn, CURLOPT_WRITEFUNCTION, WritebackFunc);
136 curl_easy_setopt(conn, CURLOPT_WRITEDATA, &PageData);
137 curl_easy_setopt(conn, CURLOPT_WRITEHEADER, &PageHeader);
138 curl_easy_setopt(conn, CURLOPT_NOSIGNAL, 1);
139 curl_easy_setopt(conn, CURLOPT_CUSTOMREQUEST, "PROPFIND");
140 curl_easy_setopt(conn, CURLOPT_POSTFIELDS, query);
141 curl_easy_setopt(conn, CURLOPT_POSTFIELDSIZE, strlen(query));
142 curl_easy_setopt(conn, CURLOPT_HTTPHEADER, connhd);
144 if (AllowSelfSign == TRUE){
145 curl_easy_setopt(conn, CURLOPT_SSL_VERIFYPEER, 0L);
146 curl_easy_setopt(conn, CURLOPT_SSL_VERIFYHOST, 0L);
149 conncode = (curl_easy_perform(conn));
151 if (conncode == CURLE_OK){
153 *ServerResult = TRUE;
155 ValidResponse = TRUE;
160 fprintf(stderr, "curl_easy_perform() failed: %s\n",
161 curl_easy_strerror(conncode));
163 *ServerResult = FALSE;
165 curl_easy_getinfo(conn, CURLINFO_RESPONSE_CODE, &HTTPErrorCode);
175 // Do an initial connection (incase of Digest authentication).
180 curl_easy_setopt(conn, CURLOPT_URL, (const char*)SAURLPrincipals.mb_str(wxConvUTF8));
181 curl_easy_setopt(conn, CURLOPT_NOPROGRESS, 0);
182 curl_easy_setopt(conn, CURLOPT_HTTPAUTH, CURLAUTH_ANYSAFE);
183 curl_easy_setopt(conn, CURLOPT_TIMEOUT, 60);
184 curl_easy_setopt(conn, CURLOPT_FAILONERROR, FALSE);
185 curl_easy_setopt(conn, CURLOPT_USERAGENT, XSDAB_USERAGENT);
186 curl_easy_setopt(conn, CURLOPT_USERPWD, (const char*)ServerAuth.mb_str(wxConvUTF8));
187 curl_easy_setopt(conn, CURLOPT_WRITEFUNCTION, WritebackFunc);
188 curl_easy_setopt(conn, CURLOPT_WRITEDATA, &PageData);
189 curl_easy_setopt(conn, CURLOPT_WRITEHEADER, &PageHeader);
190 curl_easy_setopt(conn, CURLOPT_PROGRESSDATA, this);
191 curl_easy_setopt(conn, CURLOPT_PROGRESSFUNCTION, ProgressFunc);
192 curl_easy_setopt(conn, CURLOPT_NOSIGNAL, 1);
193 curl_easy_setopt(conn, CURLOPT_CUSTOMREQUEST, "PROPFIND");
194 curl_easy_setopt(conn, CURLOPT_POSTFIELDS, query);
195 curl_easy_setopt(conn, CURLOPT_POSTFIELDSIZE, strlen(query));
196 curl_easy_setopt(conn, CURLOPT_HTTPHEADER, connhd);
198 conncode = (curl_easy_perform(conn));
200 // If the ETag is different to the non-matching X-XAB-ETAG and X-XAB-ETAG-ORIG,
201 // then bring up the conflict resolution form.
203 if (EditMode == TRUE){
207 if (conncode == CURLE_OK){
209 } else if (conncode == CURLE_HTTP_RETURNED_ERROR){
211 curl_easy_getinfo(conn, CURLINFO_RESPONSE_CODE, &HTTPErrorCode);
213 fprintf(stderr, "curl_easy_perform() failed: %s\n",
214 curl_easy_strerror(conncode));
216 fprintf(stderr, "curl_easy_perform() HTTP code was: %i\n",
223 fprintf(stderr, "curl_easy_perform() failed: %s\n",
224 curl_easy_strerror(conncode));
231 // Process the XML data from the application.
233 xmlDocPtr xmlCardDAVDoc;
234 xmlCardDAVDoc = xmlReadMemory(PageData.mb_str(wxConvUTF8), (int)PageData.Len(), "noname.xml", NULL, 0);
236 xmlNodePtr nodeLevel1;
237 xmlNodePtr nodeLevel2;
238 xmlNodePtr nodeLevel3;
239 xmlNodePtr nodeLevel4;
240 xmlNodePtr nodeLevel5;
241 xmlNodePtr nodeLevel6;
242 xmlNodePtr nodeLevel7;
244 for (nodeLevel1 = xmlCardDAVDoc->children;
246 nodeLevel1 = nodeLevel1->next)
249 for (nodeLevel2 = nodeLevel1->children;
251 nodeLevel2 = nodeLevel2->next)
255 for (nodeLevel3 = nodeLevel2->children;
257 nodeLevel3 = nodeLevel3->next)
260 for (nodeLevel4 = nodeLevel3->children;
262 nodeLevel4 = nodeLevel4->next)
265 for (nodeLevel5 = nodeLevel4->children;
267 nodeLevel5 = nodeLevel5->next)
270 for (nodeLevel6 = nodeLevel5->children;
272 nodeLevel6 = nodeLevel6->next)
275 if (!xmlStrcmp(nodeLevel6->name, (const xmlChar *)"href") ||
276 !xmlStrcmp(nodeLevel6->name, (const xmlChar *)"d:href") ||
277 !xmlStrcmp(nodeLevel6->name, (const xmlChar *)"D:href")
280 // Found the <href> part so extract the principal URL address.
282 for (nodeLevel7 = nodeLevel6->children;
284 nodeLevel7 = nodeLevel7->next)
287 SAURLPrincipalURL.Append(wxString::FromUTF8((const char*)nodeLevel7->content));
305 xmlFreeDoc(xmlCardDAVDoc);
309 // Second: Get the addressbook-home-set
311 curl_easy_reset(conn);
315 curl_easy_setopt(conn, CURLOPT_URL, (const char*)SAURLPrincipalURL.mb_str(wxConvUTF8));
316 curl_easy_setopt(conn, CURLOPT_NOPROGRESS, 1L);
317 curl_easy_setopt(conn, CURLOPT_HTTPAUTH, CURLAUTH_ANYSAFE);
318 curl_easy_setopt(conn, CURLOPT_TIMEOUT, 60);
319 curl_easy_setopt(conn, CURLOPT_FAILONERROR, FALSE);
320 curl_easy_setopt(conn, CURLOPT_USERAGENT, XSDAB_USERAGENT);
321 curl_easy_setopt(conn, CURLOPT_USERPWD, (const char*)ServerAuth.mb_str(wxConvUTF8));
322 curl_easy_setopt(conn, CURLOPT_WRITEFUNCTION, WritebackFunc);
323 curl_easy_setopt(conn, CURLOPT_WRITEDATA, &PageData);
324 curl_easy_setopt(conn, CURLOPT_WRITEHEADER, &PageHeader);
325 curl_easy_setopt(conn, CURLOPT_NOSIGNAL, 1);
326 curl_easy_setopt(conn, CURLOPT_CUSTOMREQUEST, "PROPFIND");
327 curl_easy_setopt(conn, CURLOPT_POSTFIELDS, query2);
328 curl_easy_setopt(conn, CURLOPT_POSTFIELDSIZE, strlen(query2));
329 curl_easy_setopt(conn, CURLOPT_HTTPHEADER, connhd2);
331 if (AllowSelfSign == TRUE){
332 curl_easy_setopt(conn, CURLOPT_SSL_VERIFYPEER, 0L);
333 curl_easy_setopt(conn, CURLOPT_SSL_VERIFYHOST, 0L);
336 conncode = (curl_easy_perform(conn));
338 if (conncode == CURLE_OK){
340 *ServerResult = TRUE;
346 fprintf(stderr, "curl_easy_perform() failed: %s\n",
347 curl_easy_strerror(conncode));
349 *ServerResult = FALSE;
350 ValidResponse = FALSE;
352 curl_easy_getinfo(conn, CURLINFO_RESPONSE_CODE, &HTTPErrorCode);
362 curl_easy_setopt(conn, CURLOPT_URL, (const char*)SAURLPrincipalURL.mb_str(wxConvUTF8));
363 curl_easy_setopt(conn, CURLOPT_NOPROGRESS, 0);
364 curl_easy_setopt(conn, CURLOPT_HTTPAUTH, CURLAUTH_ANYSAFE);
365 curl_easy_setopt(conn, CURLOPT_TIMEOUT, 60);
366 curl_easy_setopt(conn, CURLOPT_FAILONERROR, FALSE);
367 curl_easy_setopt(conn, CURLOPT_USERAGENT, XSDAB_USERAGENT);
368 curl_easy_setopt(conn, CURLOPT_USERPWD, (const char*)ServerAuth.mb_str(wxConvUTF8));
369 curl_easy_setopt(conn, CURLOPT_WRITEFUNCTION, WritebackFunc);
370 curl_easy_setopt(conn, CURLOPT_WRITEDATA, &PageData);
371 curl_easy_setopt(conn, CURLOPT_WRITEHEADER, &PageHeader);
372 curl_easy_setopt(conn, CURLOPT_PROGRESSDATA, this);
373 curl_easy_setopt(conn, CURLOPT_PROGRESSFUNCTION, ProgressFunc);
374 curl_easy_setopt(conn, CURLOPT_NOSIGNAL, 1);
375 curl_easy_setopt(conn, CURLOPT_CUSTOMREQUEST, "PROPFIND");
376 curl_easy_setopt(conn, CURLOPT_POSTFIELDS, query2);
377 curl_easy_setopt(conn, CURLOPT_POSTFIELDSIZE, strlen(query2));
378 curl_easy_setopt(conn, CURLOPT_HTTPHEADER, connhd2);
380 conncode = (curl_easy_perform(conn));
382 // If the ETag is different to the non-matching X-XAB-ETAG and X-XAB-ETAG-ORIG,
383 // then bring up the conflict resolution form.
385 if (EditMode == TRUE){
389 if (conncode == CURLE_OK){
391 } else if (conncode == CURLE_HTTP_RETURNED_ERROR){
393 curl_easy_getinfo(conn, CURLINFO_RESPONSE_CODE, &HTTPErrorCode);
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",
401 ValidResponse = FALSE;
407 fprintf(stderr, "curl_easy_perform() failed: %s\n",
408 curl_easy_strerror(conncode));
410 ValidResponse = FALSE;
418 xmlCardDAVDoc = xmlReadMemory(PageData.mb_str(wxConvUTF8), (int)PageData.Len(), "noname.xml", NULL, 0);
420 for (nodeLevel1 = xmlCardDAVDoc->children;
422 nodeLevel1 = nodeLevel1->next)
425 for (nodeLevel2 = nodeLevel1->children;
427 nodeLevel2 = nodeLevel2->next)
431 for (nodeLevel3 = nodeLevel2->children;
433 nodeLevel3 = nodeLevel3->next)
436 for (nodeLevel4 = nodeLevel3->children;
438 nodeLevel4 = nodeLevel4->next)
441 for (nodeLevel5 = nodeLevel4->children;
443 nodeLevel5 = nodeLevel5->next)
446 for (nodeLevel6 = nodeLevel5->children;
448 nodeLevel6 = nodeLevel6->next)
451 if (!xmlStrcmp(nodeLevel6->name, (const xmlChar *)"href") ||
452 !xmlStrcmp(nodeLevel6->name, (const xmlChar *)"d:href") ||
453 !xmlStrcmp(nodeLevel6->name, (const xmlChar *)"D:href")
456 // Found the <href> part so extract the principal URL address.
458 for (nodeLevel7 = nodeLevel6->children;
460 nodeLevel7 = nodeLevel7->next)
463 SAURLAddressURL.Append(wxString::FromUTF8((const char*)nodeLevel7->content));
481 xmlFreeDoc(xmlCardDAVDoc);
485 // Finally: Get the default-addressbook-URL from the addressbook-home-set address.
487 curl_easy_reset(conn);
491 curl_easy_setopt(conn, CURLOPT_URL, (const char*)SAURLAddressURL.mb_str(wxConvUTF8));
492 curl_easy_setopt(conn, CURLOPT_NOPROGRESS, 1L);
493 curl_easy_setopt(conn, CURLOPT_HTTPAUTH, CURLAUTH_ANYSAFE);
494 curl_easy_setopt(conn, CURLOPT_TIMEOUT, 60);
495 curl_easy_setopt(conn, CURLOPT_FAILONERROR, FALSE);
496 curl_easy_setopt(conn, CURLOPT_USERAGENT, XSDAB_USERAGENT);
497 curl_easy_setopt(conn, CURLOPT_USERPWD, (const char*)ServerAuth.mb_str(wxConvUTF8));
498 curl_easy_setopt(conn, CURLOPT_WRITEFUNCTION, WritebackFunc);
499 curl_easy_setopt(conn, CURLOPT_WRITEDATA, &PageData);
500 curl_easy_setopt(conn, CURLOPT_WRITEHEADER, &PageHeader);
501 curl_easy_setopt(conn, CURLOPT_NOSIGNAL, 1);
502 curl_easy_setopt(conn, CURLOPT_CUSTOMREQUEST, "PROPFIND");
503 curl_easy_setopt(conn, CURLOPT_POSTFIELDS, query3);
504 curl_easy_setopt(conn, CURLOPT_POSTFIELDSIZE, strlen(query3));
505 curl_easy_setopt(conn, CURLOPT_HTTPHEADER, connhd3);
507 if (AllowSelfSign == TRUE){
508 curl_easy_setopt(conn, CURLOPT_SSL_VERIFYPEER, 0L);
509 curl_easy_setopt(conn, CURLOPT_SSL_VERIFYHOST, 0L);
512 conncode = (curl_easy_perform(conn));
514 if (conncode == CURLE_OK){
516 *ServerResult = TRUE;
522 fprintf(stderr, "curl_easy_perform() failed: %s\n",
523 curl_easy_strerror(conncode));
525 *ServerResult = FALSE;
526 ValidResponse = FALSE;
528 curl_easy_getinfo(conn, CURLINFO_RESPONSE_CODE, &HTTPErrorCode);
538 curl_easy_setopt(conn, CURLOPT_URL, (const char*)SAURLAddressURL.mb_str(wxConvUTF8));
539 curl_easy_setopt(conn, CURLOPT_NOPROGRESS, 0);
540 curl_easy_setopt(conn, CURLOPT_HTTPAUTH, CURLAUTH_ANYSAFE);
541 curl_easy_setopt(conn, CURLOPT_TIMEOUT, 60);
542 curl_easy_setopt(conn, CURLOPT_FAILONERROR, FALSE);
543 curl_easy_setopt(conn, CURLOPT_USERAGENT, XSDAB_USERAGENT);
544 curl_easy_setopt(conn, CURLOPT_USERPWD, (const char*)ServerAuth.mb_str(wxConvUTF8));
545 curl_easy_setopt(conn, CURLOPT_WRITEFUNCTION, WritebackFunc);
546 curl_easy_setopt(conn, CURLOPT_WRITEDATA, &PageData);
547 curl_easy_setopt(conn, CURLOPT_WRITEHEADER, &PageHeader);
548 curl_easy_setopt(conn, CURLOPT_PROGRESSDATA, this);
549 curl_easy_setopt(conn, CURLOPT_PROGRESSFUNCTION, ProgressFunc);
550 curl_easy_setopt(conn, CURLOPT_NOSIGNAL, 1);
551 curl_easy_setopt(conn, CURLOPT_CUSTOMREQUEST, "PROPFIND");
552 curl_easy_setopt(conn, CURLOPT_POSTFIELDS, query3);
553 curl_easy_setopt(conn, CURLOPT_POSTFIELDSIZE, strlen(query3));
554 curl_easy_setopt(conn, CURLOPT_HTTPHEADER, connhd3);
556 conncode = (curl_easy_perform(conn));
558 // If the ETag is different to the non-matching X-XAB-ETAG and X-XAB-ETAG-ORIG,
559 // then bring up the conflict resolution form.
561 if (EditMode == TRUE){
565 if (conncode == CURLE_OK){
567 } else if (conncode == CURLE_HTTP_RETURNED_ERROR){
569 curl_easy_getinfo(conn, CURLINFO_RESPONSE_CODE, &HTTPErrorCode);
571 fprintf(stderr, "curl_easy_perform() failed: %s\n",
572 curl_easy_strerror(conncode));
574 fprintf(stderr, "curl_easy_perform() HTTP code was: %i\n",
577 ValidResponse = FALSE;
583 fprintf(stderr, "curl_easy_perform() failed: %s\n",
584 curl_easy_strerror(conncode));
586 ValidResponse = FALSE;
594 xmlCardDAVDoc = xmlReadMemory(PageData.mb_str(wxConvUTF8), (int)PageData.Len(), "noname.xml", NULL, 0);
596 for (nodeLevel1 = xmlCardDAVDoc->children;
598 nodeLevel1 = nodeLevel1->next)
601 for (nodeLevel2 = nodeLevel1->children;
603 nodeLevel2 = nodeLevel2->next)
607 for (nodeLevel3 = nodeLevel2->children;
609 nodeLevel3 = nodeLevel3->next)
612 for (nodeLevel4 = nodeLevel3->children;
614 nodeLevel4 = nodeLevel4->next)
617 for (nodeLevel5 = nodeLevel4->children;
619 nodeLevel5 = nodeLevel5->next)
622 for (nodeLevel6 = nodeLevel5->children;
624 nodeLevel6 = nodeLevel6->next)
627 if (!xmlStrcmp(nodeLevel6->name, (const xmlChar *)"href") ||
628 !xmlStrcmp(nodeLevel6->name, (const xmlChar *)"d:href") ||
629 !xmlStrcmp(nodeLevel6->name, (const xmlChar *)"D:href")
632 // Found the <href> part so extract the principal URL address.
634 for (nodeLevel7 = nodeLevel6->children;
636 nodeLevel7 = nodeLevel7->next)
639 FinalPrefix = wxString::FromUTF8((const char*)nodeLevel7->content);
657 xmlFreeDoc(xmlCardDAVDoc);