// carddav-defaultadrurl.cpp - CardDAV Object - Default Address URL subroutines. // // (c) 2012-2015 Xestia Software Development. // // This file is part of Xestia Address Book. // // Xestia Address Book is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by the // Free Software Foundation, version 3 of the license. // // Xestia Address Book is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License along // with Xestia Address Book. If not, see #include "carddav.h" #include "../version.h" #include #include #include #include #include #include #include #include "../vcard/vcard.h" #include "../common/dirs.h" wxString CardDAV::GetDefaultAddressBookURL(){ // First: Get the principal UID address. PageData.Clear(); PageHeader.Clear(); SSLStatus = TRUE; AuthPassed = TRUE; AbortConnection = FALSE; CURL *conn; CURLcode conncode; wxString ServerAddressURL; wxString ServerAuth; wxString ServerAddressSSL; wxString ServerAddressNormal; conn = curl_easy_init(); struct curl_slist *connhd = NULL; struct curl_slist *connhd2 = NULL; struct curl_slist *connhd3 = NULL; connhd = curl_slist_append(connhd, "Depth: 0"); connhd = curl_slist_append(connhd, "Prefer: return-minimal"); connhd = curl_slist_append(connhd, "Content-Type: application/xml; charset=utf-8"); connhd2 = curl_slist_append(connhd2, "Depth: 0"); connhd2 = curl_slist_append(connhd2, "Prefer: return-minimal"); connhd2 = curl_slist_append(connhd2, "Content-Type: application/xml; charset=utf-8"); connhd3 = curl_slist_append(connhd3, "Depth: 1"); connhd3 = curl_slist_append(connhd3, "Prefer: return-minimal"); connhd3 = curl_slist_append(connhd3, "Content-Type: application/xml; charset=utf-8"); struct CardDAVCURLPasser { CardDAV *Data; bool HeaderMode = TRUE; } CardDAVHeader, CardDAVFooter; CardDAVHeader.Data = this; CardDAVHeader.HeaderMode = TRUE; CardDAVFooter.Data = this; CardDAVFooter.HeaderMode = FALSE; wxString Data1; wxString Data2; wxString ETag; wxString ETagOriginal; wxString ETagServer; ServerAddressURL = ServerAddress + wxT(":") + wxString::Format(wxT("%i"), ServerPort) + wxT("/"); ServerAddressSSL = wxT("https://") + ServerAddressURL; ServerAddressNormal = wxT("http://") + ServerAddressURL; ServerAuth = ServerUser + wxT(":") + ServerPass; wxString SAURLPrincipals; wxString SAURLPrincipalURL; wxString SAURLAddressURL; if (ServerSSL){ SAURLPrincipals = ServerAddressSSL + wxT("principals/"); SAURLPrincipalURL = ServerAddressSSL; SAURLAddressURL = ServerAddressSSL; } else { SAURLPrincipals = ServerAddressNormal + wxT("principals/"); SAURLPrincipalURL = ServerAddressNormal; SAURLAddressURL = ServerAddressNormal; } wxString FinalPrefix; struct UploadDataStruc UploadData; // Setup the first query finding out where the principal URL is. const char* query = "\n" "\n" " " " \n" " " ""; // Setup the second query finding out where the address book home URL is. const char* query2 = "\n" "\n" " \n" " \n" " \n" ""; // Setup the third query finding out where the default address book URL is. const char* query3 = "\n" "\n" " \n" " \n" " \n" ""; if (ServerSSL){ curl_easy_setopt(conn, CURLOPT_URL, (const char*)SAURLPrincipals.mb_str(wxConvUTF8)); curl_easy_setopt(conn, CURLOPT_NOPROGRESS, 1L); curl_easy_setopt(conn, CURLOPT_HTTPAUTH, CURLAUTH_ANY); curl_easy_setopt(conn, CURLOPT_TIMEOUT, 60); curl_easy_setopt(conn, CURLOPT_FAILONERROR, TRUE); curl_easy_setopt(conn, CURLOPT_USERAGENT, XSDAB_USERAGENT); curl_easy_setopt(conn, CURLOPT_USERPWD, (const char*)ServerAuth.mb_str(wxConvUTF8)); curl_easy_setopt(conn, CURLOPT_WRITEFUNCTION, WritebackFunc); curl_easy_setopt(conn, CURLOPT_WRITEDATA, &PageData); curl_easy_setopt(conn, CURLOPT_WRITEHEADER, &PageHeader); curl_easy_setopt(conn, CURLOPT_NOSIGNAL, 1); curl_easy_setopt(conn, CURLOPT_CUSTOMREQUEST, "PROPFIND"); curl_easy_setopt(conn, CURLOPT_POSTFIELDS, query); curl_easy_setopt(conn, CURLOPT_POSTFIELDSIZE, strlen(query)); curl_easy_setopt(conn, CURLOPT_HTTPHEADER, connhd); if (AllowSelfSign == TRUE){ curl_easy_setopt(conn, CURLOPT_SSL_VERIFYPEER, 0L); curl_easy_setopt(conn, CURLOPT_SSL_VERIFYHOST, 0L); } conncode = (curl_easy_perform(conn)); if (conncode == CURLE_OK){ *ServerResult = TRUE; AuthPassed = TRUE; ValidResponse = TRUE; SSLStatus = TRUE; } else { fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(conncode)); *ServerResult = FALSE; curl_easy_getinfo(conn, CURLINFO_RESPONSE_CODE, &HTTPErrorCode); return wxT(""); } } else { // No SSL. // Do an initial connection (incase of Digest authentication). PageData.Clear(); PageHeader.Clear(); curl_easy_setopt(conn, CURLOPT_URL, (const char*)SAURLPrincipals.mb_str(wxConvUTF8)); curl_easy_setopt(conn, CURLOPT_NOPROGRESS, 0); curl_easy_setopt(conn, CURLOPT_HTTPAUTH, CURLAUTH_ANYSAFE); curl_easy_setopt(conn, CURLOPT_TIMEOUT, 60); curl_easy_setopt(conn, CURLOPT_FAILONERROR, FALSE); curl_easy_setopt(conn, CURLOPT_USERAGENT, XSDAB_USERAGENT); curl_easy_setopt(conn, CURLOPT_USERPWD, (const char*)ServerAuth.mb_str(wxConvUTF8)); curl_easy_setopt(conn, CURLOPT_WRITEFUNCTION, WritebackFunc); curl_easy_setopt(conn, CURLOPT_WRITEDATA, &PageData); curl_easy_setopt(conn, CURLOPT_WRITEHEADER, &PageHeader); curl_easy_setopt(conn, CURLOPT_PROGRESSDATA, this); curl_easy_setopt(conn, CURLOPT_PROGRESSFUNCTION, ProgressFunc); curl_easy_setopt(conn, CURLOPT_NOSIGNAL, 1); curl_easy_setopt(conn, CURLOPT_CUSTOMREQUEST, "PROPFIND"); curl_easy_setopt(conn, CURLOPT_POSTFIELDS, query); curl_easy_setopt(conn, CURLOPT_POSTFIELDSIZE, strlen(query)); curl_easy_setopt(conn, CURLOPT_HTTPHEADER, connhd); conncode = (curl_easy_perform(conn)); // If the ETag is different to the non-matching X-XAB-ETAG and X-XAB-ETAG-ORIG, // then bring up the conflict resolution form. if (EditMode == TRUE){ } if (conncode == CURLE_OK){ } else if (conncode == CURLE_HTTP_RETURNED_ERROR){ curl_easy_getinfo(conn, CURLINFO_RESPONSE_CODE, &HTTPErrorCode); fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(conncode)); fprintf(stderr, "curl_easy_perform() HTTP code was: %i\n", GetHTTPCode()); return wxT(""); } else { fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(conncode)); return wxT(""); } } // Process the XML data from the application. xmlDocPtr xmlCardDAVDoc; xmlCardDAVDoc = xmlReadMemory(PageData.mb_str(wxConvUTF8), (int)PageData.Len(), "noname.xml", NULL, 0); xmlNodePtr nodeLevel1; xmlNodePtr nodeLevel2; xmlNodePtr nodeLevel3; xmlNodePtr nodeLevel4; xmlNodePtr nodeLevel5; xmlNodePtr nodeLevel6; xmlNodePtr nodeLevel7; for (nodeLevel1 = xmlCardDAVDoc->children; nodeLevel1 != NULL; nodeLevel1 = nodeLevel1->next) { for (nodeLevel2 = nodeLevel1->children; nodeLevel2 != NULL; nodeLevel2 = nodeLevel2->next) { for (nodeLevel3 = nodeLevel2->children; nodeLevel3 != NULL; nodeLevel3 = nodeLevel3->next) { for (nodeLevel4 = nodeLevel3->children; nodeLevel4 != NULL; nodeLevel4 = nodeLevel4->next) { for (nodeLevel5 = nodeLevel4->children; nodeLevel5 != NULL; nodeLevel5 = nodeLevel5->next) { for (nodeLevel6 = nodeLevel5->children; nodeLevel6 != NULL; nodeLevel6 = nodeLevel6->next) { if (!xmlStrcmp(nodeLevel6->name, (const xmlChar *)"href") || !xmlStrcmp(nodeLevel6->name, (const xmlChar *)"d:href") || !xmlStrcmp(nodeLevel6->name, (const xmlChar *)"D:href") ){ // Found the part so extract the principal URL address. for (nodeLevel7 = nodeLevel6->children; nodeLevel7 != NULL; nodeLevel7 = nodeLevel7->next) { SAURLPrincipalURL.Append(wxString::FromUTF8((const char*)nodeLevel7->content)); } } } } } } } } xmlFreeDoc(xmlCardDAVDoc); PageData.Clear(); PageHeader.Clear(); // Second: Get the addressbook-home-set curl_easy_reset(conn); if (ServerSSL){ curl_easy_setopt(conn, CURLOPT_URL, (const char*)SAURLPrincipalURL.mb_str(wxConvUTF8)); curl_easy_setopt(conn, CURLOPT_NOPROGRESS, 1L); curl_easy_setopt(conn, CURLOPT_HTTPAUTH, CURLAUTH_ANYSAFE); curl_easy_setopt(conn, CURLOPT_TIMEOUT, 60); curl_easy_setopt(conn, CURLOPT_FAILONERROR, FALSE); curl_easy_setopt(conn, CURLOPT_USERAGENT, XSDAB_USERAGENT); curl_easy_setopt(conn, CURLOPT_USERPWD, (const char*)ServerAuth.mb_str(wxConvUTF8)); curl_easy_setopt(conn, CURLOPT_WRITEFUNCTION, WritebackFunc); curl_easy_setopt(conn, CURLOPT_WRITEDATA, &PageData); curl_easy_setopt(conn, CURLOPT_WRITEHEADER, &PageHeader); curl_easy_setopt(conn, CURLOPT_NOSIGNAL, 1); curl_easy_setopt(conn, CURLOPT_CUSTOMREQUEST, "PROPFIND"); curl_easy_setopt(conn, CURLOPT_POSTFIELDS, query2); curl_easy_setopt(conn, CURLOPT_POSTFIELDSIZE, strlen(query2)); curl_easy_setopt(conn, CURLOPT_HTTPHEADER, connhd2); if (AllowSelfSign == TRUE){ curl_easy_setopt(conn, CURLOPT_SSL_VERIFYPEER, 0L); curl_easy_setopt(conn, CURLOPT_SSL_VERIFYHOST, 0L); } conncode = (curl_easy_perform(conn)); if (conncode == CURLE_OK){ *ServerResult = TRUE; AuthPassed = TRUE; SSLStatus = TRUE; } else { fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(conncode)); *ServerResult = FALSE; ValidResponse = FALSE; curl_easy_getinfo(conn, CURLINFO_RESPONSE_CODE, &HTTPErrorCode); return wxT(""); } } else { // No SSL. curl_easy_setopt(conn, CURLOPT_URL, (const char*)SAURLPrincipalURL.mb_str(wxConvUTF8)); curl_easy_setopt(conn, CURLOPT_NOPROGRESS, 0); curl_easy_setopt(conn, CURLOPT_HTTPAUTH, CURLAUTH_ANYSAFE); curl_easy_setopt(conn, CURLOPT_TIMEOUT, 60); curl_easy_setopt(conn, CURLOPT_FAILONERROR, FALSE); curl_easy_setopt(conn, CURLOPT_USERAGENT, XSDAB_USERAGENT); curl_easy_setopt(conn, CURLOPT_USERPWD, (const char*)ServerAuth.mb_str(wxConvUTF8)); curl_easy_setopt(conn, CURLOPT_WRITEFUNCTION, WritebackFunc); curl_easy_setopt(conn, CURLOPT_WRITEDATA, &PageData); curl_easy_setopt(conn, CURLOPT_WRITEHEADER, &PageHeader); curl_easy_setopt(conn, CURLOPT_PROGRESSDATA, this); curl_easy_setopt(conn, CURLOPT_PROGRESSFUNCTION, ProgressFunc); curl_easy_setopt(conn, CURLOPT_NOSIGNAL, 1); curl_easy_setopt(conn, CURLOPT_CUSTOMREQUEST, "PROPFIND"); curl_easy_setopt(conn, CURLOPT_POSTFIELDS, query2); curl_easy_setopt(conn, CURLOPT_POSTFIELDSIZE, strlen(query2)); curl_easy_setopt(conn, CURLOPT_HTTPHEADER, connhd2); conncode = (curl_easy_perform(conn)); // If the ETag is different to the non-matching X-XAB-ETAG and X-XAB-ETAG-ORIG, // then bring up the conflict resolution form. if (EditMode == TRUE){ } if (conncode == CURLE_OK){ } else if (conncode == CURLE_HTTP_RETURNED_ERROR){ curl_easy_getinfo(conn, CURLINFO_RESPONSE_CODE, &HTTPErrorCode); fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(conncode)); fprintf(stderr, "curl_easy_perform() HTTP code was: %i\n", GetHTTPCode()); ValidResponse = FALSE; return wxT(""); } else { fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(conncode)); ValidResponse = FALSE; return wxT(""); } } xmlCardDAVDoc = xmlReadMemory(PageData.mb_str(wxConvUTF8), (int)PageData.Len(), "noname.xml", NULL, 0); for (nodeLevel1 = xmlCardDAVDoc->children; nodeLevel1 != NULL; nodeLevel1 = nodeLevel1->next) { for (nodeLevel2 = nodeLevel1->children; nodeLevel2 != NULL; nodeLevel2 = nodeLevel2->next) { for (nodeLevel3 = nodeLevel2->children; nodeLevel3 != NULL; nodeLevel3 = nodeLevel3->next) { for (nodeLevel4 = nodeLevel3->children; nodeLevel4 != NULL; nodeLevel4 = nodeLevel4->next) { for (nodeLevel5 = nodeLevel4->children; nodeLevel5 != NULL; nodeLevel5 = nodeLevel5->next) { for (nodeLevel6 = nodeLevel5->children; nodeLevel6 != NULL; nodeLevel6 = nodeLevel6->next) { if (!xmlStrcmp(nodeLevel6->name, (const xmlChar *)"href") || !xmlStrcmp(nodeLevel6->name, (const xmlChar *)"d:href") || !xmlStrcmp(nodeLevel6->name, (const xmlChar *)"D:href") ){ // Found the part so extract the principal URL address. for (nodeLevel7 = nodeLevel6->children; nodeLevel7 != NULL; nodeLevel7 = nodeLevel7->next) { SAURLAddressURL.Append(wxString::FromUTF8((const char*)nodeLevel7->content)); } } } } } } } } xmlFreeDoc(xmlCardDAVDoc); PageData.Clear(); PageHeader.Clear(); // Finally: Get the default-addressbook-URL from the addressbook-home-set address. curl_easy_reset(conn); if (ServerSSL){ curl_easy_setopt(conn, CURLOPT_URL, (const char*)SAURLAddressURL.mb_str(wxConvUTF8)); curl_easy_setopt(conn, CURLOPT_NOPROGRESS, 1L); curl_easy_setopt(conn, CURLOPT_HTTPAUTH, CURLAUTH_ANYSAFE); curl_easy_setopt(conn, CURLOPT_TIMEOUT, 60); curl_easy_setopt(conn, CURLOPT_FAILONERROR, FALSE); curl_easy_setopt(conn, CURLOPT_USERAGENT, XSDAB_USERAGENT); curl_easy_setopt(conn, CURLOPT_USERPWD, (const char*)ServerAuth.mb_str(wxConvUTF8)); curl_easy_setopt(conn, CURLOPT_WRITEFUNCTION, WritebackFunc); curl_easy_setopt(conn, CURLOPT_WRITEDATA, &PageData); curl_easy_setopt(conn, CURLOPT_WRITEHEADER, &PageHeader); curl_easy_setopt(conn, CURLOPT_NOSIGNAL, 1); curl_easy_setopt(conn, CURLOPT_CUSTOMREQUEST, "PROPFIND"); curl_easy_setopt(conn, CURLOPT_POSTFIELDS, query3); curl_easy_setopt(conn, CURLOPT_POSTFIELDSIZE, strlen(query3)); curl_easy_setopt(conn, CURLOPT_HTTPHEADER, connhd3); if (AllowSelfSign == TRUE){ curl_easy_setopt(conn, CURLOPT_SSL_VERIFYPEER, 0L); curl_easy_setopt(conn, CURLOPT_SSL_VERIFYHOST, 0L); } conncode = (curl_easy_perform(conn)); if (conncode == CURLE_OK){ *ServerResult = TRUE; AuthPassed = TRUE; SSLStatus = TRUE; } else { fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(conncode)); *ServerResult = FALSE; ValidResponse = FALSE; curl_easy_getinfo(conn, CURLINFO_RESPONSE_CODE, &HTTPErrorCode); return wxT(""); } } else { // No SSL. curl_easy_setopt(conn, CURLOPT_URL, (const char*)SAURLAddressURL.mb_str(wxConvUTF8)); curl_easy_setopt(conn, CURLOPT_NOPROGRESS, 0); curl_easy_setopt(conn, CURLOPT_HTTPAUTH, CURLAUTH_ANYSAFE); curl_easy_setopt(conn, CURLOPT_TIMEOUT, 60); curl_easy_setopt(conn, CURLOPT_FAILONERROR, FALSE); curl_easy_setopt(conn, CURLOPT_USERAGENT, XSDAB_USERAGENT); curl_easy_setopt(conn, CURLOPT_USERPWD, (const char*)ServerAuth.mb_str(wxConvUTF8)); curl_easy_setopt(conn, CURLOPT_WRITEFUNCTION, WritebackFunc); curl_easy_setopt(conn, CURLOPT_WRITEDATA, &PageData); curl_easy_setopt(conn, CURLOPT_WRITEHEADER, &PageHeader); curl_easy_setopt(conn, CURLOPT_PROGRESSDATA, this); curl_easy_setopt(conn, CURLOPT_PROGRESSFUNCTION, ProgressFunc); curl_easy_setopt(conn, CURLOPT_NOSIGNAL, 1); curl_easy_setopt(conn, CURLOPT_CUSTOMREQUEST, "PROPFIND"); curl_easy_setopt(conn, CURLOPT_POSTFIELDS, query3); curl_easy_setopt(conn, CURLOPT_POSTFIELDSIZE, strlen(query3)); curl_easy_setopt(conn, CURLOPT_HTTPHEADER, connhd3); conncode = (curl_easy_perform(conn)); // If the ETag is different to the non-matching X-XAB-ETAG and X-XAB-ETAG-ORIG, // then bring up the conflict resolution form. if (EditMode == TRUE){ } if (conncode == CURLE_OK){ } else if (conncode == CURLE_HTTP_RETURNED_ERROR){ curl_easy_getinfo(conn, CURLINFO_RESPONSE_CODE, &HTTPErrorCode); fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(conncode)); fprintf(stderr, "curl_easy_perform() HTTP code was: %i\n", GetHTTPCode()); ValidResponse = FALSE; return wxT(""); } else { fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(conncode)); ValidResponse = FALSE; return wxT(""); } } xmlCardDAVDoc = xmlReadMemory(PageData.mb_str(wxConvUTF8), (int)PageData.Len(), "noname.xml", NULL, 0); for (nodeLevel1 = xmlCardDAVDoc->children; nodeLevel1 != NULL; nodeLevel1 = nodeLevel1->next) { for (nodeLevel2 = nodeLevel1->children; nodeLevel2 != NULL; nodeLevel2 = nodeLevel2->next) { for (nodeLevel3 = nodeLevel2->children; nodeLevel3 != NULL; nodeLevel3 = nodeLevel3->next) { for (nodeLevel4 = nodeLevel3->children; nodeLevel4 != NULL; nodeLevel4 = nodeLevel4->next) { for (nodeLevel5 = nodeLevel4->children; nodeLevel5 != NULL; nodeLevel5 = nodeLevel5->next) { for (nodeLevel6 = nodeLevel5->children; nodeLevel6 != NULL; nodeLevel6 = nodeLevel6->next) { if (!xmlStrcmp(nodeLevel6->name, (const xmlChar *)"href") || !xmlStrcmp(nodeLevel6->name, (const xmlChar *)"d:href") || !xmlStrcmp(nodeLevel6->name, (const xmlChar *)"D:href") ){ // Found the part so extract the principal URL address. for (nodeLevel7 = nodeLevel6->children; nodeLevel7 != NULL; nodeLevel7 = nodeLevel7->next) { FinalPrefix = wxString::FromUTF8((const char*)nodeLevel7->content); } } } } } } } } xmlFreeDoc(xmlCardDAVDoc); PageData.Clear(); PageHeader.Clear(); return FinalPrefix; }