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 case CURLE_HTTP_RETURNED_ERROR:
205 if (connectionData.useSSL)
207 sslStatus = connectionData.useSSL;
208 sslVerified = COSSL_VERIFIED;
210 serverResult.result = CALDAVQUERYRESULT_OK;
211 if (serverResult.httpCode == 401)
216 case CURLE_SSL_CACERT:
217 case CURLE_SSL_CONNECT_ERROR:
218 if (connectionData.useSSL)
220 sslStatus = connectionData.useSSL;
221 sslVerified = COSSL_UNABLETOVERIFY;
223 serverResult.result = CALDAVQUERYRESULT_SSLFAILURE;
227 serverResult.result = CALDAVQUERYRESULT_SERVERERROR;
232 // Set the certificate data (if required).
234 #if defined(__APPLE__)
236 if (connectionData.useSSL) {
238 certificateData = PageHeaderObject.SSLContext;
242 #elif defined(__WIN32__)
244 if (connectionData.useSSL) {
246 certificateData = PageHeaderObject.SSLContext;
252 // Check if a valid response was received before continuing.
254 if (serverResult.httpCode >= 200 && serverResult.httpCode <= 299)
256 validResponse = true;
263 CalDAVServerResult CalDAV::GetServerResult(){
265 return connectionServerResult;
269 CalDAVServerSupport CalDAV::GetServerSupport(){
271 CalDAVServerSupport serverStatus;
273 // Setup the server connection.
275 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, "OPTIONS");
277 CURLcode serverResult = curl_easy_perform(connectionHandle);
281 if (serverResult == CURLE_OK){
282 connectionServerResult.result = CALDAVQUERYRESULT_OK;
284 connectionServerResult.result = CALDAVQUERYRESULT_SERVERERROR;
286 connectionServerResult.code = serverResult;
287 curl_easy_getinfo(connectionHandle, CURLINFO_RESPONSE_CODE, &connectionServerResult.httpCode);
289 if (serverResult != CURLE_OK){
293 // Check that the server header has data in,
294 // otherwise return an "empty" CalDAVServerSupport.
296 if (serverHeader.size() == 0){
300 // Process each line looking for the first DAV header
303 bool newlineMode = true;
307 for (int charSeek = 0; charSeek < serverHeader.size(); charSeek++){
309 if (newlineMode == true){
311 // Check if we have reached the end of the string.
313 if (charSeek >= serverHeader.size()){
319 // Check the first four letters to make sure
322 string davHeaderCheck = "";
325 davHeaderCheck = serverHeader.substr(charSeek, 4);
328 catch (out_of_range &oor){
332 if (davHeaderCheck == "DAV:"){
336 for (; charSeek < serverHeader.size(); charSeek++){
338 if (serverHeader[charSeek] == '\n'){
344 davLine.push_back(serverHeader[charSeek]);
356 if (serverHeader[charSeek] == '\n'){
364 // Process the DAV line.
366 vector<string> davLineData;
367 string davSegmentString;
369 for (int charSeek = 0; charSeek < davLine.size(); charSeek++){
371 if (davLine[charSeek] == ' '){
375 if (davLine[charSeek] == ','){
377 davLineData.push_back(davSegmentString);
378 davSegmentString.clear();
383 davSegmentString += davLine[charSeek];
387 // Process the DAV values and set each value
388 // to true as required.
390 for (int davItemSeek = 0;
391 davItemSeek < davLineData.size();
394 if (davLineData.at(davItemSeek) == "calendar-access"){
396 serverStatus.basicSupport = true;
402 // Reset the connection status.
404 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, NULL);
410 string CalDAV::GetUserPrincipal(){
412 string currentUserPrincipal = "";
413 string userPrincipalRequest = "";
414 CalDAVSendData userPrincipalSendData;
416 userPrincipalRequest = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
417 "<d:propfind xmlns:d=\"DAV:\">\n"
419 " <d:current-user-principal />\n"
423 userPrincipalSendData.readptr = &userPrincipalRequest;
424 userPrincipalSendData.sizeleft = userPrincipalRequest.size();
428 struct curl_slist *userPrincipalRequestHeader = NULL;
430 userPrincipalRequestHeader = curl_slist_append(userPrincipalRequestHeader, "Depth: 0");
431 userPrincipalRequestHeader = curl_slist_append(userPrincipalRequestHeader, "Prefer: return-minimal");
432 userPrincipalRequestHeader = curl_slist_append(userPrincipalRequestHeader, "Content-Type: application/xml; charset=utf-8");
434 curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, userPrincipalRequestHeader);
436 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, "PROPFIND");
437 curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 1L);
438 curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
439 curl_easy_setopt(connectionHandle, CURLOPT_READDATA, &userPrincipalSendData);
440 curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, CalDAVSend);
445 serverHeader.clear();
447 CURLcode serverResult = curl_easy_perform(connectionHandle);
451 if (serverResult == CURLE_OK){
452 connectionServerResult.result = CALDAVQUERYRESULT_OK;
454 connectionServerResult.result = CALDAVQUERYRESULT_SERVERERROR;
456 connectionServerResult.code = serverResult;
457 curl_easy_getinfo(connectionHandle, CURLINFO_RESPONSE_CODE, &connectionServerResult.httpCode);
459 if (serverResult != CURLE_OK){
461 return currentUserPrincipal;
465 // Process the User Principal from the ServerData.
467 currentUserPrincipal = ProcessXMLUserPrincipal();
469 // Reset the changed settings.
471 curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 0L);
472 curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
473 curl_easy_setopt(connectionHandle, CURLOPT_READDATA, NULL);
474 curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, NULL);
476 return currentUserPrincipal;
480 string CalDAV::GetCalendarHome(string userPrincipalURI){
482 string calendarHomeURI = "";
484 // Build the Calendar Home URL address.
486 string calendarHomeURL = BuildServerAddress(&connectionData, userPrincipalURI);
488 // Setup the header request.
490 CalDAVSendData calendarHomeSendData;
492 string calendarHomeRequest = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
493 "<d:propfind xmlns:d=\"DAV:\" xmlns:c=\"urn:ietf:params:xml:ns:caldav\">\n"
495 " <c:calendar-home-set />\n"
499 calendarHomeSendData.readptr = &calendarHomeRequest;
500 calendarHomeSendData.sizeleft = calendarHomeRequest.size();
504 struct curl_slist *calendarRequestHeader = NULL;
506 calendarRequestHeader = curl_slist_append(calendarRequestHeader, "Depth: 0");
507 calendarRequestHeader = curl_slist_append(calendarRequestHeader, "Prefer: return-minimal");
508 calendarRequestHeader = curl_slist_append(calendarRequestHeader, "Content-Type: application/xml; charset=utf-8");
510 curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, calendarRequestHeader);
511 curl_easy_setopt(connectionHandle, CURLOPT_URL, calendarHomeURL.c_str());
512 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, "PROPFIND");
513 curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 1L);
514 curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
515 curl_easy_setopt(connectionHandle, CURLOPT_READDATA, &calendarHomeSendData);
516 curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, CalDAVSend);
521 serverHeader.clear();
523 CURLcode serverResult = curl_easy_perform(connectionHandle);
527 if (serverResult == CURLE_OK){
528 connectionServerResult.result = CALDAVQUERYRESULT_OK;
530 connectionServerResult.result = CALDAVQUERYRESULT_SERVERERROR;
532 connectionServerResult.code = serverResult;
533 curl_easy_getinfo(connectionHandle, CURLINFO_RESPONSE_CODE, &connectionServerResult.httpCode);
535 if (serverResult != CURLE_OK){
537 return calendarHomeURI;
541 // Process the User Principal from the ServerData.
543 calendarHomeURI = ProcessXMLCalendarHome();
545 // Reset the changed settings.
547 string originalServerAddress = BuildServerAddress(&connectionData, "/principals/");
548 curl_easy_setopt(connectionHandle, CURLOPT_URL, originalServerAddress.c_str());
550 curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 0L);
551 curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
552 curl_easy_setopt(connectionHandle, CURLOPT_READDATA, NULL);
553 curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, NULL);
554 curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, NULL);
556 return calendarHomeURI;
560 CalDAVCalendarList CalDAV::GetCalendars(){
562 CalDAVCalendarList serverList;
563 CalDAVSendData calendarListSendData;
565 // Build the server address.
567 string userPrincipalURI = "";
568 userPrincipalURI = GetUserPrincipal();
570 if (userPrincipalURI.size() == 0){
576 string calendarHomeURI = "";
577 calendarHomeURI = GetCalendarHome(userPrincipalURI);
579 string calendarListURLAddress = BuildServerAddress(&connectionData, calendarHomeURI);
581 string calendarListRequest = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
582 "<d:propfind xmlns:d=\"DAV:\" xmlns:cs=\"http://calendarserver.org/ns/\""
583 " xmlns:c=\"urn:ietf:params:xml:ns:caldav\" xmlns:x0=\"http://apple.com/ns/ical/\">\n"
585 " <d:resourcetype />\n"
586 " <d:displayname />\n"
587 " <d:sync-token />\n"
588 " <x0:calendar-color />\n"
589 " <x0:calendar-order />\n"
591 " <c:supported-calendar-component-set />\n"
592 " <c:calendar-description />\n"
596 calendarListSendData.readptr = &calendarListRequest;
597 calendarListSendData.sizeleft = calendarListRequest.size();
601 struct curl_slist *calendarListRequestHeader = NULL;
603 calendarListRequestHeader = curl_slist_append(calendarListRequestHeader, "Depth: 1");
604 calendarListRequestHeader = curl_slist_append(calendarListRequestHeader, "Prefer: return-minimal");
605 calendarListRequestHeader = curl_slist_append(calendarListRequestHeader, "Content-Type: application/xml; charset=utf-8");
607 curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, calendarListRequestHeader);
608 curl_easy_setopt(connectionHandle, CURLOPT_URL, calendarListURLAddress.c_str());
609 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, "PROPFIND");
610 curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 1L);
611 curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
612 curl_easy_setopt(connectionHandle, CURLOPT_READDATA, &calendarListSendData);
613 curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, CalDAVSend);
618 serverHeader.clear();
620 CURLcode serverResult = curl_easy_perform(connectionHandle);
622 //ServerList = ProcessXMLCalendarList();
624 if (serverResult == CURLE_OK){
625 connectionServerResult.result = CALDAVQUERYRESULT_OK;
627 connectionServerResult.result = CALDAVQUERYRESULT_SERVERERROR;
629 connectionServerResult.code = serverResult;
630 curl_easy_getinfo(connectionHandle, CURLINFO_RESPONSE_CODE, &connectionServerResult.httpCode);
632 if (serverResult != CURLE_OK){
638 // Process the received XML data into a list of calendars
641 serverList = ProcessXMLCalendarList();
643 // Restore the original settings.
645 string originalServerAddress = BuildServerAddress(&connectionData, "/principals/");
647 curl_easy_setopt(connectionHandle, CURLOPT_URL, originalServerAddress.c_str());
648 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, NULL);
649 curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 0L);
650 curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
651 curl_easy_setopt(connectionHandle, CURLOPT_READDATA, NULL);
652 curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, NULL);
658 CalDAVEntryList CalDAV::GetEntryList(string *calendarHREF){
660 CalDAVEntryList entryList;
661 CalDAVSendData entryListSendData;
663 if (calendarHREF->size() == 0){
669 string entryListURLAddress = BuildServerAddress(&connectionData, *calendarHREF);
671 string entryListRequest = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
673 /*if (CalendarTag == nullptr){*/
675 entryListRequest += "<c:calendar-query xmlns:d=\"DAV:\" xmlns:cs=\"http://calendarserver.org/ns/\""
676 " xmlns:c=\"urn:ietf:params:xml:ns:caldav\" xmlns:x0=\"http://apple.com/ns/ical/\">\n"
679 " <c:calendar-data />\n"
682 " <c:comp-filter name=\"VCALENDAR\" />\n"
684 "</c:calendar-query>";
688 EntryListRequest += "<d:sync-collection xmlns:d=\"DAV:\" xmlns:cs=\"http://calendarserver.org/ns/\""
689 " xmlns:c=\"urn:ietf:params:xml:ns:caldav\" xmlns:x0=\"http://apple.com/ns/ical/\">\n"
691 EntryListRequest += *CalendarTag;
692 EntryListRequest += "</d:sync-token>\n"
693 " <d:sync-level>1</d:sync-level>\n"
696 " <c:calendar-data />\n"
698 "</d:sync-collection>";
702 entryListSendData.readptr = &entryListRequest;
703 entryListSendData.sizeleft = entryListRequest.size();
705 struct curl_slist *entryListRequestHeader = NULL;
707 entryListRequestHeader = curl_slist_append(entryListRequestHeader, "Content-Type: application/xml; charset=utf-8");
709 /*if (CalendarTag != nullptr){
711 EntryListRequestHeader = curl_slist_append(EntryListRequestHeader, "Content-Type: application/xml; charset=utf-8");
712 EntryListRequestHeader = curl_slist_append(EntryListRequestHeader, "Content-Type: application/xml; charset=utf-8");
716 curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, entryListRequestHeader);
717 curl_easy_setopt(connectionHandle, CURLOPT_URL, entryListURLAddress.c_str());
718 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, "REPORT");
719 curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 1L);
720 curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
721 curl_easy_setopt(connectionHandle, CURLOPT_READDATA, &entryListSendData);
722 curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, CalDAVSend);
727 serverHeader.clear();
729 CURLcode serverResult = curl_easy_perform(connectionHandle);
731 //ServerList = ProcessXMLCalendarList();
733 if (serverResult == CURLE_OK){
734 connectionServerResult.result = CALDAVQUERYRESULT_OK;
736 connectionServerResult.result = CALDAVQUERYRESULT_SERVERERROR;
738 connectionServerResult.code = serverResult;
739 curl_easy_getinfo(connectionHandle, CURLINFO_RESPONSE_CODE, &connectionServerResult.httpCode);
741 if (serverResult != CURLE_OK){
747 // Process the received XML data into a list of calendars
750 entryList = ProcessXMLEntryList();
752 // Restore the original settings.
754 string originalServerAddress = BuildServerAddress(&connectionData, "/principals/");
756 curl_easy_setopt(connectionHandle, CURLOPT_URL, originalServerAddress.c_str());
757 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, NULL);
758 curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 0L);
759 curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
760 curl_easy_setopt(connectionHandle, CURLOPT_READDATA, NULL);
761 curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, NULL);
767 CalDAVEntryList CalDAV::GetEntryList(string *calendarHREF, string *calendarTag){
769 CalDAVEntryList entryList;
770 CalDAVSendData entryListSendData;
772 if (calendarHREF->size() == 0){
778 string entryListURLAddress = BuildServerAddress(&connectionData, *calendarHREF);
780 // First query: Get the list of contacts that need to be updated.
782 string entryListRequest = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
784 entryListRequest += "<d:sync-collection xmlns:d=\"DAV:\" xmlns:cs=\"http://calendarserver.org/ns/\""
785 " xmlns:c=\"urn:ietf:params:xml:ns:caldav\" xmlns:x0=\"http://apple.com/ns/ical/\">\n"
788 if (calendarTag != nullptr){
790 entryListRequest += *calendarTag;
794 entryListRequest += "";
798 entryListRequest += "</d:sync-token>\n"
799 " <d:sync-level>1</d:sync-level>\n"
803 "</d:sync-collection>";
805 entryListSendData.readptr = &entryListRequest;
806 entryListSendData.sizeleft = entryListRequest.size();
808 struct curl_slist *entryListRequestHeader = NULL;
810 entryListRequestHeader = curl_slist_append(entryListRequestHeader, "Content-Type: application/xml; charset=utf-8");
812 curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, entryListRequestHeader);
813 curl_easy_setopt(connectionHandle, CURLOPT_URL, entryListURLAddress.c_str());
814 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, "REPORT");
815 curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 1L);
816 curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
817 curl_easy_setopt(connectionHandle, CURLOPT_READDATA, &entryListSendData);
818 curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, CalDAVSend);
823 serverHeader.clear();
825 CURLcode serverResult = curl_easy_perform(connectionHandle);
827 if (serverResult == CURLE_OK){
828 connectionServerResult.result = CALDAVQUERYRESULT_OK;
830 connectionServerResult.result = CALDAVQUERYRESULT_SERVERERROR;
832 connectionServerResult.code = serverResult;
833 curl_easy_getinfo(connectionHandle, CURLINFO_RESPONSE_CODE, &connectionServerResult.httpCode);
835 if (serverResult != CURLE_OK){
841 entryList = ProcessXMLSyncTokenList();
843 // Check the last entry matches the HREF and if it
844 // does then delete it.
846 if (entryList.href.size() > 0) {
848 if (entryList.href.rbegin()->second == *calendarHREF){
850 entryList.href.erase((entryList.href.size() - 1));
851 entryList.tag.erase((entryList.href.size() - 1));
852 entryList.data.erase((entryList.href.size() - 1));
858 // Build the list into a new list for getting the new
859 // calendar data with.
861 entryListRequest.clear();
863 entryListRequest = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
865 entryListRequest += "<c:calendar-multiget xmlns:d=\"DAV:\" "
866 " xmlns:c=\"urn:ietf:params:xml:ns:caldav\">\n"
869 " <c:calendar-data />\n"
872 for (std::map<int,string>::iterator hrefIter = entryList.href.begin();
873 hrefIter != entryList.href.end(); hrefIter++){
875 string entryListHREFString = hrefIter->second;
877 entryListRequest += " <d:href>";
878 entryListRequest += entryListHREFString;
879 entryListRequest += "</d:href>\n";
883 entryListRequest += "</c:calendar-multiget>";
885 CalDAVSendData updatedEntryListSendData;
887 updatedEntryListSendData.readptr = &entryListRequest;
888 updatedEntryListSendData.sizeleft = entryListRequest.size();
890 curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, entryListRequestHeader);
891 curl_easy_setopt(connectionHandle, CURLOPT_URL, entryListURLAddress.c_str());
892 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, "REPORT");
893 curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 1L);
894 curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
895 curl_easy_setopt(connectionHandle, CURLOPT_READDATA, &updatedEntryListSendData);
896 curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, CalDAVSend);
898 // Get the updated calendar data.
901 serverHeader.clear();
902 entryList.href.clear();
903 entryList.tag.clear();
904 entryList.data.clear();
906 serverResult = curl_easy_perform(connectionHandle);
908 // Check the last entry matches the HREF and if it
909 // does then delete it.
911 if (serverResult == CURLE_OK){
912 connectionServerResult.result = CALDAVQUERYRESULT_OK;
914 connectionServerResult.result = CALDAVQUERYRESULT_SERVERERROR;
916 connectionServerResult.code = serverResult;
917 curl_easy_getinfo(connectionHandle, CURLINFO_RESPONSE_CODE, &connectionServerResult.httpCode);
919 if (serverResult != CURLE_OK){
925 entryList = ProcessXMLEntryList();
927 // Second query: Get the list of contact data for the contacts that have
930 // Restore the original settings.
932 string originalServerAddress = BuildServerAddress(&connectionData, "/principals/");
934 curl_easy_setopt(connectionHandle, CURLOPT_URL, originalServerAddress.c_str());
935 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, NULL);
936 curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 0L);
937 curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
938 curl_easy_setopt(connectionHandle, CURLOPT_READDATA, NULL);
939 curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, NULL);
945 CalDAVServerResult CalDAV::AddCalendar(string calendarName){
947 CalDAVServerResult serverResult;
949 AddCalendar(&calendarName, nullptr);
955 CalDAVServerResult CalDAV::AddCalendar(string *calendarName, string *calendarShortName){
957 CalDAVServerResult serverResult;
958 CalDAVSendData calendarAddSendData;
960 // Build the server address.
962 string userPrincipalURI = "";
963 userPrincipalURI = GetUserPrincipal();
965 if (userPrincipalURI.size() == 0){
971 string calendarHomeURI = "";
972 calendarHomeURI = GetCalendarHome(userPrincipalURI);
974 // Generate the UUID.
976 string UUIDValue = "";
978 if (calendarShortName == nullptr){
980 UUIDValue = GenerateUUID();
981 UUIDValue.erase(UUIDValue.end()-1);
985 UUIDValue = *calendarShortName;
989 string calendarHomeURL = calendarHomeURI;
990 calendarHomeURL.append(UUIDValue);
991 calendarHomeURL.append("/");
993 // Build the calendar list address.
995 string calendarListURLAddress = BuildServerAddress(&connectionData, calendarHomeURL);
997 string calendarAddRequest = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
998 "<c:mkcalendar xmlns:d=\"DAV:\" xmlns:c=\"urn:ietf:params:xml:ns:caldav\">\n"
1002 calendarAddRequest += *calendarName;
1003 calendarAddRequest += "</d:displayname>\n"
1004 " <c:supported-calendar-component-set>\n"
1005 " <c:comp name=\"VTODO\"/>\n"
1006 " <c:comp name=\"VEVENT\"/>\n"
1007 " </c:supported-calendar-component-set>\n"
1012 calendarAddSendData.readptr = &calendarAddRequest;
1013 calendarAddSendData.sizeleft = calendarAddRequest.size();
1015 // Setup the header.
1017 struct curl_slist *calendarRequestHeader = NULL;
1019 //curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, CalendarRequestHeader);
1020 curl_easy_setopt(connectionHandle, CURLOPT_URL, calendarListURLAddress.c_str());
1021 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, "MKCALENDAR");
1022 curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 1L);
1023 curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
1024 curl_easy_setopt(connectionHandle, CURLOPT_READDATA, &calendarAddSendData);
1025 curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, CalDAVSend);
1027 // Process the data.
1030 serverHeader.clear();
1032 CURLcode serverConnectionResult = curl_easy_perform(connectionHandle);
1034 if (serverConnectionResult == CURLE_OK){
1035 serverResult.result = CALDAVQUERYRESULT_OK;
1037 serverResult.result = CALDAVQUERYRESULT_SERVERERROR;
1039 serverResult.code = serverConnectionResult;
1040 curl_easy_getinfo(connectionHandle, CURLINFO_RESPONSE_CODE, &serverResult.httpCode);
1042 // Restore the original settings.
1044 string originalServerAddress = BuildServerAddress(&connectionData, "/principals/");
1045 curl_easy_setopt(connectionHandle, CURLOPT_URL, originalServerAddress.c_str());
1046 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, NULL);
1047 curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 0L);
1048 curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
1049 curl_easy_setopt(connectionHandle, CURLOPT_READDATA, NULL);
1050 curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, NULL);
1052 return serverResult;
1056 CalDAVServerResult CalDAV::EditCalendarProcess(string *calendarHREF,
1057 string *calendarName,
1058 Colour *calendarColour,
1059 string *calendarDescription,
1060 int *calendarOrder){
1062 CalDAVServerResult serverResult;
1063 CalDAVSendData calendarEditSendData;
1065 // Build the server address.
1067 string userPrincipalURI = "";
1068 userPrincipalURI = GetUserPrincipal();
1070 if (userPrincipalURI.size() == 0){
1072 return serverResult;
1076 string calendarHomeURI = "";
1077 calendarHomeURI = GetCalendarHome(userPrincipalURI);
1079 // Generate the UUID.
1081 string UUIDValue = GenerateUUID();
1082 UUIDValue.erase(UUIDValue.end()-1);
1084 string calendarHomeURL = calendarHomeURI;
1085 calendarHomeURL.append(UUIDValue);
1086 calendarHomeURL.append("/");
1088 // Build the calendar list address.
1090 string calendarEditURLAddress = BuildServerAddress(&connectionData, (*calendarHREF));
1092 string calendarEditRequest = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
1093 "<d:propertyupdate xmlns:d=\"DAV:\" xmlns:c=\"urn:ietf:params:xml:ns:caldav\"\n"
1094 " xmlns:x0=\"http://apple.com/ns/ical/\">\n"
1098 // Update the calendar name.
1100 if (calendarName != nullptr){
1102 calendarEditRequest += "<d:displayname>";
1103 calendarEditRequest += (*calendarName);
1104 calendarEditRequest += "</d:displayname>\n";
1108 // Update the calendar colour.
1110 if (calendarColour != nullptr){
1112 calendarEditRequest += "<x0:calendar-color>";
1113 calendarEditRequest += (*calendarColour);
1114 calendarEditRequest += "</x0:calendar-color>\n";
1118 // Update the calendar description.
1120 if (calendarDescription != nullptr){
1122 calendarEditRequest += "<c:calendar-description>";
1123 calendarEditRequest += (*calendarDescription);
1124 calendarEditRequest += "</c:calendar-description>\n";
1128 // Update the calendar order.
1130 if (calendarOrder != nullptr){
1132 calendarEditRequest += "<x0:calendar-order>";
1133 calendarEditRequest += to_string((*calendarOrder));
1134 calendarEditRequest += "</x0:calendar-order>\n";
1138 calendarEditRequest += " </d:prop>\n"
1140 "</d:propertyupdate>";
1142 calendarEditSendData.readptr = &calendarEditRequest;
1143 calendarEditSendData.sizeleft = calendarEditRequest.size();
1145 // Setup the header.
1147 struct curl_slist *calendarRequestHeader = NULL;
1149 //curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, CalendarRequestHeader);
1150 curl_easy_setopt(connectionHandle, CURLOPT_URL, calendarEditURLAddress.c_str());
1151 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, "PROPPATCH");
1152 curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 1L);
1153 curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
1154 curl_easy_setopt(connectionHandle, CURLOPT_READDATA, &calendarEditSendData);
1155 curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, CalDAVSend);
1157 // Process the data.
1160 serverHeader.clear();
1162 CURLcode serverConnectionResult = curl_easy_perform(connectionHandle);
1164 if (serverConnectionResult == CURLE_OK){
1165 serverResult.result = CALDAVQUERYRESULT_OK;
1167 serverResult.result = CALDAVQUERYRESULT_SERVERERROR;
1169 serverResult.code = serverConnectionResult;
1170 curl_easy_getinfo(connectionHandle, CURLINFO_RESPONSE_CODE, &serverResult.httpCode);
1172 // Restore the original settings.
1174 string originalServerAddress = BuildServerAddress(&connectionData, "/principals/");
1175 curl_easy_setopt(connectionHandle, CURLOPT_URL, originalServerAddress.c_str());
1176 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, NULL);
1177 curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 0L);
1178 curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
1179 curl_easy_setopt(connectionHandle, CURLOPT_READDATA, NULL);
1180 curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, NULL);
1182 return serverResult;
1186 CalDAVServerResult CalDAV::EditCalendar(string *calendarHREF,
1187 string *calendarName,
1188 Colour *calendarColour,
1189 string *calendarDescription,
1190 int *calendarOrder){
1192 CalDAVServerResult serverResult;
1194 serverResult = EditCalendarProcess(calendarHREF,
1197 calendarDescription,
1200 return serverResult;
1204 CalDAVServerResult CalDAV::EditCalendar(string *calendarHREF,
1205 Colour *calendarColour){
1207 CalDAVServerResult serverResult;
1209 serverResult = EditCalendarProcess(calendarHREF,
1215 return serverResult;
1219 CalDAVServerResult CalDAV::EditCalendar(string *calendarHREF,
1220 string *calendarName){
1222 CalDAVServerResult serverResult;
1224 serverResult = EditCalendarProcess(calendarHREF,
1230 return serverResult;
1234 CalDAVServerResult CalDAV::EditCalendar(string *calendarHREF,
1235 int *calendarOrder){
1237 CalDAVServerResult serverResult;
1239 serverResult = EditCalendarProcess(calendarHREF,
1245 return serverResult;
1249 CalDAVServerResult CalDAV::EditCalendarDescription(string *calendarHREF,
1250 string *calendarDescription){
1252 CalDAVServerResult serverResult;
1254 serverResult = EditCalendarProcess(calendarHREF,
1257 calendarDescription,
1260 return serverResult;
1264 CalDAVServerResult CalDAV::DeleteCalendar(string *calendarHREF){
1266 CalDAVServerResult serverResult;
1268 // Build the server address.
1270 string userPrincipalURI = "";
1271 userPrincipalURI = GetUserPrincipal();
1273 if (userPrincipalURI.size() == 0){
1275 return serverResult;
1279 string calendarHomeURI = "";
1280 calendarHomeURI = GetCalendarHome(userPrincipalURI);
1282 // Generate the UUID.
1284 string UUIDValue = GenerateUUID();
1285 UUIDValue.erase(UUIDValue.end()-1);
1287 string calendarHomeURL = calendarHomeURI;
1288 calendarHomeURL.append(UUIDValue);
1289 calendarHomeURL.append("/");
1291 // Build the calendar list address.
1293 struct curl_slist *deleteRequestHeader = NULL;
1295 deleteRequestHeader = curl_slist_append(deleteRequestHeader, "Depth: infinity");
1297 string calendarDeleteURLAddress = BuildServerAddress(&connectionData, (*calendarHREF));
1299 curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, deleteRequestHeader);
1300 curl_easy_setopt(connectionHandle, CURLOPT_URL, calendarDeleteURLAddress.c_str());
1301 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, "DELETE");
1303 // Delete the calendar.
1306 serverHeader.clear();
1308 CURLcode serverConnectionResult = curl_easy_perform(connectionHandle);
1310 if (serverConnectionResult == CURLE_OK){
1311 serverResult.result = CALDAVQUERYRESULT_OK;
1313 serverResult.result = CALDAVQUERYRESULT_SERVERERROR;
1315 serverResult.code = serverConnectionResult;
1316 curl_easy_getinfo(connectionHandle, CURLINFO_RESPONSE_CODE, &serverResult.httpCode);
1318 // Restore the original settings.
1320 string originalServerAddress = BuildServerAddress(&connectionData, "/principals/");
1321 curl_easy_setopt(connectionHandle, CURLOPT_URL, originalServerAddress.c_str());
1322 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, NULL);
1323 curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 0L);
1324 curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
1325 curl_easy_setopt(connectionHandle, CURLOPT_READDATA, NULL);
1326 curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, NULL);
1327 curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, NULL);
1329 return serverResult;
1333 CalDAVServerResult CalDAV::GetEntryETag(string *calendarEntryHREF, string *eTagValue){
1335 CalDAVServerResult serverResult;
1336 CalDAVSendData entryETagGetData;
1338 // Build the server address.
1340 string userPrincipalURI = "";
1341 userPrincipalURI = GetUserPrincipal();
1343 if (userPrincipalURI.size() == 0){
1345 return serverResult;
1349 string calendarHomeURI = "";
1350 calendarHomeURI = GetCalendarHome(userPrincipalURI);
1352 // Split the path and filename.
1354 string entryURIPath;
1355 string entryFilename;
1357 SplitPathFilename(calendarEntryHREF, &entryURIPath, &entryFilename);
1359 // Build the request for the server.
1361 string entryETagRequest = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
1362 "<c:calendar-multiget xmlns:d=\"DAV:\" xmlns:c=\"urn:ietf:params:xml:ns:caldav\">\n"
1367 entryETagRequest += (*calendarEntryHREF);
1368 entryETagRequest += "</d:href>\n"
1369 "</c:calendar-multiget>";
1371 entryETagGetData.readptr = &entryETagRequest;
1372 entryETagGetData.sizeleft = entryETagRequest.size();
1374 // Build the calendar list address.
1376 struct curl_slist *getETagRequestHeader = NULL;
1378 getETagRequestHeader = curl_slist_append(getETagRequestHeader, "Depth: 1");
1379 getETagRequestHeader = curl_slist_append(getETagRequestHeader, "Prefer: return-minimal");
1380 getETagRequestHeader = curl_slist_append(getETagRequestHeader, "Content-Type: application/xml; charset=utf-8");
1382 string getETagURLAddress = BuildServerAddress(&connectionData, entryURIPath);
1384 curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, getETagRequestHeader);
1385 curl_easy_setopt(connectionHandle, CURLOPT_URL, getETagURLAddress.c_str());
1386 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, "REPORT");
1387 curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 1L);
1388 curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
1389 curl_easy_setopt(connectionHandle, CURLOPT_READDATA, &entryETagGetData);
1390 curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, CalDAVSend);
1392 // Attempt to get the entity tag.
1395 serverHeader.clear();
1397 CURLcode serverConnectionResult = curl_easy_perform(connectionHandle);
1399 if (serverConnectionResult == CURLE_OK){
1400 serverResult.result = CALDAVQUERYRESULT_OK;
1402 serverResult.result = CALDAVQUERYRESULT_SERVERERROR;
1404 serverResult.code = serverConnectionResult;
1405 curl_easy_getinfo(connectionHandle, CURLINFO_RESPONSE_CODE, &serverResult.httpCode);
1407 if (serverConnectionResult != CURLE_OK){
1408 return serverResult;
1411 // Get the entity tag from the result.
1413 *eTagValue = ProcessXMLEntryETag();
1415 // Restore the original settings.
1417 string originalServerAddress = BuildServerAddress(&connectionData, "/principals/");
1418 curl_easy_setopt(connectionHandle, CURLOPT_URL, originalServerAddress.c_str());
1419 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, NULL);
1420 curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 0L);
1421 curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
1422 curl_easy_setopt(connectionHandle, CURLOPT_READDATA, NULL);
1423 curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, NULL);
1424 curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, NULL);
1426 return serverResult;
1430 CalDAVServerResult CalDAV::AddEntry(string *calendarEntryHREF, string *entryData){
1432 // Add an entry to the calendar collection.
1434 CalDAVServerResult serverResult;
1435 CalDAVSendData entryAddSendData;
1437 // Build the calendar list address.
1439 string entryAddURLAddress = BuildServerAddress(&connectionData, (*calendarEntryHREF));
1441 entryAddSendData.readptr = entryData;
1442 entryAddSendData.sizeleft = entryData->size();
1444 struct curl_slist *calendarRequestHeader = NULL;
1446 calendarRequestHeader = curl_slist_append(calendarRequestHeader, "Content-Type: text/calendar; charset=utf-8");
1448 curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, calendarRequestHeader);
1449 curl_easy_setopt(connectionHandle, CURLOPT_URL, entryAddURLAddress.c_str());
1450 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, "PUT");
1451 curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 1L);
1452 curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
1453 curl_easy_setopt(connectionHandle, CURLOPT_READDATA, &entryAddSendData);
1454 curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, CalDAVSend);
1456 // Process the data.
1459 serverHeader.clear();
1461 CURLcode serverConnectionResult = curl_easy_perform(connectionHandle);
1463 if (serverConnectionResult == CURLE_OK){
1464 serverResult.result = CALDAVQUERYRESULT_OK;
1466 serverResult.result = CALDAVQUERYRESULT_SERVERERROR;
1468 serverResult.code = serverConnectionResult;
1469 curl_easy_getinfo(connectionHandle, CURLINFO_RESPONSE_CODE, &serverResult.httpCode);
1471 // Restore the original settings.
1473 string originalServerAddress = BuildServerAddress(&connectionData, "/principals/");
1474 curl_easy_setopt(connectionHandle, CURLOPT_URL, originalServerAddress.c_str());
1475 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, NULL);
1476 curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 0L);
1477 curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
1478 curl_easy_setopt(connectionHandle, CURLOPT_READDATA, NULL);
1479 curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, NULL);
1480 curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, NULL);
1482 return serverResult;
1486 CalDAVServerResult CalDAV::EditEntry(string *calendarEntryHREF, string *entryData, string *entryETag){
1488 // Edit an entry in the calendar collection.
1490 // Add an entry to the calendar collection.
1492 CalDAVServerResult serverResult;
1493 CalDAVSendData entryAddSendData;
1495 // Build the calendar list address.
1497 string entryAddURLAddress = BuildServerAddress(&connectionData, (*calendarEntryHREF));
1499 entryAddSendData.readptr = entryData;
1500 entryAddSendData.sizeleft = entryData->size();
1502 string ifMatchHeader = "If-Match: \"";
1503 ifMatchHeader.append(*entryETag);
1504 ifMatchHeader.append("\"");
1506 struct curl_slist *calendarRequestHeader = NULL;
1508 calendarRequestHeader = curl_slist_append(calendarRequestHeader, "Content-Type: text/calendar; charset=utf-8");
1509 calendarRequestHeader = curl_slist_append(calendarRequestHeader, ifMatchHeader.c_str());
1511 curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, calendarRequestHeader);
1512 curl_easy_setopt(connectionHandle, CURLOPT_URL, entryAddURLAddress.c_str());
1513 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, "PUT");
1514 curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 1L);
1515 curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
1516 curl_easy_setopt(connectionHandle, CURLOPT_READDATA, &entryAddSendData);
1517 curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, CalDAVSend);
1519 // Process the data.
1522 serverHeader.clear();
1524 CURLcode serverConnectionResult = curl_easy_perform(connectionHandle);
1526 if (serverConnectionResult == CURLE_OK){
1527 serverResult.result = CALDAVQUERYRESULT_OK;
1529 serverResult.result = CALDAVQUERYRESULT_SERVERERROR;
1531 serverResult.code = serverConnectionResult;
1532 curl_easy_getinfo(connectionHandle, CURLINFO_RESPONSE_CODE, &serverResult.httpCode);
1534 // Restore the original settings.
1536 string originalServerAddress = BuildServerAddress(&connectionData, "/principals/");
1537 curl_easy_setopt(connectionHandle, CURLOPT_URL, originalServerAddress.c_str());
1538 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, NULL);
1539 curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 0L);
1540 curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
1541 curl_easy_setopt(connectionHandle, CURLOPT_READDATA, NULL);
1542 curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, NULL);
1543 curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, NULL);
1545 return serverResult;
1549 CalDAVServerResult CalDAV::DeleteEntry(string *calendarEntryHREF){
1551 // Delete an entry in the calendar collection.
1553 CalDAVServerResult serverResult;
1555 // Build the calendar list address.
1557 string entryDeleteURLAddress = BuildServerAddress(&connectionData, (*calendarEntryHREF));
1559 curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, NULL);
1560 curl_easy_setopt(connectionHandle, CURLOPT_URL, entryDeleteURLAddress.c_str());
1561 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, "DELETE");
1563 // Delete the calendar.
1566 serverHeader.clear();
1568 CURLcode serverConnectionResult = curl_easy_perform(connectionHandle);
1570 if (serverConnectionResult == CURLE_OK){
1571 serverResult.result = CALDAVQUERYRESULT_OK;
1573 serverResult.result = CALDAVQUERYRESULT_SERVERERROR;
1575 serverResult.code = serverConnectionResult;
1576 curl_easy_getinfo(connectionHandle, CURLINFO_RESPONSE_CODE, &serverResult.httpCode);
1578 // Restore the original settings.
1580 string originalServerAddress = BuildServerAddress(&connectionData, "/principals/");
1581 curl_easy_setopt(connectionHandle, CURLOPT_URL, originalServerAddress.c_str());
1582 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, NULL);
1583 curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 0L);
1584 curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
1585 curl_easy_setopt(connectionHandle, CURLOPT_READDATA, NULL);
1586 curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, NULL);
1587 curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, NULL);
1589 return serverResult;
1593 COSSLVerified CalDAV::SSLVerify()
1598 void CalDAV::BypassSSLVerification(bool enableBypass){
1599 enableSSLBypass = enableBypass;
1600 sslSelfSigned = enableBypass;
1603 #if defined(__APPLE__)
1605 SecTrustRef CalDAV::BuildSSLCollection(){
1607 return certificateData;
1611 #elif defined(__WIN32__)
1613 PCCERT_CONTEXT CalDAV::BuildSSLCollection(){
1615 return certificateData;
1621 SSLCertCollectionString CalDAV::BuildSSLCollection(){
1623 // Build and return the SSL collection.
1625 SSLCertCollectionString sslCertInfo;
1627 // Grab the certificate data.
1630 struct curl_slist *certdata;
1631 struct curl_certinfo *certinfo;
1634 certptr.certdata = NULL;
1636 CURLcode result = curl_easy_getinfo(connectionHandle, CURLINFO_CERTINFO, &certptr.certinfo);
1638 std::string certPropName;
1639 std::string certPropValue;
1641 for (int i = 0; i < certptr.certinfo->num_of_certs; i++){
1643 struct curl_slist *slist;
1644 SSLCertDataString sslCertDataInc;
1646 for (slist = certptr.certinfo->certinfo[i]; slist; slist = slist->next){
1648 // Using wxStringTokenizer from wxWidgets.
1650 wxStringTokenizer certDataInc(wxString::FromUTF8(slist->data), ":");
1652 // Get first token as the property name.
1654 certPropName = certDataInc.GetNextToken().ToStdString();
1656 // Get remaining tokens as the property value.
1658 while(certDataInc.HasMoreTokens()){
1660 certPropValue.append(certDataInc.GetNextToken());
1664 sslCertDataInc.CertData.insert(std::make_pair(certPropName, certPropValue));
1665 certPropName.clear();
1666 certPropValue.clear();
1670 sslCertInfo.SSLCollection.insert(std::make_pair(i, sslCertDataInc));
1680 bool CalDAV::CanDoSSL(){
1684 bool CalDAV::HasValidResponse(){
1685 return validResponse;
1688 bool CalDAV::AbleToLogin(){
1692 bool CalDAV::IsSelfSigned(){
1693 return sslSelfSigned;
1696 string CalDAV::GetErrorMessage(){
1698 errorMessage = sessionErrorBuffer;
1699 return errorMessage;
1703 static bool CalDAVObjectValidSettings(CalDAVConnectionData *connData){
1705 // Check if the passed CalDAV Connection Data is has
1706 // an address set. Return false if nullptr is used.
1708 if (connData == nullptr){
1714 // Check the server hostname. Return false
1715 // if no value has been set.
1717 if (connData->hostname.size() == 0){
1723 // Check the server port. Return false if
1724 // no value has been set or the port number
1725 // is less than 1 or higher than 65535.
1727 if (connData->port < 1 || connData->port > 65535){
1733 // Check the server username. Return false
1734 // if no value has been set.
1736 if (connData->username.size() == 0){
1742 // Check the server password. Return false
1743 // if no value has been set.
1745 if (connData->password.size() == 0){
1751 // Cannot check UseSSL: It is either true
1754 // Cannot check Prefix: The prefix may need
1755 // to be worked out first.
1757 // No errors were found whilst checking so
1764 string CalDAV::BuildServerAddress(CalDAVConnectionData *connData, string uriAddress){
1766 string serverAddress;
1768 // Setup the server address.
1770 if (connData->useSSL == true){
1771 serverAddress += "https://";
1773 serverAddress += "http://";
1776 serverAddress += connData->hostname;
1778 // Check if server port is 80, otherwise
1779 // specifiy the port number in the address.
1781 if (connData->port != 80){
1782 serverAddress += ":";
1783 serverAddress += to_string(connData->port);
1786 serverAddress += uriAddress;
1788 return serverAddress;
1792 void CalDAV::SetupDefaultParametersNonSSL(bool doAuthentication){
1794 std::string serverAddress = "";
1796 string serverAddressURL = "http://" + connectionData.hostname + ":" + to_string(connectionData.port) + "/";
1797 string usernamePassword = connectionData.username + ":" + connectionData.password;
1799 curl_easy_setopt(connectionHandle, CURLOPT_URL, serverAddressURL.c_str());
1800 curl_easy_setopt(connectionHandle, CURLOPT_NOPROGRESS, 1L);
1801 curl_easy_setopt(connectionHandle, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST|CURLAUTH_BASIC);
1802 curl_easy_setopt(connectionHandle, CURLOPT_TIMEOUT, 60);
1803 curl_easy_setopt(connectionHandle, CURLOPT_FAILONERROR, true);
1804 curl_easy_setopt(connectionHandle, CURLOPT_USERAGENT, XSDCAL_USERAGENT);
1805 curl_easy_setopt(connectionHandle, CURLOPT_NOSIGNAL, 1L);
1806 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, "GET");
1807 curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, nullptr);
1808 curl_easy_setopt(connectionHandle, CURLOPT_POSTFIELDS, nullptr);
1809 curl_easy_setopt(connectionHandle, CURLOPT_POSTFIELDSIZE, 0L);
1811 if (doAuthentication == true){
1812 curl_easy_setopt(connectionHandle, CURLOPT_USERPWD, usernamePassword.c_str());
1814 curl_easy_setopt(connectionHandle, CURLOPT_USERPWD, NULL);
1819 void CalDAV::SetupDefaultParametersSSL(bool doAuthentication){
1821 // Setup the default parameters.
1823 string ServerAddressURL = "https://" + connectionData.hostname + ":" + to_string(connectionData.port) + "/";
1824 string UsernamePassword = connectionData.username + ":" + connectionData.password;
1826 curl_easy_setopt(connectionHandle, CURLOPT_URL, ServerAddressURL.c_str());
1827 curl_easy_setopt(connectionHandle, CURLOPT_NOPROGRESS, 1L);
1828 curl_easy_setopt(connectionHandle, CURLOPT_CERTINFO, 1L);
1829 curl_easy_setopt(connectionHandle, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST|CURLAUTH_BASIC);
1830 curl_easy_setopt(connectionHandle, CURLOPT_TIMEOUT, 60);
1831 curl_easy_setopt(connectionHandle, CURLOPT_FAILONERROR, 0L);
1832 curl_easy_setopt(connectionHandle, CURLOPT_USERAGENT, XSDCAL_USERAGENT);
1833 curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
1834 curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, "GET");
1835 curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, nullptr);
1836 curl_easy_setopt(connectionHandle, CURLOPT_POSTFIELDS, nullptr);
1837 curl_easy_setopt(connectionHandle, CURLOPT_POSTFIELDSIZE, 0L);
1839 if (doAuthentication == true){
1840 curl_easy_setopt(connectionHandle, CURLOPT_USERPWD, UsernamePassword.c_str());
1842 curl_easy_setopt(connectionHandle, CURLOPT_USERPWD, NULL);
1845 if (enableSSLBypass == true){
1846 curl_easy_setopt(connectionHandle, CURLOPT_SSL_VERIFYHOST, 0L);
1847 curl_easy_setopt(connectionHandle, CURLOPT_SSL_VERIFYPEER, 0L);
1848 curl_easy_setopt(connectionHandle, CURLOPT_SSL_VERIFYSTATUS, 0L);
1850 curl_easy_setopt(connectionHandle, CURLOPT_SSL_VERIFYHOST, 2L);
1851 curl_easy_setopt(connectionHandle, CURLOPT_SSL_VERIFYPEER, 1L);
1852 curl_easy_setopt(connectionHandle, CURLOPT_SSL_VERIFYSTATUS, 1L);
1855 #if !defined(__APPLE__) || defined(__WIN32__)
1857 if (connectionData.account.size() > 0){
1859 // Check if the server certificate file exists.
1861 string certificateFilename = GetAccountDir(connectionData.account, true);
1863 if (wxFile::Exists(certificateFilename)){
1865 curl_easy_setopt(connectionHandle, CURLOPT_CAINFO, certificateFilename.c_str());
1875 void CalDAV::ResetResults(){
1878 COSSLVerified SSLVerified = COSSL_NORESULT;
1879 validResponse = false;
1881 sslSelfSigned = false;
1882 //taskCompleted = false;
1884 sessionErrorBuffer[0] = '\0';
1885 //sessionResult = CURLE_OK;
1888 /*if (headerList != nullptr){
1889 curl_slist_free_all(headerList);
1890 headerList = nullptr;