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 CalDAV::CalDAVReceive(char *receivedBuffer, size_t size, size_t newMemoryBytes, void *stream)
26 // Writeback function for the CardDAV object.
28 CalDAVPassObject *data = static_cast<CalDAVPassObject*>(stream);
29 data->DataSetting->append(receivedBuffer);
31 // Get the SSL engine pointer and trust if required on certain operating systems.
33 if (data->ServerUsingSSL == true) {
35 #if defined(__APPLE__)
37 const struct curl_tlssessioninfo *TLSInfo;
39 TLSCode = curl_easy_getinfo(data->ConnectionSessionObject, CURLINFO_TLS_SSL_PTR, &TLSInfo);
41 SecTrustRef CertificateData;
43 if (TLSInfo->internals != nullptr && TLSCode == CURLE_OK) {
44 SSLCopyPeerTrust((SSLContext*)TLSInfo->internals, &CertificateData);
45 data->SSLContext = CertificateData;
48 #elif defined(__WIN32__)
50 const struct curl_tlssessioninfo *TLSInfo;
52 TLSCode = curl_easy_getinfo(data->ConnectionSessionObject, CURLINFO_TLS_SSL_PTR, &TLSInfo);
54 if (TLSInfo->internals != nullptr && TLSCode == CURLE_OK) {
56 // Free the previous certificate data.
58 //CertFreeCertificateContext(CertificateData);
60 PCCERT_CONTEXT CertificateData;
62 PCtxtHandle SSLHandle = (PCtxtHandle)TLSInfo->internals;
63 SECURITY_STATUS GetData = QueryContextAttributes(SSLHandle, SECPKG_ATTR_REMOTE_CERT_CONTEXT, &CertificateData);
65 data->SSLContext = CertificateData;
73 return size * newMemoryBytes;
77 size_t CalDAVSend(char *sendBuffer, size_t size, size_t newMemoryBytes, void *dataStruct){
79 struct CalDAVSendData *uploadPtr = (struct CalDAVSendData *)dataStruct;
81 if (uploadPtr->sizeleft){
83 uploadPtr->sizeleft--;
86 charSend = (*uploadPtr->readptr)[uploadPtr->seek];
88 *sendBuffer = charSend;
102 // Setup the objects within the CalDAV connection
105 connectionHandle = curl_easy_init();
111 // Destory the objects within the CalDAV connection
114 curl_easy_cleanup(connectionHandle);
115 connectionHandle = nullptr;
119 void CalDAV::SetupConnectionData(CalDAVConnectionData *connData){
121 // Check if ConnData is a nullptr, return if it is.
123 if (connData == nullptr){
127 // Set the connection settings to the values from ConnData.
129 connectionData = (*connData);
133 CalDAVStatus CalDAV::GetConnectionData(){
135 // Get the current connection settings for the CalDAV
136 // connection object and return a CalDAVStatus object.
138 CalDAVStatus connectionStatus;
140 connectionStatus.hostname = connectionData.hostname;
141 connectionStatus.port = connectionData.port;
142 connectionStatus.username = connectionData.username;
143 connectionStatus.prefix = connectionData.prefix;
144 connectionStatus.useSSL = connectionData.useSSL;
145 connectionStatus.timeout = connectionData.timeout;
147 return connectionStatus;
151 CalDAVServerResult CalDAV::Connect(bool doAuthentication){
153 connectionData.useSSL ? SetupDefaultParametersSSL(doAuthentication) : SetupDefaultParametersNonSSL(doAuthentication);
156 CalDAVServerResult serverResult;
158 string serverAddress = "";
159 string serverUserPass = "";
161 // Setup the server address.
163 serverAddress = BuildServerAddress(&connectionData, "/principals/");
165 // Setup the server password.
167 serverUserPass += connectionData.username;
168 serverUserPass += ":";
169 serverUserPass += connectionData.password;
171 PageDataObject.CalDAVObject = this;
172 PageDataObject.ConnectionSessionObject = connectionHandle;
173 PageDataObject.DataSetting = &serverData;
174 PageDataObject.ServerUsingSSL = true;
176 PageHeaderObject.CalDAVObject = this;
177 PageHeaderObject.ConnectionSessionObject = connectionHandle;
178 PageHeaderObject.DataSetting = &serverHeader;
179 PageHeaderObject.ServerUsingSSL = true;
181 curl_easy_setopt(connectionHandle, CURLOPT_URL, serverAddress.c_str());
182 curl_easy_setopt(connectionHandle, CURLOPT_USERPWD, serverUserPass.c_str());
183 curl_easy_setopt(connectionHandle, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST);
184 curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
185 curl_easy_setopt(connectionHandle, CURLOPT_FAILONERROR, 1L);
186 curl_easy_setopt(connectionHandle, CURLOPT_TIMEOUT, connectionData.timeout);
187 curl_easy_setopt(connectionHandle, CURLOPT_WRITEFUNCTION, CalDAV::CalDAVReceive);
188 curl_easy_setopt(connectionHandle, CURLOPT_WRITEDATA, &PageDataObject);
189 curl_easy_setopt(connectionHandle, CURLOPT_WRITEHEADER, &PageHeaderObject);
191 // Connect to the CalDAV server.
193 serverResult.code = curl_easy_perform(connectionHandle);
195 // Process the result received from the server.
197 // Get the HTTP code.
199 curl_easy_getinfo(connectionHandle, CURLINFO_RESPONSE_CODE, &serverResult.httpCode);
201 switch(serverResult.code){
204 if (connectionData.useSSL)
206 sslStatus = connectionData.useSSL;
207 sslVerified = COSSL_VERIFIED;
209 serverResult.result = CALDAVQUERYRESULT_OK;
211 case CURLE_HTTP_RETURNED_ERROR:
212 if (connectionData.useSSL)
214 sslStatus = connectionData.useSSL;
215 sslVerified = COSSL_VERIFIED;
217 serverResult.result = CALDAVQUERYRESULT_OK;
218 if (serverResult.httpCode == 401)
223 case CURLE_SSL_CACERT:
224 case CURLE_SSL_CONNECT_ERROR:
225 case CURLE_PEER_FAILED_VERIFICATION:
226 if (connectionData.useSSL)
228 sslStatus = connectionData.useSSL;
229 sslVerified = COSSL_UNABLETOVERIFY;
231 serverResult.result = CALDAVQUERYRESULT_SSLFAILURE;
235 serverResult.result = CALDAVQUERYRESULT_SERVERERROR;
240 // Set the certificate data (if required).
242 #if defined(__APPLE__)
244 if (connectionData.useSSL) {
246 certificateData = PageHeaderObject.SSLContext;
250 #elif defined(__WIN32__)
252 if (connectionData.useSSL) {
254 certificateData = PageHeaderObject.SSLContext;
260 // Check if a valid response was received before continuing.
262 if (serverResult.httpCode >= 200 && serverResult.httpCode <= 299)
264 validResponse = true;
271 CalDAVServerResult CalDAV::GetServerResult(){
273 return connectionServerResult;
277 CalDAVServerSupport CalDAV::GetServerSupport(){
279 CalDAVServerSupport serverStatus;
281 // Setup the server connection.
283 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, "OPTIONS");
285 CURLcode serverResult = curl_easy_perform(connectionHandle);
289 if (serverResult == CURLE_OK){
290 connectionServerResult.result = CALDAVQUERYRESULT_OK;
292 connectionServerResult.result = CALDAVQUERYRESULT_SERVERERROR;
294 connectionServerResult.code = serverResult;
295 curl_easy_getinfo(connectionHandle, CURLINFO_RESPONSE_CODE, &connectionServerResult.httpCode);
297 if (serverResult != CURLE_OK){
301 // Check that the server header has data in,
302 // otherwise return an "empty" CalDAVServerSupport.
304 if (serverHeader.size() == 0){
308 // Process each line looking for the first DAV header
311 bool newlineMode = true;
315 for (int charSeek = 0; charSeek < serverHeader.size(); charSeek++){
317 if (newlineMode == true){
319 // Check if we have reached the end of the string.
321 if (charSeek >= serverHeader.size()){
327 // Check the first four letters to make sure
330 string davHeaderCheck = "";
333 davHeaderCheck = serverHeader.substr(charSeek, 4);
336 catch (out_of_range &oor){
340 if (davHeaderCheck == "DAV:"){
344 for (; charSeek < serverHeader.size(); charSeek++){
346 if (serverHeader[charSeek] == '\n'){
352 davLine.push_back(serverHeader[charSeek]);
364 if (serverHeader[charSeek] == '\n'){
372 // Process the DAV line.
374 vector<string> davLineData;
375 string davSegmentString;
377 for (int charSeek = 0; charSeek < davLine.size(); charSeek++){
379 if (davLine[charSeek] == ' '){
383 if (davLine[charSeek] == ','){
385 davLineData.push_back(davSegmentString);
386 davSegmentString.clear();
391 davSegmentString += davLine[charSeek];
395 // Process the DAV values and set each value
396 // to true as required.
398 for (int davItemSeek = 0;
399 davItemSeek < davLineData.size();
402 if (davLineData.at(davItemSeek) == "calendar-access"){
404 serverStatus.basicSupport = true;
410 // Reset the connection status.
412 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, NULL);
418 string CalDAV::GetUserPrincipal(){
420 string currentUserPrincipal = "";
421 string userPrincipalRequest = "";
422 CalDAVSendData userPrincipalSendData;
424 userPrincipalRequest = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
425 "<d:propfind xmlns:d=\"DAV:\">\n"
427 " <d:current-user-principal />\n"
431 userPrincipalSendData.readptr = &userPrincipalRequest;
432 userPrincipalSendData.sizeleft = userPrincipalRequest.size();
436 struct curl_slist *userPrincipalRequestHeader = NULL;
438 userPrincipalRequestHeader = curl_slist_append(userPrincipalRequestHeader, "Depth: 0");
439 userPrincipalRequestHeader = curl_slist_append(userPrincipalRequestHeader, "Prefer: return-minimal");
440 userPrincipalRequestHeader = curl_slist_append(userPrincipalRequestHeader, "Content-Type: application/xml; charset=utf-8");
442 curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, userPrincipalRequestHeader);
444 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, "PROPFIND");
445 curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 1L);
446 curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
447 curl_easy_setopt(connectionHandle, CURLOPT_READDATA, &userPrincipalSendData);
448 curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, CalDAVSend);
453 serverHeader.clear();
455 CURLcode serverResult = curl_easy_perform(connectionHandle);
459 if (serverResult == CURLE_OK){
460 connectionServerResult.result = CALDAVQUERYRESULT_OK;
462 connectionServerResult.result = CALDAVQUERYRESULT_SERVERERROR;
464 connectionServerResult.code = serverResult;
465 curl_easy_getinfo(connectionHandle, CURLINFO_RESPONSE_CODE, &connectionServerResult.httpCode);
467 if (serverResult != CURLE_OK){
469 return currentUserPrincipal;
473 // Process the User Principal from the ServerData.
475 currentUserPrincipal = ProcessXMLUserPrincipal();
477 // Reset the changed settings.
479 curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 0L);
480 curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
481 curl_easy_setopt(connectionHandle, CURLOPT_READDATA, NULL);
482 curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, NULL);
484 return currentUserPrincipal;
488 string CalDAV::GetCalendarHome(string userPrincipalURI){
490 string calendarHomeURI = "";
492 // Build the Calendar Home URL address.
494 string calendarHomeURL = BuildServerAddress(&connectionData, userPrincipalURI);
496 // Setup the header request.
498 CalDAVSendData calendarHomeSendData;
500 string calendarHomeRequest = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
501 "<d:propfind xmlns:d=\"DAV:\" xmlns:c=\"urn:ietf:params:xml:ns:caldav\">\n"
503 " <c:calendar-home-set />\n"
507 calendarHomeSendData.readptr = &calendarHomeRequest;
508 calendarHomeSendData.sizeleft = calendarHomeRequest.size();
512 struct curl_slist *calendarRequestHeader = NULL;
514 calendarRequestHeader = curl_slist_append(calendarRequestHeader, "Depth: 0");
515 calendarRequestHeader = curl_slist_append(calendarRequestHeader, "Prefer: return-minimal");
516 calendarRequestHeader = curl_slist_append(calendarRequestHeader, "Content-Type: application/xml; charset=utf-8");
518 curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, calendarRequestHeader);
519 curl_easy_setopt(connectionHandle, CURLOPT_URL, calendarHomeURL.c_str());
520 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, "PROPFIND");
521 curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 1L);
522 curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
523 curl_easy_setopt(connectionHandle, CURLOPT_READDATA, &calendarHomeSendData);
524 curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, CalDAVSend);
529 serverHeader.clear();
531 CURLcode serverResult = curl_easy_perform(connectionHandle);
535 if (serverResult == CURLE_OK){
536 connectionServerResult.result = CALDAVQUERYRESULT_OK;
538 connectionServerResult.result = CALDAVQUERYRESULT_SERVERERROR;
540 connectionServerResult.code = serverResult;
541 curl_easy_getinfo(connectionHandle, CURLINFO_RESPONSE_CODE, &connectionServerResult.httpCode);
543 if (serverResult != CURLE_OK){
545 return calendarHomeURI;
549 // Process the User Principal from the ServerData.
551 calendarHomeURI = ProcessXMLCalendarHome();
553 // Reset the changed settings.
555 string originalServerAddress = BuildServerAddress(&connectionData, "/principals/");
556 curl_easy_setopt(connectionHandle, CURLOPT_URL, originalServerAddress.c_str());
558 curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 0L);
559 curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
560 curl_easy_setopt(connectionHandle, CURLOPT_READDATA, NULL);
561 curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, NULL);
562 curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, NULL);
564 return calendarHomeURI;
568 CalDAVCalendarList CalDAV::GetCalendars(){
570 CalDAVCalendarList serverList;
571 CalDAVSendData calendarListSendData;
573 // Build the server address.
575 string userPrincipalURI = "";
576 userPrincipalURI = GetUserPrincipal();
578 if (userPrincipalURI.size() == 0){
584 string calendarHomeURI = "";
585 calendarHomeURI = GetCalendarHome(userPrincipalURI);
587 string calendarListURLAddress = BuildServerAddress(&connectionData, calendarHomeURI);
589 string calendarListRequest = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
590 "<d:propfind xmlns:d=\"DAV:\" xmlns:cs=\"http://calendarserver.org/ns/\""
591 " xmlns:c=\"urn:ietf:params:xml:ns:caldav\" xmlns:x0=\"http://apple.com/ns/ical/\">\n"
593 " <d:resourcetype />\n"
594 " <d:displayname />\n"
595 " <d:sync-token />\n"
596 " <x0:calendar-color />\n"
597 " <x0:calendar-order />\n"
599 " <c:supported-calendar-component-set />\n"
600 " <c:calendar-description />\n"
604 calendarListSendData.readptr = &calendarListRequest;
605 calendarListSendData.sizeleft = calendarListRequest.size();
609 struct curl_slist *calendarListRequestHeader = NULL;
611 calendarListRequestHeader = curl_slist_append(calendarListRequestHeader, "Depth: 1");
612 calendarListRequestHeader = curl_slist_append(calendarListRequestHeader, "Prefer: return-minimal");
613 calendarListRequestHeader = curl_slist_append(calendarListRequestHeader, "Content-Type: application/xml; charset=utf-8");
615 curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, calendarListRequestHeader);
616 curl_easy_setopt(connectionHandle, CURLOPT_URL, calendarListURLAddress.c_str());
617 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, "PROPFIND");
618 curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 1L);
619 curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
620 curl_easy_setopt(connectionHandle, CURLOPT_READDATA, &calendarListSendData);
621 curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, CalDAVSend);
626 serverHeader.clear();
628 CURLcode serverResult = curl_easy_perform(connectionHandle);
630 //ServerList = ProcessXMLCalendarList();
632 if (serverResult == CURLE_OK){
633 connectionServerResult.result = CALDAVQUERYRESULT_OK;
635 connectionServerResult.result = CALDAVQUERYRESULT_SERVERERROR;
637 connectionServerResult.code = serverResult;
638 curl_easy_getinfo(connectionHandle, CURLINFO_RESPONSE_CODE, &connectionServerResult.httpCode);
640 if (serverResult != CURLE_OK){
646 // Process the received XML data into a list of calendars
649 serverList = ProcessXMLCalendarList();
651 // Restore the original settings.
653 string originalServerAddress = BuildServerAddress(&connectionData, "/principals/");
655 curl_easy_setopt(connectionHandle, CURLOPT_URL, originalServerAddress.c_str());
656 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, NULL);
657 curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 0L);
658 curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
659 curl_easy_setopt(connectionHandle, CURLOPT_READDATA, NULL);
660 curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, NULL);
666 CalDAVEntryList CalDAV::GetEntryList(string *calendarHREF){
668 CalDAVEntryList entryList;
669 CalDAVSendData entryListSendData;
671 if (calendarHREF->size() == 0){
677 string entryListURLAddress = BuildServerAddress(&connectionData, *calendarHREF);
679 string entryListRequest = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
681 /*if (CalendarTag == nullptr){*/
683 entryListRequest += "<c:calendar-query xmlns:d=\"DAV:\" xmlns:cs=\"http://calendarserver.org/ns/\""
684 " xmlns:c=\"urn:ietf:params:xml:ns:caldav\" xmlns:x0=\"http://apple.com/ns/ical/\">\n"
687 " <c:calendar-data />\n"
690 " <c:comp-filter name=\"VCALENDAR\" />\n"
692 "</c:calendar-query>";
696 EntryListRequest += "<d:sync-collection xmlns:d=\"DAV:\" xmlns:cs=\"http://calendarserver.org/ns/\""
697 " xmlns:c=\"urn:ietf:params:xml:ns:caldav\" xmlns:x0=\"http://apple.com/ns/ical/\">\n"
699 EntryListRequest += *CalendarTag;
700 EntryListRequest += "</d:sync-token>\n"
701 " <d:sync-level>1</d:sync-level>\n"
704 " <c:calendar-data />\n"
706 "</d:sync-collection>";
710 entryListSendData.readptr = &entryListRequest;
711 entryListSendData.sizeleft = entryListRequest.size();
713 struct curl_slist *entryListRequestHeader = NULL;
715 entryListRequestHeader = curl_slist_append(entryListRequestHeader, "Content-Type: application/xml; charset=utf-8");
717 /*if (CalendarTag != nullptr){
719 EntryListRequestHeader = curl_slist_append(EntryListRequestHeader, "Content-Type: application/xml; charset=utf-8");
720 EntryListRequestHeader = curl_slist_append(EntryListRequestHeader, "Content-Type: application/xml; charset=utf-8");
724 curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, entryListRequestHeader);
725 curl_easy_setopt(connectionHandle, CURLOPT_URL, entryListURLAddress.c_str());
726 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, "REPORT");
727 curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 1L);
728 curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
729 curl_easy_setopt(connectionHandle, CURLOPT_READDATA, &entryListSendData);
730 curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, CalDAVSend);
735 serverHeader.clear();
737 CURLcode serverResult = curl_easy_perform(connectionHandle);
739 //ServerList = ProcessXMLCalendarList();
741 if (serverResult == CURLE_OK){
742 connectionServerResult.result = CALDAVQUERYRESULT_OK;
744 connectionServerResult.result = CALDAVQUERYRESULT_SERVERERROR;
746 connectionServerResult.code = serverResult;
747 curl_easy_getinfo(connectionHandle, CURLINFO_RESPONSE_CODE, &connectionServerResult.httpCode);
749 if (serverResult != CURLE_OK){
755 // Process the received XML data into a list of calendars
758 entryList = ProcessXMLEntryList();
760 // Restore the original settings.
762 string originalServerAddress = BuildServerAddress(&connectionData, "/principals/");
764 curl_easy_setopt(connectionHandle, CURLOPT_URL, originalServerAddress.c_str());
765 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, NULL);
766 curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 0L);
767 curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
768 curl_easy_setopt(connectionHandle, CURLOPT_READDATA, NULL);
769 curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, NULL);
775 CalDAVEntryList CalDAV::GetEntryList(string *calendarHREF, string *calendarTag){
777 CalDAVEntryList entryList;
778 CalDAVSendData entryListSendData;
780 if (calendarHREF->size() == 0){
786 string entryListURLAddress = BuildServerAddress(&connectionData, *calendarHREF);
788 // First query: Get the list of contacts that need to be updated.
790 string entryListRequest = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
792 entryListRequest += "<d:sync-collection xmlns:d=\"DAV:\" xmlns:cs=\"http://calendarserver.org/ns/\""
793 " xmlns:c=\"urn:ietf:params:xml:ns:caldav\" xmlns:x0=\"http://apple.com/ns/ical/\">\n"
796 if (calendarTag != nullptr){
798 entryListRequest += *calendarTag;
802 entryListRequest += "";
806 entryListRequest += "</d:sync-token>\n"
807 " <d:sync-level>1</d:sync-level>\n"
811 "</d:sync-collection>";
813 entryListSendData.readptr = &entryListRequest;
814 entryListSendData.sizeleft = entryListRequest.size();
816 struct curl_slist *entryListRequestHeader = NULL;
818 entryListRequestHeader = curl_slist_append(entryListRequestHeader, "Content-Type: application/xml; charset=utf-8");
820 curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, entryListRequestHeader);
821 curl_easy_setopt(connectionHandle, CURLOPT_URL, entryListURLAddress.c_str());
822 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, "REPORT");
823 curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 1L);
824 curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
825 curl_easy_setopt(connectionHandle, CURLOPT_READDATA, &entryListSendData);
826 curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, CalDAVSend);
831 serverHeader.clear();
833 CURLcode serverResult = curl_easy_perform(connectionHandle);
835 if (serverResult == CURLE_OK){
836 connectionServerResult.result = CALDAVQUERYRESULT_OK;
838 connectionServerResult.result = CALDAVQUERYRESULT_SERVERERROR;
840 connectionServerResult.code = serverResult;
841 curl_easy_getinfo(connectionHandle, CURLINFO_RESPONSE_CODE, &connectionServerResult.httpCode);
843 if (serverResult != CURLE_OK){
849 entryList = ProcessXMLSyncTokenList();
851 // Check the last entry matches the HREF and if it
852 // does then delete it.
854 if (entryList.href.size() > 0) {
856 if (entryList.href.rbegin()->second == *calendarHREF){
858 entryList.href.erase((entryList.href.size() - 1));
859 entryList.tag.erase((entryList.href.size() - 1));
860 entryList.data.erase((entryList.href.size() - 1));
866 // Build the list into a new list for getting the new
867 // calendar data with.
869 entryListRequest.clear();
871 entryListRequest = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
873 entryListRequest += "<c:calendar-multiget xmlns:d=\"DAV:\" "
874 " xmlns:c=\"urn:ietf:params:xml:ns:caldav\">\n"
877 " <c:calendar-data />\n"
880 for (std::map<int,string>::iterator hrefIter = entryList.href.begin();
881 hrefIter != entryList.href.end(); hrefIter++){
883 string entryListHREFString = hrefIter->second;
885 entryListRequest += " <d:href>";
886 entryListRequest += entryListHREFString;
887 entryListRequest += "</d:href>\n";
891 entryListRequest += "</c:calendar-multiget>";
893 CalDAVSendData updatedEntryListSendData;
895 updatedEntryListSendData.readptr = &entryListRequest;
896 updatedEntryListSendData.sizeleft = entryListRequest.size();
898 curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, entryListRequestHeader);
899 curl_easy_setopt(connectionHandle, CURLOPT_URL, entryListURLAddress.c_str());
900 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, "REPORT");
901 curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 1L);
902 curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
903 curl_easy_setopt(connectionHandle, CURLOPT_READDATA, &updatedEntryListSendData);
904 curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, CalDAVSend);
906 // Get the updated calendar data.
909 serverHeader.clear();
910 entryList.href.clear();
911 entryList.tag.clear();
912 entryList.data.clear();
914 serverResult = curl_easy_perform(connectionHandle);
916 // Check the last entry matches the HREF and if it
917 // does then delete it.
919 if (serverResult == CURLE_OK){
920 connectionServerResult.result = CALDAVQUERYRESULT_OK;
922 connectionServerResult.result = CALDAVQUERYRESULT_SERVERERROR;
924 connectionServerResult.code = serverResult;
925 curl_easy_getinfo(connectionHandle, CURLINFO_RESPONSE_CODE, &connectionServerResult.httpCode);
927 if (serverResult != CURLE_OK){
933 entryList = ProcessXMLEntryList();
935 // Second query: Get the list of contact data for the contacts that have
938 // Restore the original settings.
940 string originalServerAddress = BuildServerAddress(&connectionData, "/principals/");
942 curl_easy_setopt(connectionHandle, CURLOPT_URL, originalServerAddress.c_str());
943 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, NULL);
944 curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 0L);
945 curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
946 curl_easy_setopt(connectionHandle, CURLOPT_READDATA, NULL);
947 curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, NULL);
953 CalDAVServerResult CalDAV::AddCalendar(string calendarName){
955 CalDAVServerResult serverResult;
957 AddCalendar(&calendarName, nullptr);
963 CalDAVServerResult CalDAV::AddCalendar(string *calendarName, string *calendarShortName){
965 CalDAVServerResult serverResult;
966 CalDAVSendData calendarAddSendData;
968 // Build the server address.
970 string userPrincipalURI = "";
971 userPrincipalURI = GetUserPrincipal();
973 if (userPrincipalURI.size() == 0){
979 string calendarHomeURI = "";
980 calendarHomeURI = GetCalendarHome(userPrincipalURI);
982 // Generate the UUID.
984 string UUIDValue = "";
986 if (calendarShortName == nullptr){
988 UUIDValue = GenerateUUID();
989 UUIDValue.erase(UUIDValue.end()-1);
993 UUIDValue = *calendarShortName;
997 string calendarHomeURL = calendarHomeURI;
998 calendarHomeURL.append(UUIDValue);
999 calendarHomeURL.append("/");
1001 // Build the calendar list address.
1003 string calendarListURLAddress = BuildServerAddress(&connectionData, calendarHomeURL);
1005 string calendarAddRequest = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
1006 "<c:mkcalendar xmlns:d=\"DAV:\" xmlns:c=\"urn:ietf:params:xml:ns:caldav\">\n"
1010 calendarAddRequest += *calendarName;
1011 calendarAddRequest += "</d:displayname>\n"
1012 " <c:supported-calendar-component-set>\n"
1013 " <c:comp name=\"VTODO\"/>\n"
1014 " <c:comp name=\"VEVENT\"/>\n"
1015 " </c:supported-calendar-component-set>\n"
1020 calendarAddSendData.readptr = &calendarAddRequest;
1021 calendarAddSendData.sizeleft = calendarAddRequest.size();
1023 // Setup the header.
1025 struct curl_slist *calendarRequestHeader = NULL;
1027 //curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, CalendarRequestHeader);
1028 curl_easy_setopt(connectionHandle, CURLOPT_URL, calendarListURLAddress.c_str());
1029 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, "MKCALENDAR");
1030 curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 1L);
1031 curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
1032 curl_easy_setopt(connectionHandle, CURLOPT_READDATA, &calendarAddSendData);
1033 curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, CalDAVSend);
1035 // Process the data.
1038 serverHeader.clear();
1040 CURLcode serverConnectionResult = curl_easy_perform(connectionHandle);
1042 if (serverConnectionResult == CURLE_OK){
1043 serverResult.result = CALDAVQUERYRESULT_OK;
1045 serverResult.result = CALDAVQUERYRESULT_SERVERERROR;
1047 serverResult.code = serverConnectionResult;
1048 curl_easy_getinfo(connectionHandle, CURLINFO_RESPONSE_CODE, &serverResult.httpCode);
1050 // Restore the original settings.
1052 string originalServerAddress = BuildServerAddress(&connectionData, "/principals/");
1053 curl_easy_setopt(connectionHandle, CURLOPT_URL, originalServerAddress.c_str());
1054 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, NULL);
1055 curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 0L);
1056 curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
1057 curl_easy_setopt(connectionHandle, CURLOPT_READDATA, NULL);
1058 curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, NULL);
1060 return serverResult;
1064 CalDAVServerResult CalDAV::EditCalendarProcess(string *calendarHREF,
1065 string *calendarName,
1066 Colour *calendarColour,
1067 string *calendarDescription,
1068 int *calendarOrder){
1070 CalDAVServerResult serverResult;
1071 CalDAVSendData calendarEditSendData;
1073 // Build the server address.
1075 string userPrincipalURI = "";
1076 userPrincipalURI = GetUserPrincipal();
1078 if (userPrincipalURI.size() == 0){
1080 return serverResult;
1084 string calendarHomeURI = "";
1085 calendarHomeURI = GetCalendarHome(userPrincipalURI);
1087 // Generate the UUID.
1089 string UUIDValue = GenerateUUID();
1090 UUIDValue.erase(UUIDValue.end()-1);
1092 string calendarHomeURL = calendarHomeURI;
1093 calendarHomeURL.append(UUIDValue);
1094 calendarHomeURL.append("/");
1096 // Build the calendar list address.
1098 string calendarEditURLAddress = BuildServerAddress(&connectionData, (*calendarHREF));
1100 string calendarEditRequest = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
1101 "<d:propertyupdate xmlns:d=\"DAV:\" xmlns:c=\"urn:ietf:params:xml:ns:caldav\"\n"
1102 " xmlns:x0=\"http://apple.com/ns/ical/\">\n"
1106 // Update the calendar name.
1108 if (calendarName != nullptr){
1110 calendarEditRequest += "<d:displayname>";
1111 calendarEditRequest += (*calendarName);
1112 calendarEditRequest += "</d:displayname>\n";
1116 // Update the calendar colour.
1118 if (calendarColour != nullptr){
1120 calendarEditRequest += "<x0:calendar-color>";
1121 calendarEditRequest += (*calendarColour);
1122 calendarEditRequest += "</x0:calendar-color>\n";
1126 // Update the calendar description.
1128 if (calendarDescription != nullptr){
1130 calendarEditRequest += "<c:calendar-description>";
1131 calendarEditRequest += (*calendarDescription);
1132 calendarEditRequest += "</c:calendar-description>\n";
1136 // Update the calendar order.
1138 if (calendarOrder != nullptr){
1140 calendarEditRequest += "<x0:calendar-order>";
1141 calendarEditRequest += to_string((*calendarOrder));
1142 calendarEditRequest += "</x0:calendar-order>\n";
1146 calendarEditRequest += " </d:prop>\n"
1148 "</d:propertyupdate>";
1150 calendarEditSendData.readptr = &calendarEditRequest;
1151 calendarEditSendData.sizeleft = calendarEditRequest.size();
1153 // Setup the header.
1155 struct curl_slist *calendarRequestHeader = NULL;
1157 //curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, CalendarRequestHeader);
1158 curl_easy_setopt(connectionHandle, CURLOPT_URL, calendarEditURLAddress.c_str());
1159 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, "PROPPATCH");
1160 curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 1L);
1161 curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
1162 curl_easy_setopt(connectionHandle, CURLOPT_READDATA, &calendarEditSendData);
1163 curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, CalDAVSend);
1165 // Process the data.
1168 serverHeader.clear();
1170 CURLcode serverConnectionResult = curl_easy_perform(connectionHandle);
1172 if (serverConnectionResult == CURLE_OK){
1173 serverResult.result = CALDAVQUERYRESULT_OK;
1175 serverResult.result = CALDAVQUERYRESULT_SERVERERROR;
1177 serverResult.code = serverConnectionResult;
1178 curl_easy_getinfo(connectionHandle, CURLINFO_RESPONSE_CODE, &serverResult.httpCode);
1180 // Restore the original settings.
1182 string originalServerAddress = BuildServerAddress(&connectionData, "/principals/");
1183 curl_easy_setopt(connectionHandle, CURLOPT_URL, originalServerAddress.c_str());
1184 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, NULL);
1185 curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 0L);
1186 curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
1187 curl_easy_setopt(connectionHandle, CURLOPT_READDATA, NULL);
1188 curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, NULL);
1190 return serverResult;
1194 CalDAVServerResult CalDAV::EditCalendar(string *calendarHREF,
1195 string *calendarName,
1196 Colour *calendarColour,
1197 string *calendarDescription,
1198 int *calendarOrder){
1200 CalDAVServerResult serverResult;
1202 serverResult = EditCalendarProcess(calendarHREF,
1205 calendarDescription,
1208 return serverResult;
1212 CalDAVServerResult CalDAV::EditCalendar(string *calendarHREF,
1213 Colour *calendarColour){
1215 CalDAVServerResult serverResult;
1217 serverResult = EditCalendarProcess(calendarHREF,
1223 return serverResult;
1227 CalDAVServerResult CalDAV::EditCalendar(string *calendarHREF,
1228 string *calendarName){
1230 CalDAVServerResult serverResult;
1232 serverResult = EditCalendarProcess(calendarHREF,
1238 return serverResult;
1242 CalDAVServerResult CalDAV::EditCalendar(string *calendarHREF,
1243 int *calendarOrder){
1245 CalDAVServerResult serverResult;
1247 serverResult = EditCalendarProcess(calendarHREF,
1253 return serverResult;
1257 CalDAVServerResult CalDAV::EditCalendarDescription(string *calendarHREF,
1258 string *calendarDescription){
1260 CalDAVServerResult serverResult;
1262 serverResult = EditCalendarProcess(calendarHREF,
1265 calendarDescription,
1268 return serverResult;
1272 CalDAVServerResult CalDAV::DeleteCalendar(string *calendarHREF){
1274 CalDAVServerResult serverResult;
1276 // Build the server address.
1278 string userPrincipalURI = "";
1279 userPrincipalURI = GetUserPrincipal();
1281 if (userPrincipalURI.size() == 0){
1283 return serverResult;
1287 string calendarHomeURI = "";
1288 calendarHomeURI = GetCalendarHome(userPrincipalURI);
1290 // Generate the UUID.
1292 string UUIDValue = GenerateUUID();
1293 UUIDValue.erase(UUIDValue.end()-1);
1295 string calendarHomeURL = calendarHomeURI;
1296 calendarHomeURL.append(UUIDValue);
1297 calendarHomeURL.append("/");
1299 // Build the calendar list address.
1301 struct curl_slist *deleteRequestHeader = NULL;
1303 deleteRequestHeader = curl_slist_append(deleteRequestHeader, "Depth: infinity");
1305 string calendarDeleteURLAddress = BuildServerAddress(&connectionData, (*calendarHREF));
1307 curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, deleteRequestHeader);
1308 curl_easy_setopt(connectionHandle, CURLOPT_URL, calendarDeleteURLAddress.c_str());
1309 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, "DELETE");
1311 // Delete the calendar.
1314 serverHeader.clear();
1316 CURLcode serverConnectionResult = curl_easy_perform(connectionHandle);
1318 if (serverConnectionResult == CURLE_OK){
1319 serverResult.result = CALDAVQUERYRESULT_OK;
1321 serverResult.result = CALDAVQUERYRESULT_SERVERERROR;
1323 serverResult.code = serverConnectionResult;
1324 curl_easy_getinfo(connectionHandle, CURLINFO_RESPONSE_CODE, &serverResult.httpCode);
1326 // Restore the original settings.
1328 string originalServerAddress = BuildServerAddress(&connectionData, "/principals/");
1329 curl_easy_setopt(connectionHandle, CURLOPT_URL, originalServerAddress.c_str());
1330 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, NULL);
1331 curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 0L);
1332 curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
1333 curl_easy_setopt(connectionHandle, CURLOPT_READDATA, NULL);
1334 curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, NULL);
1335 curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, NULL);
1337 return serverResult;
1341 CalDAVServerResult CalDAV::GetEntryETag(string *calendarEntryHREF, string *eTagValue){
1343 CalDAVServerResult serverResult;
1344 CalDAVSendData entryETagGetData;
1346 // Build the server address.
1348 string userPrincipalURI = "";
1349 userPrincipalURI = GetUserPrincipal();
1351 if (userPrincipalURI.size() == 0){
1353 return serverResult;
1357 string calendarHomeURI = "";
1358 calendarHomeURI = GetCalendarHome(userPrincipalURI);
1360 // Split the path and filename.
1362 string entryURIPath;
1363 string entryFilename;
1365 SplitPathFilename(calendarEntryHREF, &entryURIPath, &entryFilename);
1367 // Build the request for the server.
1369 string entryETagRequest = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
1370 "<c:calendar-multiget xmlns:d=\"DAV:\" xmlns:c=\"urn:ietf:params:xml:ns:caldav\">\n"
1375 entryETagRequest += (*calendarEntryHREF);
1376 entryETagRequest += "</d:href>\n"
1377 "</c:calendar-multiget>";
1379 entryETagGetData.readptr = &entryETagRequest;
1380 entryETagGetData.sizeleft = entryETagRequest.size();
1382 // Build the calendar list address.
1384 struct curl_slist *getETagRequestHeader = NULL;
1386 getETagRequestHeader = curl_slist_append(getETagRequestHeader, "Depth: 1");
1387 getETagRequestHeader = curl_slist_append(getETagRequestHeader, "Prefer: return-minimal");
1388 getETagRequestHeader = curl_slist_append(getETagRequestHeader, "Content-Type: application/xml; charset=utf-8");
1390 string getETagURLAddress = BuildServerAddress(&connectionData, entryURIPath);
1392 curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, getETagRequestHeader);
1393 curl_easy_setopt(connectionHandle, CURLOPT_URL, getETagURLAddress.c_str());
1394 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, "REPORT");
1395 curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 1L);
1396 curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
1397 curl_easy_setopt(connectionHandle, CURLOPT_READDATA, &entryETagGetData);
1398 curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, CalDAVSend);
1400 // Attempt to get the entity tag.
1403 serverHeader.clear();
1405 CURLcode serverConnectionResult = curl_easy_perform(connectionHandle);
1407 if (serverConnectionResult == CURLE_OK){
1408 serverResult.result = CALDAVQUERYRESULT_OK;
1410 serverResult.result = CALDAVQUERYRESULT_SERVERERROR;
1412 serverResult.code = serverConnectionResult;
1413 curl_easy_getinfo(connectionHandle, CURLINFO_RESPONSE_CODE, &serverResult.httpCode);
1415 if (serverConnectionResult != CURLE_OK){
1416 return serverResult;
1419 // Get the entity tag from the result.
1421 *eTagValue = ProcessXMLEntryETag();
1423 // Restore the original settings.
1425 string originalServerAddress = BuildServerAddress(&connectionData, "/principals/");
1426 curl_easy_setopt(connectionHandle, CURLOPT_URL, originalServerAddress.c_str());
1427 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, NULL);
1428 curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 0L);
1429 curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
1430 curl_easy_setopt(connectionHandle, CURLOPT_READDATA, NULL);
1431 curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, NULL);
1432 curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, NULL);
1434 return serverResult;
1438 CalDAVServerResult CalDAV::AddEntry(string *calendarEntryHREF, string *entryData){
1440 // Add an entry to the calendar collection.
1442 CalDAVServerResult serverResult;
1443 CalDAVSendData entryAddSendData;
1445 // Build the calendar list address.
1447 string entryAddURLAddress = BuildServerAddress(&connectionData, (*calendarEntryHREF));
1449 entryAddSendData.readptr = entryData;
1450 entryAddSendData.sizeleft = entryData->size();
1452 struct curl_slist *calendarRequestHeader = NULL;
1454 calendarRequestHeader = curl_slist_append(calendarRequestHeader, "Content-Type: text/calendar; charset=utf-8");
1456 curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, calendarRequestHeader);
1457 curl_easy_setopt(connectionHandle, CURLOPT_URL, entryAddURLAddress.c_str());
1458 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, "PUT");
1459 curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 1L);
1460 curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
1461 curl_easy_setopt(connectionHandle, CURLOPT_READDATA, &entryAddSendData);
1462 curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, CalDAVSend);
1464 // Process the data.
1467 serverHeader.clear();
1469 CURLcode serverConnectionResult = curl_easy_perform(connectionHandle);
1471 if (serverConnectionResult == CURLE_OK){
1472 serverResult.result = CALDAVQUERYRESULT_OK;
1474 serverResult.result = CALDAVQUERYRESULT_SERVERERROR;
1476 serverResult.code = serverConnectionResult;
1477 curl_easy_getinfo(connectionHandle, CURLINFO_RESPONSE_CODE, &serverResult.httpCode);
1479 // Restore the original settings.
1481 string originalServerAddress = BuildServerAddress(&connectionData, "/principals/");
1482 curl_easy_setopt(connectionHandle, CURLOPT_URL, originalServerAddress.c_str());
1483 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, NULL);
1484 curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 0L);
1485 curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
1486 curl_easy_setopt(connectionHandle, CURLOPT_READDATA, NULL);
1487 curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, NULL);
1488 curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, NULL);
1490 return serverResult;
1494 CalDAVServerResult CalDAV::EditEntry(string *calendarEntryHREF, string *entryData, string *entryETag){
1496 // Edit an entry in the calendar collection.
1498 // Add an entry to the calendar collection.
1500 CalDAVServerResult serverResult;
1501 CalDAVSendData entryAddSendData;
1503 // Build the calendar list address.
1505 string entryAddURLAddress = BuildServerAddress(&connectionData, (*calendarEntryHREF));
1507 entryAddSendData.readptr = entryData;
1508 entryAddSendData.sizeleft = entryData->size();
1510 string ifMatchHeader = "If-Match: \"";
1511 ifMatchHeader.append(*entryETag);
1512 ifMatchHeader.append("\"");
1514 struct curl_slist *calendarRequestHeader = NULL;
1516 calendarRequestHeader = curl_slist_append(calendarRequestHeader, "Content-Type: text/calendar; charset=utf-8");
1517 calendarRequestHeader = curl_slist_append(calendarRequestHeader, ifMatchHeader.c_str());
1519 curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, calendarRequestHeader);
1520 curl_easy_setopt(connectionHandle, CURLOPT_URL, entryAddURLAddress.c_str());
1521 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, "PUT");
1522 curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 1L);
1523 curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
1524 curl_easy_setopt(connectionHandle, CURLOPT_READDATA, &entryAddSendData);
1525 curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, CalDAVSend);
1527 // Process the data.
1530 serverHeader.clear();
1532 CURLcode serverConnectionResult = curl_easy_perform(connectionHandle);
1534 if (serverConnectionResult == CURLE_OK){
1535 serverResult.result = CALDAVQUERYRESULT_OK;
1537 serverResult.result = CALDAVQUERYRESULT_SERVERERROR;
1539 serverResult.code = serverConnectionResult;
1540 curl_easy_getinfo(connectionHandle, CURLINFO_RESPONSE_CODE, &serverResult.httpCode);
1542 // Restore the original settings.
1544 string originalServerAddress = BuildServerAddress(&connectionData, "/principals/");
1545 curl_easy_setopt(connectionHandle, CURLOPT_URL, originalServerAddress.c_str());
1546 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, NULL);
1547 curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 0L);
1548 curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
1549 curl_easy_setopt(connectionHandle, CURLOPT_READDATA, NULL);
1550 curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, NULL);
1551 curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, NULL);
1553 return serverResult;
1557 CalDAVServerResult CalDAV::DeleteEntry(string *calendarEntryHREF){
1559 // Delete an entry in the calendar collection.
1561 CalDAVServerResult serverResult;
1563 // Build the calendar list address.
1565 string entryDeleteURLAddress = BuildServerAddress(&connectionData, (*calendarEntryHREF));
1567 curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, NULL);
1568 curl_easy_setopt(connectionHandle, CURLOPT_URL, entryDeleteURLAddress.c_str());
1569 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, "DELETE");
1571 // Delete the calendar.
1574 serverHeader.clear();
1576 CURLcode serverConnectionResult = curl_easy_perform(connectionHandle);
1578 if (serverConnectionResult == CURLE_OK){
1579 serverResult.result = CALDAVQUERYRESULT_OK;
1581 serverResult.result = CALDAVQUERYRESULT_SERVERERROR;
1583 serverResult.code = serverConnectionResult;
1584 curl_easy_getinfo(connectionHandle, CURLINFO_RESPONSE_CODE, &serverResult.httpCode);
1586 // Restore the original settings.
1588 string originalServerAddress = BuildServerAddress(&connectionData, "/principals/");
1589 curl_easy_setopt(connectionHandle, CURLOPT_URL, originalServerAddress.c_str());
1590 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, NULL);
1591 curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 0L);
1592 curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
1593 curl_easy_setopt(connectionHandle, CURLOPT_READDATA, NULL);
1594 curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, NULL);
1595 curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, NULL);
1597 return serverResult;
1601 COSSLVerified CalDAV::SSLVerify()
1606 void CalDAV::BypassSSLVerification(bool enableBypass){
1607 enableSSLBypass = enableBypass;
1608 sslSelfSigned = enableBypass;
1611 #if defined(__APPLE__)
1613 SecTrustRef CalDAV::BuildSSLCollection(){
1615 return certificateData;
1619 #elif defined(__WIN32__)
1621 PCCERT_CONTEXT CalDAV::BuildSSLCollection(){
1623 return certificateData;
1629 SSLCertCollectionString CalDAV::BuildSSLCollection(){
1631 // Build and return the SSL collection.
1633 SSLCertCollectionString sslCertInfo;
1635 // Grab the certificate data.
1638 struct curl_slist *certdata;
1639 struct curl_certinfo *certinfo;
1642 certptr.certdata = NULL;
1644 CURLcode result = curl_easy_getinfo(connectionHandle, CURLINFO_CERTINFO, &certptr.certinfo);
1646 std::string certPropName;
1647 std::string certPropValue;
1649 for (int i = 0; i < certptr.certinfo->num_of_certs; i++){
1651 struct curl_slist *slist;
1652 SSLCertDataString sslCertDataInc;
1654 for (slist = certptr.certinfo->certinfo[i]; slist; slist = slist->next){
1656 // Using wxStringTokenizer from wxWidgets.
1658 wxStringTokenizer certDataInc(wxString::FromUTF8(slist->data), ":");
1660 // Get first token as the property name.
1662 certPropName = certDataInc.GetNextToken().ToStdString();
1664 // Get remaining tokens as the property value.
1666 while(certDataInc.HasMoreTokens()){
1668 certPropValue.append(certDataInc.GetNextToken());
1672 sslCertDataInc.CertData.insert(std::make_pair(certPropName, certPropValue));
1673 certPropName.clear();
1674 certPropValue.clear();
1678 sslCertInfo.SSLCollection.insert(std::make_pair(i, sslCertDataInc));
1688 bool CalDAV::CanDoSSL(){
1692 bool CalDAV::HasValidResponse(){
1693 return validResponse;
1696 bool CalDAV::AbleToLogin(){
1700 bool CalDAV::IsSelfSigned(){
1701 return sslSelfSigned;
1704 string CalDAV::GetErrorMessage(){
1706 errorMessage = sessionErrorBuffer;
1707 return errorMessage;
1711 static bool CalDAVObjectValidSettings(CalDAVConnectionData *connData){
1713 // Check if the passed CalDAV Connection Data is has
1714 // an address set. Return false if nullptr is used.
1716 if (connData == nullptr){
1722 // Check the server hostname. Return false
1723 // if no value has been set.
1725 if (connData->hostname.size() == 0){
1731 // Check the server port. Return false if
1732 // no value has been set or the port number
1733 // is less than 1 or higher than 65535.
1735 if (connData->port < 1 || connData->port > 65535){
1741 // Check the server username. Return false
1742 // if no value has been set.
1744 if (connData->username.size() == 0){
1750 // Check the server password. Return false
1751 // if no value has been set.
1753 if (connData->password.size() == 0){
1759 // Cannot check UseSSL: It is either true
1762 // Cannot check Prefix: The prefix may need
1763 // to be worked out first.
1765 // No errors were found whilst checking so
1772 string CalDAV::BuildServerAddress(CalDAVConnectionData *connData, string uriAddress){
1774 string serverAddress;
1776 // Setup the server address.
1778 if (connData->useSSL == true){
1779 serverAddress += "https://";
1781 serverAddress += "http://";
1784 serverAddress += connData->hostname;
1786 // Check if server port is 80, otherwise
1787 // specifiy the port number in the address.
1789 if (connData->port != 80){
1790 serverAddress += ":";
1791 serverAddress += to_string(connData->port);
1794 serverAddress += uriAddress;
1796 return serverAddress;
1800 void CalDAV::SetupDefaultParametersNonSSL(bool doAuthentication){
1802 std::string serverAddress = "";
1804 string serverAddressURL = "http://" + connectionData.hostname + ":" + to_string(connectionData.port) + "/";
1805 string usernamePassword = connectionData.username + ":" + connectionData.password;
1807 curl_easy_setopt(connectionHandle, CURLOPT_URL, serverAddressURL.c_str());
1808 curl_easy_setopt(connectionHandle, CURLOPT_NOPROGRESS, 1L);
1809 curl_easy_setopt(connectionHandle, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST|CURLAUTH_BASIC);
1810 curl_easy_setopt(connectionHandle, CURLOPT_TIMEOUT, 60);
1811 curl_easy_setopt(connectionHandle, CURLOPT_FAILONERROR, true);
1812 curl_easy_setopt(connectionHandle, CURLOPT_USERAGENT, XSDCAL_USERAGENT);
1813 curl_easy_setopt(connectionHandle, CURLOPT_NOSIGNAL, 1L);
1814 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, "GET");
1815 curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, nullptr);
1816 curl_easy_setopt(connectionHandle, CURLOPT_POSTFIELDS, nullptr);
1817 curl_easy_setopt(connectionHandle, CURLOPT_POSTFIELDSIZE, 0L);
1819 if (doAuthentication == true){
1820 curl_easy_setopt(connectionHandle, CURLOPT_USERPWD, usernamePassword.c_str());
1822 curl_easy_setopt(connectionHandle, CURLOPT_USERPWD, NULL);
1827 void CalDAV::SetupDefaultParametersSSL(bool doAuthentication){
1829 // Setup the default parameters.
1831 string ServerAddressURL = "https://" + connectionData.hostname + ":" + to_string(connectionData.port) + "/";
1832 string UsernamePassword = connectionData.username + ":" + connectionData.password;
1834 curl_easy_setopt(connectionHandle, CURLOPT_URL, ServerAddressURL.c_str());
1835 curl_easy_setopt(connectionHandle, CURLOPT_NOPROGRESS, 1L);
1836 curl_easy_setopt(connectionHandle, CURLOPT_CERTINFO, 1L);
1837 curl_easy_setopt(connectionHandle, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST|CURLAUTH_BASIC);
1838 curl_easy_setopt(connectionHandle, CURLOPT_TIMEOUT, 60);
1839 curl_easy_setopt(connectionHandle, CURLOPT_FAILONERROR, 0L);
1840 curl_easy_setopt(connectionHandle, CURLOPT_USERAGENT, XSDCAL_USERAGENT);
1841 curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
1842 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, "GET");
1843 curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, nullptr);
1844 curl_easy_setopt(connectionHandle, CURLOPT_POSTFIELDS, nullptr);
1845 curl_easy_setopt(connectionHandle, CURLOPT_POSTFIELDSIZE, 0L);
1847 if (doAuthentication == true){
1848 curl_easy_setopt(connectionHandle, CURLOPT_USERPWD, UsernamePassword.c_str());
1850 curl_easy_setopt(connectionHandle, CURLOPT_USERPWD, NULL);
1853 if (enableSSLBypass == true){
1854 curl_easy_setopt(connectionHandle, CURLOPT_SSL_VERIFYHOST, 0L);
1855 curl_easy_setopt(connectionHandle, CURLOPT_SSL_VERIFYPEER, 0L);
1856 curl_easy_setopt(connectionHandle, CURLOPT_SSL_VERIFYSTATUS, 0L);
1858 curl_easy_setopt(connectionHandle, CURLOPT_SSL_VERIFYHOST, 2L);
1859 curl_easy_setopt(connectionHandle, CURLOPT_SSL_VERIFYPEER, 1L);
1860 curl_easy_setopt(connectionHandle, CURLOPT_SSL_VERIFYSTATUS, 1L);
1863 #if !defined(__APPLE__) || defined(__WIN32__)
1865 if (connectionData.account.size() > 0){
1867 // Check if the server certificate file exists.
1869 string certificateFilename = GetAccountDir(connectionData.account, true);
1871 if (wxFile::Exists(certificateFilename)){
1873 curl_easy_setopt(connectionHandle, CURLOPT_CAINFO, certificateFilename.c_str());
1883 void CalDAV::ResetResults(){
1886 COSSLVerified SSLVerified = COSSL_NORESULT;
1887 validResponse = false;
1889 sslSelfSigned = false;
1890 //taskCompleted = false;
1892 sessionErrorBuffer[0] = '\0';
1893 //sessionResult = CURLE_OK;
1896 /*if (headerList != nullptr){
1897 curl_slist_free_all(headerList);
1898 headerList = nullptr;