1 // CalDAV.cpp - CalDAV Connection Object.
3 // (c) 2016-2017 Xestia Software Development.
5 // This file is part of Xestia Calendar.
7 // Xestia Calendar 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 Calendar 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 Calendar. If not, see <http://www.gnu.org/licenses/>
23 size_t CalDAVReceive(char *receivedBuffer, size_t size, size_t newMemoryBytes, string *stringPointer)
26 stringPointer->append(receivedBuffer, newMemoryBytes);
28 return size * newMemoryBytes;
32 size_t CalDAVSend(char *sendBuffer, size_t size, size_t newMemoryBytes, void *dataStruct){
34 struct CalDAVSendData *uploadPtr = (struct CalDAVSendData *)dataStruct;
36 if (uploadPtr->sizeleft){
38 uploadPtr->sizeleft--;
41 charSend = (*uploadPtr->readptr)[uploadPtr->seek];
43 *sendBuffer = charSend;
57 // Setup the objects within the CalDAV connection
60 connectionHandle = curl_easy_init();
66 // Destory the objects within the CalDAV connection
69 curl_easy_cleanup(connectionHandle);
70 connectionHandle = nullptr;
74 void CalDAV::SetupConnectionData(CalDAVConnectionData *connData){
76 // Check if ConnData is a nullptr, return if it is.
78 if (connData == nullptr){
82 // Set the connection settings to the values from ConnData.
84 connectionData = (*connData);
88 CalDAVStatus CalDAV::GetConnectionData(){
90 // Get the current connection settings for the CalDAV
91 // connection object and return a CalDAVStatus object.
93 CalDAVStatus connectionStatus;
95 connectionStatus.hostname = connectionData.hostname;
96 connectionStatus.port = connectionData.port;
97 connectionStatus.username = connectionData.username;
98 connectionStatus.prefix = connectionData.prefix;
99 connectionStatus.useSSL = connectionData.useSSL;
100 connectionStatus.timeout = connectionData.timeout;
102 return connectionStatus;
106 CalDAVServerResult CalDAV::Connect(bool doAuthentication){
108 connectionData.useSSL ? SetupDefaultParametersSSL(doAuthentication) : SetupDefaultParametersNonSSL(doAuthentication);
111 CalDAVServerResult serverResult;
113 string serverAddress = "";
114 string serverUserPass = "";
116 // Setup the server address.
118 serverAddress = BuildServerAddress(&connectionData, "/principals/");
120 // Setup the server password.
122 serverUserPass += connectionData.username;
123 serverUserPass += ":";
124 serverUserPass += connectionData.password;
126 curl_easy_setopt(connectionHandle, CURLOPT_URL, serverAddress.c_str());
127 curl_easy_setopt(connectionHandle, CURLOPT_USERPWD, serverUserPass.c_str());
128 curl_easy_setopt(connectionHandle, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST);
129 curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
130 curl_easy_setopt(connectionHandle, CURLOPT_FAILONERROR, 1L);
131 curl_easy_setopt(connectionHandle, CURLOPT_TIMEOUT, connectionData.timeout);
132 curl_easy_setopt(connectionHandle, CURLOPT_WRITEFUNCTION, CalDAVReceive);
133 curl_easy_setopt(connectionHandle, CURLOPT_WRITEDATA, &serverData);
134 curl_easy_setopt(connectionHandle, CURLOPT_WRITEHEADER, &serverHeader);
136 // Connect to the CalDAV server.
138 serverResult.code = curl_easy_perform(connectionHandle);
140 // Process the result received from the server.
142 // Get the HTTP code.
144 curl_easy_getinfo(connectionHandle, CURLINFO_RESPONSE_CODE, &serverResult.httpCode);
146 switch(serverResult.code){
149 case CURLE_HTTP_RETURNED_ERROR:
150 if (connectionData.useSSL)
152 sslStatus = connectionData.useSSL;
153 sslVerified = COSSL_VERIFIED;
155 serverResult.result = CALDAVQUERYRESULT_OK;
156 if (serverResult.httpCode == 401)
161 case CURLE_SSL_CACERT:
162 case CURLE_SSL_CONNECT_ERROR:
163 if (connectionData.useSSL)
165 sslStatus = connectionData.useSSL;
166 sslVerified = COSSL_UNABLETOVERIFY;
168 serverResult.result = CALDAVQUERYRESULT_SSLFAILURE;
172 serverResult.result = CALDAVQUERYRESULT_SERVERERROR;
177 if (serverResult.httpCode >= 200 && serverResult.httpCode <= 299)
179 validResponse = true;
186 CalDAVServerResult CalDAV::GetServerResult(){
188 return connectionServerResult;
192 CalDAVServerSupport CalDAV::GetServerSupport(){
194 CalDAVServerSupport serverStatus;
196 // Setup the server connection.
198 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, "OPTIONS");
200 CURLcode serverResult = curl_easy_perform(connectionHandle);
204 if (serverResult == CURLE_OK){
205 connectionServerResult.result = CALDAVQUERYRESULT_OK;
207 connectionServerResult.result = CALDAVQUERYRESULT_SERVERERROR;
209 connectionServerResult.code = serverResult;
210 curl_easy_getinfo(connectionHandle, CURLINFO_RESPONSE_CODE, &connectionServerResult.httpCode);
212 if (serverResult != CURLE_OK){
216 // Check that the server header has data in,
217 // otherwise return an "empty" CalDAVServerSupport.
219 if (serverHeader.size() == 0){
223 // Process each line looking for the first DAV header
226 bool newlineMode = true;
230 for (int charSeek = 0; charSeek < serverHeader.size(); charSeek++){
232 if (newlineMode == true){
234 // Check if we have reached the end of the string.
236 if (charSeek >= serverHeader.size()){
242 // Check the first four letters to make sure
245 string davHeaderCheck = "";
248 davHeaderCheck = serverHeader.substr(charSeek, 4);
251 catch (out_of_range &oor){
255 if (davHeaderCheck == "DAV:"){
259 for (; charSeek < serverHeader.size(); charSeek++){
261 if (serverHeader[charSeek] == '\n'){
267 davLine.push_back(serverHeader[charSeek]);
279 if (serverHeader[charSeek] == '\n'){
287 // Process the DAV line.
289 vector<string> davLineData;
290 string davSegmentString;
292 for (int charSeek = 0; charSeek < davLine.size(); charSeek++){
294 if (davLine[charSeek] == ' '){
298 if (davLine[charSeek] == ','){
300 davLineData.push_back(davSegmentString);
301 davSegmentString.clear();
306 davSegmentString += davLine[charSeek];
310 // Process the DAV values and set each value
311 // to true as required.
313 for (int davItemSeek = 0;
314 davItemSeek < davLineData.size();
317 if (davLineData.at(davItemSeek) == "calendar-access"){
319 serverStatus.basicSupport = true;
325 // Reset the connection status.
327 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, NULL);
333 string CalDAV::GetUserPrincipal(){
335 string currentUserPrincipal = "";
336 string userPrincipalRequest = "";
337 CalDAVSendData userPrincipalSendData;
339 userPrincipalRequest = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
340 "<d:propfind xmlns:d=\"DAV:\">\n"
342 " <d:current-user-principal />\n"
346 userPrincipalSendData.readptr = &userPrincipalRequest;
347 userPrincipalSendData.sizeleft = userPrincipalRequest.size();
351 struct curl_slist *userPrincipalRequestHeader = NULL;
353 userPrincipalRequestHeader = curl_slist_append(userPrincipalRequestHeader, "Depth: 0");
354 userPrincipalRequestHeader = curl_slist_append(userPrincipalRequestHeader, "Prefer: return-minimal");
355 userPrincipalRequestHeader = curl_slist_append(userPrincipalRequestHeader, "Content-Type: application/xml; charset=utf-8");
357 curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, userPrincipalRequestHeader);
359 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, "PROPFIND");
360 curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 1L);
361 curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
362 curl_easy_setopt(connectionHandle, CURLOPT_READDATA, &userPrincipalSendData);
363 curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, CalDAVSend);
368 serverHeader.clear();
370 CURLcode serverResult = curl_easy_perform(connectionHandle);
374 if (serverResult == CURLE_OK){
375 connectionServerResult.result = CALDAVQUERYRESULT_OK;
377 connectionServerResult.result = CALDAVQUERYRESULT_SERVERERROR;
379 connectionServerResult.code = serverResult;
380 curl_easy_getinfo(connectionHandle, CURLINFO_RESPONSE_CODE, &connectionServerResult.httpCode);
382 if (serverResult != CURLE_OK){
384 return currentUserPrincipal;
388 // Process the User Principal from the ServerData.
390 currentUserPrincipal = ProcessXMLUserPrincipal();
392 // Reset the changed settings.
394 curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 0L);
395 curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
396 curl_easy_setopt(connectionHandle, CURLOPT_READDATA, NULL);
397 curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, NULL);
399 return currentUserPrincipal;
403 string CalDAV::GetCalendarHome(string userPrincipalURI){
405 string calendarHomeURI = "";
407 // Build the Calendar Home URL address.
409 string calendarHomeURL = BuildServerAddress(&connectionData, userPrincipalURI);
411 // Setup the header request.
413 CalDAVSendData calendarHomeSendData;
415 string calendarHomeRequest = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
416 "<d:propfind xmlns:d=\"DAV:\" xmlns:c=\"urn:ietf:params:xml:ns:caldav\">\n"
418 " <c:calendar-home-set />\n"
422 calendarHomeSendData.readptr = &calendarHomeRequest;
423 calendarHomeSendData.sizeleft = calendarHomeRequest.size();
427 struct curl_slist *calendarRequestHeader = NULL;
429 calendarRequestHeader = curl_slist_append(calendarRequestHeader, "Depth: 0");
430 calendarRequestHeader = curl_slist_append(calendarRequestHeader, "Prefer: return-minimal");
431 calendarRequestHeader = curl_slist_append(calendarRequestHeader, "Content-Type: application/xml; charset=utf-8");
433 curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, calendarRequestHeader);
434 curl_easy_setopt(connectionHandle, CURLOPT_URL, calendarHomeURL.c_str());
435 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, "PROPFIND");
436 curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 1L);
437 curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
438 curl_easy_setopt(connectionHandle, CURLOPT_READDATA, &calendarHomeSendData);
439 curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, CalDAVSend);
444 serverHeader.clear();
446 CURLcode serverResult = curl_easy_perform(connectionHandle);
450 if (serverResult == CURLE_OK){
451 connectionServerResult.result = CALDAVQUERYRESULT_OK;
453 connectionServerResult.result = CALDAVQUERYRESULT_SERVERERROR;
455 connectionServerResult.code = serverResult;
456 curl_easy_getinfo(connectionHandle, CURLINFO_RESPONSE_CODE, &connectionServerResult.httpCode);
458 if (serverResult != CURLE_OK){
460 return calendarHomeURI;
464 // Process the User Principal from the ServerData.
466 calendarHomeURI = ProcessXMLCalendarHome();
468 // Reset the changed settings.
470 string originalServerAddress = BuildServerAddress(&connectionData, "/principals/");
471 curl_easy_setopt(connectionHandle, CURLOPT_URL, originalServerAddress.c_str());
473 curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 0L);
474 curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
475 curl_easy_setopt(connectionHandle, CURLOPT_READDATA, NULL);
476 curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, NULL);
477 curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, NULL);
479 return calendarHomeURI;
483 CalDAVCalendarList CalDAV::GetCalendars(){
485 CalDAVCalendarList serverList;
486 CalDAVSendData calendarListSendData;
488 // Build the server address.
490 string userPrincipalURI = "";
491 userPrincipalURI = GetUserPrincipal();
493 if (userPrincipalURI.size() == 0){
499 string calendarHomeURI = "";
500 calendarHomeURI = GetCalendarHome(userPrincipalURI);
502 string calendarListURLAddress = BuildServerAddress(&connectionData, calendarHomeURI);
504 string calendarListRequest = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
505 "<d:propfind xmlns:d=\"DAV:\" xmlns:cs=\"http://calendarserver.org/ns/\""
506 " xmlns:c=\"urn:ietf:params:xml:ns:caldav\" xmlns:x0=\"http://apple.com/ns/ical/\">\n"
508 " <d:resourcetype />\n"
509 " <d:displayname />\n"
510 " <d:sync-token />\n"
511 " <x0:calendar-color />\n"
512 " <x0:calendar-order />\n"
514 " <c:supported-calendar-component-set />\n"
515 " <c:calendar-description />\n"
519 calendarListSendData.readptr = &calendarListRequest;
520 calendarListSendData.sizeleft = calendarListRequest.size();
524 struct curl_slist *calendarListRequestHeader = NULL;
526 calendarListRequestHeader = curl_slist_append(calendarListRequestHeader, "Depth: 1");
527 calendarListRequestHeader = curl_slist_append(calendarListRequestHeader, "Prefer: return-minimal");
528 calendarListRequestHeader = curl_slist_append(calendarListRequestHeader, "Content-Type: application/xml; charset=utf-8");
530 curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, calendarListRequestHeader);
531 curl_easy_setopt(connectionHandle, CURLOPT_URL, calendarListURLAddress.c_str());
532 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, "PROPFIND");
533 curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 1L);
534 curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
535 curl_easy_setopt(connectionHandle, CURLOPT_READDATA, &calendarListSendData);
536 curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, CalDAVSend);
541 serverHeader.clear();
543 CURLcode serverResult = curl_easy_perform(connectionHandle);
545 //ServerList = ProcessXMLCalendarList();
547 if (serverResult == CURLE_OK){
548 connectionServerResult.result = CALDAVQUERYRESULT_OK;
550 connectionServerResult.result = CALDAVQUERYRESULT_SERVERERROR;
552 connectionServerResult.code = serverResult;
553 curl_easy_getinfo(connectionHandle, CURLINFO_RESPONSE_CODE, &connectionServerResult.httpCode);
555 if (serverResult != CURLE_OK){
561 // Process the received XML data into a list of calendars
564 serverList = ProcessXMLCalendarList();
566 // Restore the original settings.
568 string originalServerAddress = BuildServerAddress(&connectionData, "/principals/");
570 curl_easy_setopt(connectionHandle, CURLOPT_URL, originalServerAddress.c_str());
571 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, NULL);
572 curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 0L);
573 curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
574 curl_easy_setopt(connectionHandle, CURLOPT_READDATA, NULL);
575 curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, NULL);
581 CalDAVEntryList CalDAV::GetEntryList(string *calendarHREF){
583 CalDAVEntryList entryList;
584 CalDAVSendData entryListSendData;
586 if (calendarHREF->size() == 0){
592 string entryListURLAddress = BuildServerAddress(&connectionData, *calendarHREF);
594 string entryListRequest = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
596 /*if (CalendarTag == nullptr){*/
598 entryListRequest += "<c:calendar-query xmlns:d=\"DAV:\" xmlns:cs=\"http://calendarserver.org/ns/\""
599 " xmlns:c=\"urn:ietf:params:xml:ns:caldav\" xmlns:x0=\"http://apple.com/ns/ical/\">\n"
602 " <c:calendar-data />\n"
605 " <c:comp-filter name=\"VCALENDAR\" />\n"
607 "</c:calendar-query>";
611 EntryListRequest += "<d:sync-collection xmlns:d=\"DAV:\" xmlns:cs=\"http://calendarserver.org/ns/\""
612 " xmlns:c=\"urn:ietf:params:xml:ns:caldav\" xmlns:x0=\"http://apple.com/ns/ical/\">\n"
614 EntryListRequest += *CalendarTag;
615 EntryListRequest += "</d:sync-token>\n"
616 " <d:sync-level>1</d:sync-level>\n"
619 " <c:calendar-data />\n"
621 "</d:sync-collection>";
625 entryListSendData.readptr = &entryListRequest;
626 entryListSendData.sizeleft = entryListRequest.size();
628 struct curl_slist *entryListRequestHeader = NULL;
630 entryListRequestHeader = curl_slist_append(entryListRequestHeader, "Content-Type: application/xml; charset=utf-8");
632 /*if (CalendarTag != nullptr){
634 EntryListRequestHeader = curl_slist_append(EntryListRequestHeader, "Content-Type: application/xml; charset=utf-8");
635 EntryListRequestHeader = curl_slist_append(EntryListRequestHeader, "Content-Type: application/xml; charset=utf-8");
639 curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, entryListRequestHeader);
640 curl_easy_setopt(connectionHandle, CURLOPT_URL, entryListURLAddress.c_str());
641 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, "REPORT");
642 curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 1L);
643 curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
644 curl_easy_setopt(connectionHandle, CURLOPT_READDATA, &entryListSendData);
645 curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, CalDAVSend);
650 serverHeader.clear();
652 CURLcode serverResult = curl_easy_perform(connectionHandle);
654 //ServerList = ProcessXMLCalendarList();
656 if (serverResult == CURLE_OK){
657 connectionServerResult.result = CALDAVQUERYRESULT_OK;
659 connectionServerResult.result = CALDAVQUERYRESULT_SERVERERROR;
661 connectionServerResult.code = serverResult;
662 curl_easy_getinfo(connectionHandle, CURLINFO_RESPONSE_CODE, &connectionServerResult.httpCode);
664 if (serverResult != CURLE_OK){
670 // Process the received XML data into a list of calendars
673 entryList = ProcessXMLEntryList();
675 // Restore the original settings.
677 string originalServerAddress = BuildServerAddress(&connectionData, "/principals/");
679 curl_easy_setopt(connectionHandle, CURLOPT_URL, originalServerAddress.c_str());
680 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, NULL);
681 curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 0L);
682 curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
683 curl_easy_setopt(connectionHandle, CURLOPT_READDATA, NULL);
684 curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, NULL);
690 CalDAVEntryList CalDAV::GetEntryList(string *calendarHREF, string *calendarTag){
692 CalDAVEntryList entryList;
693 CalDAVSendData entryListSendData;
695 if (calendarHREF->size() == 0){
701 string entryListURLAddress = BuildServerAddress(&connectionData, *calendarHREF);
703 // First query: Get the list of contacts that need to be updated.
705 string entryListRequest = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
707 entryListRequest += "<d:sync-collection xmlns:d=\"DAV:\" xmlns:cs=\"http://calendarserver.org/ns/\""
708 " xmlns:c=\"urn:ietf:params:xml:ns:caldav\" xmlns:x0=\"http://apple.com/ns/ical/\">\n"
711 if (calendarTag != nullptr){
713 entryListRequest += *calendarTag;
717 entryListRequest += "";
721 entryListRequest += "</d:sync-token>\n"
722 " <d:sync-level>1</d:sync-level>\n"
726 "</d:sync-collection>";
728 entryListSendData.readptr = &entryListRequest;
729 entryListSendData.sizeleft = entryListRequest.size();
731 struct curl_slist *entryListRequestHeader = NULL;
733 entryListRequestHeader = curl_slist_append(entryListRequestHeader, "Content-Type: application/xml; charset=utf-8");
735 curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, entryListRequestHeader);
736 curl_easy_setopt(connectionHandle, CURLOPT_URL, entryListURLAddress.c_str());
737 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, "REPORT");
738 curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 1L);
739 curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
740 curl_easy_setopt(connectionHandle, CURLOPT_READDATA, &entryListSendData);
741 curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, CalDAVSend);
746 serverHeader.clear();
748 CURLcode serverResult = curl_easy_perform(connectionHandle);
750 if (serverResult == CURLE_OK){
751 connectionServerResult.result = CALDAVQUERYRESULT_OK;
753 connectionServerResult.result = CALDAVQUERYRESULT_SERVERERROR;
755 connectionServerResult.code = serverResult;
756 curl_easy_getinfo(connectionHandle, CURLINFO_RESPONSE_CODE, &connectionServerResult.httpCode);
758 if (serverResult != CURLE_OK){
764 entryList = ProcessXMLSyncTokenList();
766 // Check the last entry matches the HREF and if it
767 // does then delete it.
769 if (entryList.href.size() > 0) {
771 if (entryList.href.rbegin()->second == *calendarHREF){
773 entryList.href.erase((entryList.href.size() - 1));
774 entryList.tag.erase((entryList.href.size() - 1));
775 entryList.data.erase((entryList.href.size() - 1));
781 // Build the list into a new list for getting the new
782 // calendar data with.
784 entryListRequest.clear();
786 entryListRequest = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
788 entryListRequest += "<c:calendar-multiget xmlns:d=\"DAV:\" "
789 " xmlns:c=\"urn:ietf:params:xml:ns:caldav\">\n"
792 " <c:calendar-data />\n"
795 for (std::map<int,string>::iterator hrefIter = entryList.href.begin();
796 hrefIter != entryList.href.end(); hrefIter++){
798 string entryListHREFString = hrefIter->second;
800 entryListRequest += " <d:href>";
801 entryListRequest += entryListHREFString;
802 entryListRequest += "</d:href>\n";
806 entryListRequest += "</c:calendar-multiget>";
808 CalDAVSendData updatedEntryListSendData;
810 updatedEntryListSendData.readptr = &entryListRequest;
811 updatedEntryListSendData.sizeleft = entryListRequest.size();
813 curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, entryListRequestHeader);
814 curl_easy_setopt(connectionHandle, CURLOPT_URL, entryListURLAddress.c_str());
815 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, "REPORT");
816 curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 1L);
817 curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
818 curl_easy_setopt(connectionHandle, CURLOPT_READDATA, &updatedEntryListSendData);
819 curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, CalDAVSend);
821 // Get the updated calendar data.
824 serverHeader.clear();
825 entryList.href.clear();
826 entryList.tag.clear();
827 entryList.data.clear();
829 serverResult = curl_easy_perform(connectionHandle);
831 // Check the last entry matches the HREF and if it
832 // does then delete it.
834 if (serverResult == CURLE_OK){
835 connectionServerResult.result = CALDAVQUERYRESULT_OK;
837 connectionServerResult.result = CALDAVQUERYRESULT_SERVERERROR;
839 connectionServerResult.code = serverResult;
840 curl_easy_getinfo(connectionHandle, CURLINFO_RESPONSE_CODE, &connectionServerResult.httpCode);
842 if (serverResult != CURLE_OK){
848 entryList = ProcessXMLEntryList();
850 // Second query: Get the list of contact data for the contacts that have
853 // Restore the original settings.
855 string originalServerAddress = BuildServerAddress(&connectionData, "/principals/");
857 curl_easy_setopt(connectionHandle, CURLOPT_URL, originalServerAddress.c_str());
858 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, NULL);
859 curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 0L);
860 curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
861 curl_easy_setopt(connectionHandle, CURLOPT_READDATA, NULL);
862 curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, NULL);
868 CalDAVServerResult CalDAV::AddCalendar(string calendarName){
870 CalDAVServerResult serverResult;
872 AddCalendar(&calendarName, nullptr);
878 CalDAVServerResult CalDAV::AddCalendar(string *calendarName, string *calendarShortName){
880 CalDAVServerResult serverResult;
881 CalDAVSendData calendarAddSendData;
883 // Build the server address.
885 string userPrincipalURI = "";
886 userPrincipalURI = GetUserPrincipal();
888 if (userPrincipalURI.size() == 0){
894 string calendarHomeURI = "";
895 calendarHomeURI = GetCalendarHome(userPrincipalURI);
897 // Generate the UUID.
899 string UUIDValue = "";
901 if (calendarShortName == nullptr){
903 UUIDValue = GenerateUUID();
904 UUIDValue.erase(UUIDValue.end()-1);
908 UUIDValue = *calendarShortName;
912 string calendarHomeURL = calendarHomeURI;
913 calendarHomeURL.append(UUIDValue);
914 calendarHomeURL.append("/");
916 // Build the calendar list address.
918 string calendarListURLAddress = BuildServerAddress(&connectionData, calendarHomeURL);
920 string calendarAddRequest = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
921 "<c:mkcalendar xmlns:d=\"DAV:\" xmlns:c=\"urn:ietf:params:xml:ns:caldav\">\n"
925 calendarAddRequest += *calendarName;
926 calendarAddRequest += "</d:displayname>\n"
927 " <c:supported-calendar-component-set>\n"
928 " <c:comp name=\"VTODO\"/>\n"
929 " <c:comp name=\"VEVENT\"/>\n"
930 " </c:supported-calendar-component-set>\n"
935 calendarAddSendData.readptr = &calendarAddRequest;
936 calendarAddSendData.sizeleft = calendarAddRequest.size();
940 struct curl_slist *calendarRequestHeader = NULL;
942 //curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, CalendarRequestHeader);
943 curl_easy_setopt(connectionHandle, CURLOPT_URL, calendarListURLAddress.c_str());
944 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, "MKCALENDAR");
945 curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 1L);
946 curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
947 curl_easy_setopt(connectionHandle, CURLOPT_READDATA, &calendarAddSendData);
948 curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, CalDAVSend);
953 serverHeader.clear();
955 CURLcode serverConnectionResult = curl_easy_perform(connectionHandle);
957 if (serverConnectionResult == CURLE_OK){
958 serverResult.result = CALDAVQUERYRESULT_OK;
960 serverResult.result = CALDAVQUERYRESULT_SERVERERROR;
962 serverResult.code = serverConnectionResult;
963 curl_easy_getinfo(connectionHandle, CURLINFO_RESPONSE_CODE, &serverResult.httpCode);
965 // Restore the original settings.
967 string originalServerAddress = BuildServerAddress(&connectionData, "/principals/");
968 curl_easy_setopt(connectionHandle, CURLOPT_URL, originalServerAddress.c_str());
969 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, NULL);
970 curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 0L);
971 curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
972 curl_easy_setopt(connectionHandle, CURLOPT_READDATA, NULL);
973 curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, NULL);
979 CalDAVServerResult CalDAV::EditCalendarProcess(string *calendarHREF,
980 string *calendarName,
981 Colour *calendarColour,
982 string *calendarDescription,
985 CalDAVServerResult serverResult;
986 CalDAVSendData calendarEditSendData;
988 // Build the server address.
990 string userPrincipalURI = "";
991 userPrincipalURI = GetUserPrincipal();
993 if (userPrincipalURI.size() == 0){
999 string calendarHomeURI = "";
1000 calendarHomeURI = GetCalendarHome(userPrincipalURI);
1002 // Generate the UUID.
1004 string UUIDValue = GenerateUUID();
1005 UUIDValue.erase(UUIDValue.end()-1);
1007 string calendarHomeURL = calendarHomeURI;
1008 calendarHomeURL.append(UUIDValue);
1009 calendarHomeURL.append("/");
1011 // Build the calendar list address.
1013 string calendarEditURLAddress = BuildServerAddress(&connectionData, (*calendarHREF));
1015 string calendarEditRequest = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
1016 "<d:propertyupdate xmlns:d=\"DAV:\" xmlns:c=\"urn:ietf:params:xml:ns:caldav\"\n"
1017 " xmlns:x0=\"http://apple.com/ns/ical/\">\n"
1021 // Update the calendar name.
1023 if (calendarName != nullptr){
1025 calendarEditRequest += "<d:displayname>";
1026 calendarEditRequest += (*calendarName);
1027 calendarEditRequest += "</d:displayname>\n";
1031 // Update the calendar colour.
1033 if (calendarColour != nullptr){
1035 calendarEditRequest += "<x0:calendar-color>";
1036 calendarEditRequest += (*calendarColour);
1037 calendarEditRequest += "</x0:calendar-color>\n";
1041 // Update the calendar description.
1043 if (calendarDescription != nullptr){
1045 calendarEditRequest += "<c:calendar-description>";
1046 calendarEditRequest += (*calendarDescription);
1047 calendarEditRequest += "</c:calendar-description>\n";
1051 // Update the calendar order.
1053 if (calendarOrder != nullptr){
1055 calendarEditRequest += "<x0:calendar-order>";
1056 calendarEditRequest += to_string((*calendarOrder));
1057 calendarEditRequest += "</x0:calendar-order>\n";
1061 calendarEditRequest += " </d:prop>\n"
1063 "</d:propertyupdate>";
1065 calendarEditSendData.readptr = &calendarEditRequest;
1066 calendarEditSendData.sizeleft = calendarEditRequest.size();
1068 // Setup the header.
1070 struct curl_slist *calendarRequestHeader = NULL;
1072 //curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, CalendarRequestHeader);
1073 curl_easy_setopt(connectionHandle, CURLOPT_URL, calendarEditURLAddress.c_str());
1074 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, "PROPPATCH");
1075 curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 1L);
1076 curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
1077 curl_easy_setopt(connectionHandle, CURLOPT_READDATA, &calendarEditSendData);
1078 curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, CalDAVSend);
1080 // Process the data.
1083 serverHeader.clear();
1085 CURLcode serverConnectionResult = curl_easy_perform(connectionHandle);
1087 if (serverConnectionResult == CURLE_OK){
1088 serverResult.result = CALDAVQUERYRESULT_OK;
1090 serverResult.result = CALDAVQUERYRESULT_SERVERERROR;
1092 serverResult.code = serverConnectionResult;
1093 curl_easy_getinfo(connectionHandle, CURLINFO_RESPONSE_CODE, &serverResult.httpCode);
1095 // Restore the original settings.
1097 string originalServerAddress = BuildServerAddress(&connectionData, "/principals/");
1098 curl_easy_setopt(connectionHandle, CURLOPT_URL, originalServerAddress.c_str());
1099 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, NULL);
1100 curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 0L);
1101 curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
1102 curl_easy_setopt(connectionHandle, CURLOPT_READDATA, NULL);
1103 curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, NULL);
1105 return serverResult;
1109 CalDAVServerResult CalDAV::EditCalendar(string *calendarHREF,
1110 string *calendarName,
1111 Colour *calendarColour,
1112 string *calendarDescription,
1113 int *calendarOrder){
1115 CalDAVServerResult serverResult;
1117 serverResult = EditCalendarProcess(calendarHREF,
1120 calendarDescription,
1123 return serverResult;
1127 CalDAVServerResult CalDAV::EditCalendar(string *calendarHREF,
1128 Colour *calendarColour){
1130 CalDAVServerResult serverResult;
1132 serverResult = EditCalendarProcess(calendarHREF,
1138 return serverResult;
1142 CalDAVServerResult CalDAV::EditCalendar(string *calendarHREF,
1143 string *calendarName){
1145 CalDAVServerResult serverResult;
1147 serverResult = EditCalendarProcess(calendarHREF,
1153 return serverResult;
1157 CalDAVServerResult CalDAV::EditCalendar(string *calendarHREF,
1158 int *calendarOrder){
1160 CalDAVServerResult serverResult;
1162 serverResult = EditCalendarProcess(calendarHREF,
1168 return serverResult;
1172 CalDAVServerResult CalDAV::EditCalendarDescription(string *calendarHREF,
1173 string *calendarDescription){
1175 CalDAVServerResult serverResult;
1177 serverResult = EditCalendarProcess(calendarHREF,
1180 calendarDescription,
1183 return serverResult;
1187 CalDAVServerResult CalDAV::DeleteCalendar(string *calendarHREF){
1189 CalDAVServerResult serverResult;
1191 // Build the server address.
1193 string userPrincipalURI = "";
1194 userPrincipalURI = GetUserPrincipal();
1196 if (userPrincipalURI.size() == 0){
1198 return serverResult;
1202 string calendarHomeURI = "";
1203 calendarHomeURI = GetCalendarHome(userPrincipalURI);
1205 // Generate the UUID.
1207 string UUIDValue = GenerateUUID();
1208 UUIDValue.erase(UUIDValue.end()-1);
1210 string calendarHomeURL = calendarHomeURI;
1211 calendarHomeURL.append(UUIDValue);
1212 calendarHomeURL.append("/");
1214 // Build the calendar list address.
1216 struct curl_slist *deleteRequestHeader = NULL;
1218 deleteRequestHeader = curl_slist_append(deleteRequestHeader, "Depth: infinity");
1220 string calendarDeleteURLAddress = BuildServerAddress(&connectionData, (*calendarHREF));
1222 curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, deleteRequestHeader);
1223 curl_easy_setopt(connectionHandle, CURLOPT_URL, calendarDeleteURLAddress.c_str());
1224 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, "DELETE");
1226 // Delete the calendar.
1229 serverHeader.clear();
1231 CURLcode serverConnectionResult = curl_easy_perform(connectionHandle);
1233 if (serverConnectionResult == CURLE_OK){
1234 serverResult.result = CALDAVQUERYRESULT_OK;
1236 serverResult.result = CALDAVQUERYRESULT_SERVERERROR;
1238 serverResult.code = serverConnectionResult;
1239 curl_easy_getinfo(connectionHandle, CURLINFO_RESPONSE_CODE, &serverResult.httpCode);
1241 // Restore the original settings.
1243 string originalServerAddress = BuildServerAddress(&connectionData, "/principals/");
1244 curl_easy_setopt(connectionHandle, CURLOPT_URL, originalServerAddress.c_str());
1245 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, NULL);
1246 curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 0L);
1247 curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
1248 curl_easy_setopt(connectionHandle, CURLOPT_READDATA, NULL);
1249 curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, NULL);
1250 curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, NULL);
1252 return serverResult;
1256 CalDAVServerResult CalDAV::GetEntryETag(string *calendarEntryHREF, string *eTagValue){
1258 CalDAVServerResult serverResult;
1259 CalDAVSendData entryETagGetData;
1261 // Build the server address.
1263 string userPrincipalURI = "";
1264 userPrincipalURI = GetUserPrincipal();
1266 if (userPrincipalURI.size() == 0){
1268 return serverResult;
1272 string calendarHomeURI = "";
1273 calendarHomeURI = GetCalendarHome(userPrincipalURI);
1275 // Split the path and filename.
1277 string entryURIPath;
1278 string entryFilename;
1280 SplitPathFilename(calendarEntryHREF, &entryURIPath, &entryFilename);
1282 // Build the request for the server.
1284 string entryETagRequest = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
1285 "<c:calendar-multiget xmlns:d=\"DAV:\" xmlns:c=\"urn:ietf:params:xml:ns:caldav\">\n"
1290 entryETagRequest += (*calendarEntryHREF);
1291 entryETagRequest += "</d:href>\n"
1292 "</c:calendar-multiget>";
1294 entryETagGetData.readptr = &entryETagRequest;
1295 entryETagGetData.sizeleft = entryETagRequest.size();
1297 // Build the calendar list address.
1299 struct curl_slist *getETagRequestHeader = NULL;
1301 getETagRequestHeader = curl_slist_append(getETagRequestHeader, "Depth: 1");
1302 getETagRequestHeader = curl_slist_append(getETagRequestHeader, "Prefer: return-minimal");
1303 getETagRequestHeader = curl_slist_append(getETagRequestHeader, "Content-Type: application/xml; charset=utf-8");
1305 string getETagURLAddress = BuildServerAddress(&connectionData, entryURIPath);
1307 curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, getETagRequestHeader);
1308 curl_easy_setopt(connectionHandle, CURLOPT_URL, getETagURLAddress.c_str());
1309 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, "REPORT");
1310 curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 1L);
1311 curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
1312 curl_easy_setopt(connectionHandle, CURLOPT_READDATA, &entryETagGetData);
1313 curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, CalDAVSend);
1315 // Attempt to get the entity tag.
1318 serverHeader.clear();
1320 CURLcode serverConnectionResult = curl_easy_perform(connectionHandle);
1322 if (serverConnectionResult == CURLE_OK){
1323 serverResult.result = CALDAVQUERYRESULT_OK;
1325 serverResult.result = CALDAVQUERYRESULT_SERVERERROR;
1327 serverResult.code = serverConnectionResult;
1328 curl_easy_getinfo(connectionHandle, CURLINFO_RESPONSE_CODE, &serverResult.httpCode);
1330 if (serverConnectionResult != CURLE_OK){
1331 return serverResult;
1334 // Get the entity tag from the result.
1336 *eTagValue = ProcessXMLEntryETag();
1338 // Restore the original settings.
1340 string originalServerAddress = BuildServerAddress(&connectionData, "/principals/");
1341 curl_easy_setopt(connectionHandle, CURLOPT_URL, originalServerAddress.c_str());
1342 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, NULL);
1343 curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 0L);
1344 curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
1345 curl_easy_setopt(connectionHandle, CURLOPT_READDATA, NULL);
1346 curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, NULL);
1347 curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, NULL);
1349 return serverResult;
1353 CalDAVServerResult CalDAV::AddEntry(string *calendarEntryHREF, string *entryData){
1355 // Add an entry to the calendar collection.
1357 CalDAVServerResult serverResult;
1358 CalDAVSendData entryAddSendData;
1360 // Build the calendar list address.
1362 string entryAddURLAddress = BuildServerAddress(&connectionData, (*calendarEntryHREF));
1364 entryAddSendData.readptr = entryData;
1365 entryAddSendData.sizeleft = entryData->size();
1367 struct curl_slist *calendarRequestHeader = NULL;
1369 calendarRequestHeader = curl_slist_append(calendarRequestHeader, "Content-Type: text/calendar; charset=utf-8");
1371 curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, calendarRequestHeader);
1372 curl_easy_setopt(connectionHandle, CURLOPT_URL, entryAddURLAddress.c_str());
1373 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, "PUT");
1374 curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 1L);
1375 curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
1376 curl_easy_setopt(connectionHandle, CURLOPT_READDATA, &entryAddSendData);
1377 curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, CalDAVSend);
1379 // Process the data.
1382 serverHeader.clear();
1384 CURLcode serverConnectionResult = curl_easy_perform(connectionHandle);
1386 if (serverConnectionResult == CURLE_OK){
1387 serverResult.result = CALDAVQUERYRESULT_OK;
1389 serverResult.result = CALDAVQUERYRESULT_SERVERERROR;
1391 serverResult.code = serverConnectionResult;
1392 curl_easy_getinfo(connectionHandle, CURLINFO_RESPONSE_CODE, &serverResult.httpCode);
1394 // Restore the original settings.
1396 string originalServerAddress = BuildServerAddress(&connectionData, "/principals/");
1397 curl_easy_setopt(connectionHandle, CURLOPT_URL, originalServerAddress.c_str());
1398 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, NULL);
1399 curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 0L);
1400 curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
1401 curl_easy_setopt(connectionHandle, CURLOPT_READDATA, NULL);
1402 curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, NULL);
1403 curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, NULL);
1405 return serverResult;
1409 CalDAVServerResult CalDAV::EditEntry(string *calendarEntryHREF, string *entryData, string *entryETag){
1411 // Edit an entry in the calendar collection.
1413 // Add an entry to the calendar collection.
1415 CalDAVServerResult serverResult;
1416 CalDAVSendData entryAddSendData;
1418 // Build the calendar list address.
1420 string entryAddURLAddress = BuildServerAddress(&connectionData, (*calendarEntryHREF));
1422 entryAddSendData.readptr = entryData;
1423 entryAddSendData.sizeleft = entryData->size();
1425 string ifMatchHeader = "If-Match: \"";
1426 ifMatchHeader.append(*entryETag);
1427 ifMatchHeader.append("\"");
1429 struct curl_slist *calendarRequestHeader = NULL;
1431 calendarRequestHeader = curl_slist_append(calendarRequestHeader, "Content-Type: text/calendar; charset=utf-8");
1432 calendarRequestHeader = curl_slist_append(calendarRequestHeader, ifMatchHeader.c_str());
1434 curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, calendarRequestHeader);
1435 curl_easy_setopt(connectionHandle, CURLOPT_URL, entryAddURLAddress.c_str());
1436 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, "PUT");
1437 curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 1L);
1438 curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
1439 curl_easy_setopt(connectionHandle, CURLOPT_READDATA, &entryAddSendData);
1440 curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, CalDAVSend);
1442 // Process the data.
1445 serverHeader.clear();
1447 CURLcode serverConnectionResult = curl_easy_perform(connectionHandle);
1449 if (serverConnectionResult == CURLE_OK){
1450 serverResult.result = CALDAVQUERYRESULT_OK;
1452 serverResult.result = CALDAVQUERYRESULT_SERVERERROR;
1454 serverResult.code = serverConnectionResult;
1455 curl_easy_getinfo(connectionHandle, CURLINFO_RESPONSE_CODE, &serverResult.httpCode);
1457 // Restore the original settings.
1459 string originalServerAddress = BuildServerAddress(&connectionData, "/principals/");
1460 curl_easy_setopt(connectionHandle, CURLOPT_URL, originalServerAddress.c_str());
1461 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, NULL);
1462 curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 0L);
1463 curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
1464 curl_easy_setopt(connectionHandle, CURLOPT_READDATA, NULL);
1465 curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, NULL);
1466 curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, NULL);
1468 return serverResult;
1472 CalDAVServerResult CalDAV::DeleteEntry(string *calendarEntryHREF){
1474 // Delete an entry in the calendar collection.
1476 CalDAVServerResult serverResult;
1478 // Build the calendar list address.
1480 string entryDeleteURLAddress = BuildServerAddress(&connectionData, (*calendarEntryHREF));
1482 curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, NULL);
1483 curl_easy_setopt(connectionHandle, CURLOPT_URL, entryDeleteURLAddress.c_str());
1484 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, "DELETE");
1486 // Delete the calendar.
1489 serverHeader.clear();
1491 CURLcode serverConnectionResult = curl_easy_perform(connectionHandle);
1493 if (serverConnectionResult == CURLE_OK){
1494 serverResult.result = CALDAVQUERYRESULT_OK;
1496 serverResult.result = CALDAVQUERYRESULT_SERVERERROR;
1498 serverResult.code = serverConnectionResult;
1499 curl_easy_getinfo(connectionHandle, CURLINFO_RESPONSE_CODE, &serverResult.httpCode);
1501 // Restore the original settings.
1503 string originalServerAddress = BuildServerAddress(&connectionData, "/principals/");
1504 curl_easy_setopt(connectionHandle, CURLOPT_URL, originalServerAddress.c_str());
1505 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, NULL);
1506 curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 0L);
1507 curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
1508 curl_easy_setopt(connectionHandle, CURLOPT_READDATA, NULL);
1509 curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, NULL);
1510 curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, NULL);
1512 return serverResult;
1516 COSSLVerified CalDAV::SSLVerify()
1521 void CalDAV::BypassSSLVerification(bool enableBypass){
1522 enableSSLBypass = enableBypass;
1523 sslSelfSigned = enableBypass;
1526 #if defined(__APPLE__)
1528 SecTrustRef CalDAV::BuildSSLCollection(){
1530 return certificateData;
1534 #elif defined(__WIN32__)
1536 PCCERT_CONTEXT CalDAV::BuildSSLCollection(){
1538 return certificateData;
1544 SSLCertCollectionString CalDAV::BuildSSLCollection(){
1546 // Build and return the SSL collection.
1548 SSLCertCollectionString sslCertInfo;
1550 // Grab the certificate data.
1553 struct curl_slist *certdata;
1554 struct curl_certinfo *certinfo;
1557 certptr.certdata = NULL;
1559 CURLcode result = curl_easy_getinfo(connectionHandle, CURLINFO_CERTINFO, &certptr.certinfo);
1561 std::string certPropName;
1562 std::string certPropValue;
1564 for (int i = 0; i < certptr.certinfo->num_of_certs; i++){
1566 struct curl_slist *slist;
1567 SSLCertDataString sslCertDataInc;
1569 for (slist = certptr.certinfo->certinfo[i]; slist; slist = slist->next){
1571 // Using wxStringTokenizer from wxWidgets.
1573 wxStringTokenizer certDataInc(wxString::FromUTF8(slist->data), ":");
1575 // Get first token as the property name.
1577 certPropName = certDataInc.GetNextToken().ToStdString();
1579 // Get remaining tokens as the property value.
1581 while(certDataInc.HasMoreTokens()){
1583 certPropValue.append(certDataInc.GetNextToken());
1587 sslCertDataInc.CertData.insert(std::make_pair(certPropName, certPropValue));
1588 certPropName.clear();
1589 certPropValue.clear();
1593 sslCertInfo.SSLCollection.insert(std::make_pair(i, sslCertDataInc));
1603 bool CalDAV::CanDoSSL(){
1607 bool CalDAV::HasValidResponse(){
1608 return validResponse;
1611 bool CalDAV::AbleToLogin(){
1615 bool CalDAV::IsSelfSigned(){
1616 return sslSelfSigned;
1619 string CalDAV::GetErrorMessage(){
1621 errorMessage = sessionErrorBuffer;
1622 return errorMessage;
1626 static bool CalDAVObjectValidSettings(CalDAVConnectionData *connData){
1628 // Check if the passed CalDAV Connection Data is has
1629 // an address set. Return false if nullptr is used.
1631 if (connData == nullptr){
1637 // Check the server hostname. Return false
1638 // if no value has been set.
1640 if (connData->hostname.size() == 0){
1646 // Check the server port. Return false if
1647 // no value has been set or the port number
1648 // is less than 1 or higher than 65535.
1650 if (connData->port < 1 || connData->port > 65535){
1656 // Check the server username. Return false
1657 // if no value has been set.
1659 if (connData->username.size() == 0){
1665 // Check the server password. Return false
1666 // if no value has been set.
1668 if (connData->password.size() == 0){
1674 // Cannot check UseSSL: It is either true
1677 // Cannot check Prefix: The prefix may need
1678 // to be worked out first.
1680 // No errors were found whilst checking so
1687 string CalDAV::BuildServerAddress(CalDAVConnectionData *connData, string uriAddress){
1689 string serverAddress;
1691 // Setup the server address.
1693 if (connData->useSSL == true){
1694 serverAddress += "https://";
1696 serverAddress += "http://";
1699 serverAddress += connData->hostname;
1701 // Check if server port is 80, otherwise
1702 // specifiy the port number in the address.
1704 if (connData->port != 80){
1705 serverAddress += ":";
1706 serverAddress += to_string(connData->port);
1709 serverAddress += uriAddress;
1711 return serverAddress;
1715 void CalDAV::SetupDefaultParametersNonSSL(bool doAuthentication){
1717 std::string serverAddress = "";
1719 string serverAddressURL = "http://" + connectionData.hostname + ":" + to_string(connectionData.port) + "/";
1720 string usernamePassword = connectionData.username + ":" + connectionData.password;
1722 curl_easy_setopt(connectionHandle, CURLOPT_URL, serverAddressURL.c_str());
1723 curl_easy_setopt(connectionHandle, CURLOPT_NOPROGRESS, 1L);
1724 curl_easy_setopt(connectionHandle, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST|CURLAUTH_BASIC);
1725 curl_easy_setopt(connectionHandle, CURLOPT_TIMEOUT, 60);
1726 curl_easy_setopt(connectionHandle, CURLOPT_FAILONERROR, true);
1727 curl_easy_setopt(connectionHandle, CURLOPT_USERAGENT, XSDCAL_USERAGENT);
1728 curl_easy_setopt(connectionHandle, CURLOPT_NOSIGNAL, 1L);
1729 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, "GET");
1730 curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, nullptr);
1731 curl_easy_setopt(connectionHandle, CURLOPT_POSTFIELDS, nullptr);
1732 curl_easy_setopt(connectionHandle, CURLOPT_POSTFIELDSIZE, 0L);
1734 if (doAuthentication == true){
1735 curl_easy_setopt(connectionHandle, CURLOPT_USERPWD, usernamePassword.c_str());
1737 curl_easy_setopt(connectionHandle, CURLOPT_USERPWD, NULL);
1742 void CalDAV::SetupDefaultParametersSSL(bool doAuthentication){
1744 // Setup the default parameters.
1746 string ServerAddressURL = "https://" + connectionData.hostname + ":" + to_string(connectionData.port) + "/";
1747 string UsernamePassword = connectionData.username + ":" + connectionData.password;
1749 curl_easy_setopt(connectionHandle, CURLOPT_URL, ServerAddressURL.c_str());
1750 curl_easy_setopt(connectionHandle, CURLOPT_NOPROGRESS, 1L);
1751 curl_easy_setopt(connectionHandle, CURLOPT_CERTINFO, 1L);
1752 curl_easy_setopt(connectionHandle, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST|CURLAUTH_BASIC);
1753 curl_easy_setopt(connectionHandle, CURLOPT_TIMEOUT, 60);
1754 curl_easy_setopt(connectionHandle, CURLOPT_FAILONERROR, 0L);
1755 curl_easy_setopt(connectionHandle, CURLOPT_USERAGENT, XSDCAL_USERAGENT);
1756 curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
1757 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, "GET");
1758 curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, nullptr);
1759 curl_easy_setopt(connectionHandle, CURLOPT_POSTFIELDS, nullptr);
1760 curl_easy_setopt(connectionHandle, CURLOPT_POSTFIELDSIZE, 0L);
1762 if (doAuthentication == true){
1763 curl_easy_setopt(connectionHandle, CURLOPT_USERPWD, UsernamePassword.c_str());
1765 curl_easy_setopt(connectionHandle, CURLOPT_USERPWD, NULL);
1768 if (enableSSLBypass == true){
1769 curl_easy_setopt(connectionHandle, CURLOPT_SSL_VERIFYHOST, 0L);
1770 curl_easy_setopt(connectionHandle, CURLOPT_SSL_VERIFYPEER, 0L);
1771 curl_easy_setopt(connectionHandle, CURLOPT_SSL_VERIFYSTATUS, 0L);
1773 curl_easy_setopt(connectionHandle, CURLOPT_SSL_VERIFYHOST, 2L);
1774 curl_easy_setopt(connectionHandle, CURLOPT_SSL_VERIFYPEER, 1L);
1775 curl_easy_setopt(connectionHandle, CURLOPT_SSL_VERIFYSTATUS, 1L);
1778 #if !defined(__APPLE__) || defined(__WIN32__)
1780 if (connectionData.account.size() > 0){
1782 // Check if the server certificate file exists.
1784 string certificateFilename = GetAccountDir(connectionData.account, true);
1786 if (wxFile::Exists(certificateFilename)){
1788 curl_easy_setopt(connectionHandle, CURLOPT_CAINFO, certificateFilename.c_str());
1798 void CalDAV::ResetResults(){
1801 COSSLVerified SSLVerified = COSSL_NORESULT;
1802 validResponse = false;
1804 sslSelfSigned = false;
1805 //taskCompleted = false;
1807 sessionErrorBuffer[0] = '\0';
1808 //sessionResult = CURLE_OK;
1811 /*if (headerList != nullptr){
1812 curl_slist_free_all(headerList);
1813 headerList = nullptr;