X-Git-Url: http://Server1/repobrowser/?a=blobdiff_plain;f=source%2Fobjects%2FCalDAV%2FCalDAV.cpp;h=ecd91bd3295bbaf53acc3985707e44f0494a4b13;hb=1fe6e43892e5c572949a293a9e19704b5debadad;hp=33c81b4b769df9fe456b0a59880ee59b61e9269c;hpb=b776fb87f9406910f146cd935605b0e505943142;p=xestiacalendar%2F.git diff --git a/source/objects/CalDAV/CalDAV.cpp b/source/objects/CalDAV/CalDAV.cpp index 33c81b4..ecd91bd 100644 --- a/source/objects/CalDAV/CalDAV.cpp +++ b/source/objects/CalDAV/CalDAV.cpp @@ -1,11 +1,1471 @@ +// CalDAV.cpp - CalDAV Connection Object. +// +// (c) 2016-2017 Xestia Software Development. +// +// This file is part of Xestia Calendar. +// +// Xestia Calendar is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by the +// Free Software Foundation, version 3 of the license. +// +// Xestia Calendar is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with Xestia Calendar. If not, see + #include "CalDAV.h" -bool CalDAVObjectValidSettings(CalDAVConnectionData *ConnData){ +using namespace std; + +size_t CalDAVReceive(char *receivedBuffer, size_t size, size_t newMemoryBytes, string *stringPointer) +{ + + stringPointer->append(receivedBuffer, newMemoryBytes); + + return size * newMemoryBytes; + +} + +size_t CalDAVSend(char *sendBuffer, size_t size, size_t newMemoryBytes, void *dataStruct){ + + struct CalDAVSendData *uploadPtr = (struct CalDAVSendData *)dataStruct; + + if (uploadPtr->sizeleft){ + + uploadPtr->sizeleft--; + char charSend; + + charSend = (*uploadPtr->readptr)[uploadPtr->seek]; + + *sendBuffer = charSend; + + uploadPtr->seek++; + + return 1; + + } + + return 0; + +} + +CalDAV::CalDAV(){ + + // Setup the objects within the CalDAV connection + // object. + + connectionHandle = curl_easy_init(); + +} + +CalDAV::~CalDAV(){ + + // Destory the objects within the CalDAV connection + // object. + + curl_easy_cleanup(connectionHandle); + connectionHandle = nullptr; + +} + +void CalDAV::SetupConnectionData(CalDAVConnectionData *connData){ + + // Check if ConnData is a nullptr, return if it is. + + if (connData == nullptr){ + return; + } + + // Set the connection settings to the values from ConnData. + + connectionData = (*connData); + +} + +CalDAVStatus CalDAV::GetConnectionData(){ + + // Get the current connection settings for the CalDAV + // connection object and return a CalDAVStatus object. + + CalDAVStatus connectionStatus; + + connectionStatus.hostname = connectionData.hostname; + connectionStatus.port = connectionData.port; + connectionStatus.username = connectionData.username; + connectionStatus.prefix = connectionData.prefix; + connectionStatus.useSSL = connectionData.useSSL; + connectionStatus.timeout = connectionData.timeout; + + return connectionStatus; + +} + +CalDAVServerResult CalDAV::Connect(){ + + CalDAVServerResult serverResult; + + string serverAddress = ""; + string serverUserPass = ""; + + // Setup the server address. + + serverAddress = BuildServerAddress(&connectionData, "/principals/"); + + // Setup the server password. + + serverUserPass += connectionData.username; + serverUserPass += ":"; + serverUserPass += connectionData.password; + + curl_easy_setopt(connectionHandle, CURLOPT_URL, serverAddress.c_str()); + curl_easy_setopt(connectionHandle, CURLOPT_USERPWD, serverUserPass.c_str()); + curl_easy_setopt(connectionHandle, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST); + curl_easy_setopt(connectionHandle, CURLOPT_FAILONERROR, 1L); + curl_easy_setopt(connectionHandle, CURLOPT_TIMEOUT, connectionData.timeout); + curl_easy_setopt(connectionHandle, CURLOPT_WRITEFUNCTION, CalDAVReceive); + curl_easy_setopt(connectionHandle, CURLOPT_WRITEDATA, &serverData); + curl_easy_setopt(connectionHandle, CURLOPT_WRITEHEADER, &serverHeader); + + // Connect to the CalDAV server. + + serverResult.code = curl_easy_perform(connectionHandle); + + // Process the result received from the server. + + if (serverResult.code != CURLE_OK){ + + serverResult.result = CALDAVQUERYRESULT_SERVERERROR; + + } else { + + serverResult.result = CALDAVQUERYRESULT_OK; + + } + + // Get the HTTP code. + + curl_easy_getinfo(connectionHandle, CURLINFO_RESPONSE_CODE, &serverResult.httpCode); + + return serverResult; + +} + +CalDAVServerResult CalDAV::GetServerResult(){ + + return connectionServerResult; + +} + +CalDAVServerSupport CalDAV::GetServerSupport(){ + + CalDAVServerSupport serverStatus; + + // Setup the server connection. + + curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, "OPTIONS"); + + CURLcode serverResult = curl_easy_perform(connectionHandle); + + // Set the results. + + if (serverResult == CURLE_OK){ + connectionServerResult.result = CALDAVQUERYRESULT_OK; + } else { + connectionServerResult.result = CALDAVQUERYRESULT_SERVERERROR; + } + connectionServerResult.code = serverResult; + curl_easy_getinfo(connectionHandle, CURLINFO_RESPONSE_CODE, &connectionServerResult.httpCode); + + if (serverResult != CURLE_OK){ + return serverStatus; + } + + // Check that the server header has data in, + // otherwise return an "empty" CalDAVServerSupport. + + if (serverHeader.size() == 0){ + return serverStatus; + } + + // Process each line looking for the first DAV header + // line. + + bool newlineMode = true; + + string davLine; + + for (int charSeek = 0; charSeek < serverHeader.size(); charSeek++){ + + if (newlineMode == true){ + + // Check if we have reached the end of the string. + + if (charSeek >= serverHeader.size()){ + + break; + + } + + // Check the first four letters to make sure + // they are 'DAV:'. + + string davHeaderCheck = ""; + + try { + davHeaderCheck = serverHeader.substr(charSeek, 4); + } + + catch (out_of_range &oor){ + break; + } + + if (davHeaderCheck == "DAV:"){ + + charSeek += 5; + + for (; charSeek < serverHeader.size(); charSeek++){ + + if (serverHeader[charSeek] == '\n'){ + + break; + + } + + davLine.push_back(serverHeader[charSeek]); + + } + + break; + + } + + newlineMode = false; + + } + + if (serverHeader[charSeek] == '\n'){ + + newlineMode = true; + + } + + } + + // Process the DAV line. + + vector davLineData; + string davSegmentString; + + for (int charSeek = 0; charSeek < davLine.size(); charSeek++){ + + if (davLine[charSeek] == ' '){ + continue; + } + + if (davLine[charSeek] == ','){ + + davLineData.push_back(davSegmentString); + davSegmentString.clear(); + continue; + + } + + davSegmentString += davLine[charSeek]; + + } + + // Process the DAV values and set each value + // to true as required. + + for (int davItemSeek = 0; + davItemSeek < davLineData.size(); + davItemSeek++){ + + if (davLineData.at(davItemSeek) == "calendar-access"){ + + serverStatus.basicSupport = true; + + } + + } + + // Reset the connection status. + + curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, NULL); + + return serverStatus; + +} + +string CalDAV::GetUserPrincipal(){ + + string currentUserPrincipal = ""; + string userPrincipalRequest = ""; + CalDAVSendData userPrincipalSendData; + + userPrincipalRequest = "\n" + "\n" + " \n" + " \n" + " \n" + ""; + + userPrincipalSendData.readptr = &userPrincipalRequest; + userPrincipalSendData.sizeleft = userPrincipalRequest.size(); + + // Setup the header. + + struct curl_slist *userPrincipalRequestHeader = NULL; + + userPrincipalRequestHeader = curl_slist_append(userPrincipalRequestHeader, "Depth: 0"); + userPrincipalRequestHeader = curl_slist_append(userPrincipalRequestHeader, "Prefer: return-minimal"); + userPrincipalRequestHeader = curl_slist_append(userPrincipalRequestHeader, "Content-Type: application/xml; charset=utf-8"); + + curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, userPrincipalRequestHeader); + + curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, "PROPFIND"); + curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 1L); + curl_easy_setopt(connectionHandle, CURLOPT_READDATA, &userPrincipalSendData); + curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, CalDAVSend); + + // Process the data. + + serverData.clear(); + serverHeader.clear(); + + CURLcode serverResult = curl_easy_perform(connectionHandle); + + // Set the results. + + if (serverResult == CURLE_OK){ + connectionServerResult.result = CALDAVQUERYRESULT_OK; + } else { + connectionServerResult.result = CALDAVQUERYRESULT_SERVERERROR; + } + connectionServerResult.code = serverResult; + curl_easy_getinfo(connectionHandle, CURLINFO_RESPONSE_CODE, &connectionServerResult.httpCode); + + if (serverResult != CURLE_OK){ + + return currentUserPrincipal; + + } + + // Process the User Principal from the ServerData. + + currentUserPrincipal = ProcessXMLUserPrincipal(); + + // Reset the changed settings. + + curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 0L); + curl_easy_setopt(connectionHandle, CURLOPT_READDATA, NULL); + curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, NULL); + + return currentUserPrincipal; + +} + +string CalDAV::GetCalendarHome(string userPrincipalURI){ + + string calendarHomeURI = ""; + + // Build the Calendar Home URL address. + + string calendarHomeURL = BuildServerAddress(&connectionData, userPrincipalURI); + + // Setup the header request. + + CalDAVSendData calendarHomeSendData; + + string calendarHomeRequest = "\n" + "\n" + " \n" + " \n" + " \n" + ""; + + calendarHomeSendData.readptr = &calendarHomeRequest; + calendarHomeSendData.sizeleft = calendarHomeRequest.size(); + + // Setup the header. + + struct curl_slist *calendarRequestHeader = NULL; + + calendarRequestHeader = curl_slist_append(calendarRequestHeader, "Depth: 0"); + calendarRequestHeader = curl_slist_append(calendarRequestHeader, "Prefer: return-minimal"); + calendarRequestHeader = curl_slist_append(calendarRequestHeader, "Content-Type: application/xml; charset=utf-8"); + + curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, calendarRequestHeader); + curl_easy_setopt(connectionHandle, CURLOPT_URL, calendarHomeURL.c_str()); + curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, "PROPFIND"); + curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 1L); + curl_easy_setopt(connectionHandle, CURLOPT_READDATA, &calendarHomeSendData); + curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, CalDAVSend); + + // Process the data. + + serverData.clear(); + serverHeader.clear(); + + CURLcode serverResult = curl_easy_perform(connectionHandle); + + // Set the results. + + if (serverResult == CURLE_OK){ + connectionServerResult.result = CALDAVQUERYRESULT_OK; + } else { + connectionServerResult.result = CALDAVQUERYRESULT_SERVERERROR; + } + connectionServerResult.code = serverResult; + curl_easy_getinfo(connectionHandle, CURLINFO_RESPONSE_CODE, &connectionServerResult.httpCode); + + if (serverResult != CURLE_OK){ + + return calendarHomeURI; + + } + + // Process the User Principal from the ServerData. + + calendarHomeURI = ProcessXMLCalendarHome(); + + // Reset the changed settings. + + string originalServerAddress = BuildServerAddress(&connectionData, "/principals/"); + curl_easy_setopt(connectionHandle, CURLOPT_URL, originalServerAddress.c_str()); + + curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 0L); + curl_easy_setopt(connectionHandle, CURLOPT_READDATA, NULL); + curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, NULL); + curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, NULL); + + return calendarHomeURI; + +} + +CalDAVCalendarList CalDAV::GetCalendars(){ + + CalDAVCalendarList serverList; + CalDAVSendData calendarListSendData; + + // Build the server address. + + string userPrincipalURI = ""; + userPrincipalURI = GetUserPrincipal(); + + if (userPrincipalURI.size() == 0){ + + return serverList; + + } + + string calendarHomeURI = ""; + calendarHomeURI = GetCalendarHome(userPrincipalURI); + + string calendarListURLAddress = BuildServerAddress(&connectionData, calendarHomeURI); + + string calendarListRequest = "\n" + "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + ""; + + calendarListSendData.readptr = &calendarListRequest; + calendarListSendData.sizeleft = calendarListRequest.size(); + + // Setup the header. + + struct curl_slist *calendarListRequestHeader = NULL; + + calendarListRequestHeader = curl_slist_append(calendarListRequestHeader, "Depth: 1"); + calendarListRequestHeader = curl_slist_append(calendarListRequestHeader, "Prefer: return-minimal"); + calendarListRequestHeader = curl_slist_append(calendarListRequestHeader, "Content-Type: application/xml; charset=utf-8"); + + curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, calendarListRequestHeader); + curl_easy_setopt(connectionHandle, CURLOPT_URL, calendarListURLAddress.c_str()); + curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, "PROPFIND"); + curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 1L); + curl_easy_setopt(connectionHandle, CURLOPT_READDATA, &calendarListSendData); + curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, CalDAVSend); + + // Process the data. + + serverData.clear(); + serverHeader.clear(); + + CURLcode serverResult = curl_easy_perform(connectionHandle); + + //ServerList = ProcessXMLCalendarList(); + + if (serverResult == CURLE_OK){ + connectionServerResult.result = CALDAVQUERYRESULT_OK; + } else { + connectionServerResult.result = CALDAVQUERYRESULT_SERVERERROR; + } + connectionServerResult.code = serverResult; + curl_easy_getinfo(connectionHandle, CURLINFO_RESPONSE_CODE, &connectionServerResult.httpCode); + + if (serverResult != CURLE_OK){ + + return serverList; + + } + + // Process the received XML data into a list of calendars + // and locations. + + serverList = ProcessXMLCalendarList(); + + // Restore the original settings. + + string originalServerAddress = BuildServerAddress(&connectionData, "/principals/"); + + curl_easy_setopt(connectionHandle, CURLOPT_URL, originalServerAddress.c_str()); + curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, NULL); + curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 0L); + curl_easy_setopt(connectionHandle, CURLOPT_READDATA, NULL); + curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, NULL); + + return serverList; + +} + +CalDAVEntryList CalDAV::GetEntryList(string *calendarHREF){ + + CalDAVEntryList entryList; + CalDAVSendData entryListSendData; + + if (calendarHREF->size() == 0){ + + return entryList; + + } + + string entryListURLAddress = BuildServerAddress(&connectionData, *calendarHREF); + + string entryListRequest = "\n"; + + /*if (CalendarTag == nullptr){*/ + + entryListRequest += "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + ""; + + /*} else { + + EntryListRequest += "\n" + " "; + EntryListRequest += *CalendarTag; + EntryListRequest += "\n" + " 1\n" + " \n" + " \n" + " \n" + " \n" + ""; + + }*/ + + entryListSendData.readptr = &entryListRequest; + entryListSendData.sizeleft = entryListRequest.size(); + + struct curl_slist *entryListRequestHeader = NULL; + + entryListRequestHeader = curl_slist_append(entryListRequestHeader, "Content-Type: application/xml; charset=utf-8"); + + /*if (CalendarTag != nullptr){ + + EntryListRequestHeader = curl_slist_append(EntryListRequestHeader, "Content-Type: application/xml; charset=utf-8"); + EntryListRequestHeader = curl_slist_append(EntryListRequestHeader, "Content-Type: application/xml; charset=utf-8"); + + }*/ + + curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, entryListRequestHeader); + curl_easy_setopt(connectionHandle, CURLOPT_URL, entryListURLAddress.c_str()); + curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, "REPORT"); + curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 1L); + curl_easy_setopt(connectionHandle, CURLOPT_READDATA, &entryListSendData); + curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, CalDAVSend); + + // Process the data. + + serverData.clear(); + serverHeader.clear(); + + CURLcode serverResult = curl_easy_perform(connectionHandle); + + //ServerList = ProcessXMLCalendarList(); + + if (serverResult == CURLE_OK){ + connectionServerResult.result = CALDAVQUERYRESULT_OK; + } else { + connectionServerResult.result = CALDAVQUERYRESULT_SERVERERROR; + } + connectionServerResult.code = serverResult; + curl_easy_getinfo(connectionHandle, CURLINFO_RESPONSE_CODE, &connectionServerResult.httpCode); + + if (serverResult != CURLE_OK){ + + return entryList; + + } + + // Process the received XML data into a list of calendars + // and locations. + + entryList = ProcessXMLEntryList(); + + // Restore the original settings. + + string originalServerAddress = BuildServerAddress(&connectionData, "/principals/"); + + curl_easy_setopt(connectionHandle, CURLOPT_URL, originalServerAddress.c_str()); + curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, NULL); + curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 0L); + curl_easy_setopt(connectionHandle, CURLOPT_READDATA, NULL); + curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, NULL); + + return entryList; + +} + +CalDAVEntryList CalDAV::GetEntryList(string *calendarHREF, string *calendarTag){ + + CalDAVEntryList entryList; + CalDAVSendData entryListSendData; + + if (calendarHREF->size() == 0){ + + return entryList; + + } + + string entryListURLAddress = BuildServerAddress(&connectionData, *calendarHREF); + + // First query: Get the list of contacts that need to be updated. + + string entryListRequest = "\n"; + + entryListRequest += "\n" + " "; + + if (calendarTag != nullptr){ + + entryListRequest += *calendarTag; + + } else { + + entryListRequest += ""; + + } + + entryListRequest += "\n" + " 1\n" + " \n" + " \n" + " \n" + ""; + + entryListSendData.readptr = &entryListRequest; + entryListSendData.sizeleft = entryListRequest.size(); + + struct curl_slist *entryListRequestHeader = NULL; + + entryListRequestHeader = curl_slist_append(entryListRequestHeader, "Content-Type: application/xml; charset=utf-8"); + + curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, entryListRequestHeader); + curl_easy_setopt(connectionHandle, CURLOPT_URL, entryListURLAddress.c_str()); + curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, "REPORT"); + curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 1L); + curl_easy_setopt(connectionHandle, CURLOPT_READDATA, &entryListSendData); + curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, CalDAVSend); + + // Process the data. + + serverData.clear(); + serverHeader.clear(); + + CURLcode serverResult = curl_easy_perform(connectionHandle); + + if (serverResult == CURLE_OK){ + connectionServerResult.result = CALDAVQUERYRESULT_OK; + } else { + connectionServerResult.result = CALDAVQUERYRESULT_SERVERERROR; + } + connectionServerResult.code = serverResult; + curl_easy_getinfo(connectionHandle, CURLINFO_RESPONSE_CODE, &connectionServerResult.httpCode); + + if (serverResult != CURLE_OK){ + + return entryList; + + } + + entryList = ProcessXMLSyncTokenList(); + + // Check the last entry matches the HREF and if it + // does then delete it. + + if (entryList.href.size() > 0) { + + if (entryList.href.rbegin()->second == *calendarHREF){ + + entryList.href.erase((entryList.href.size() - 1)); + entryList.tag.erase((entryList.href.size() - 1)); + entryList.data.erase((entryList.href.size() - 1)); + + } + + } + + // Build the list into a new list for getting the new + // calendar data with. + + entryListRequest.clear(); + + entryListRequest = "\n"; + + entryListRequest += "\n" + " \n" + " \n" + " \n" + " \n"; + + for (std::map::iterator hrefIter = entryList.href.begin(); + hrefIter != entryList.href.end(); hrefIter++){ + + string entryListHREFString = hrefIter->second; + + entryListRequest += " "; + entryListRequest += entryListHREFString; + entryListRequest += "\n"; + + } + + entryListRequest += ""; + + CalDAVSendData updatedEntryListSendData; + + updatedEntryListSendData.readptr = &entryListRequest; + updatedEntryListSendData.sizeleft = entryListRequest.size(); + + curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, entryListRequestHeader); + curl_easy_setopt(connectionHandle, CURLOPT_URL, entryListURLAddress.c_str()); + curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, "REPORT"); + curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 1L); + curl_easy_setopt(connectionHandle, CURLOPT_READDATA, &updatedEntryListSendData); + curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, CalDAVSend); + + // Get the updated calendar data. + + serverData.clear(); + serverHeader.clear(); + entryList.href.clear(); + entryList.tag.clear(); + entryList.data.clear(); + + serverResult = curl_easy_perform(connectionHandle); + + // Check the last entry matches the HREF and if it + // does then delete it. + + if (serverResult == CURLE_OK){ + connectionServerResult.result = CALDAVQUERYRESULT_OK; + } else { + connectionServerResult.result = CALDAVQUERYRESULT_SERVERERROR; + } + connectionServerResult.code = serverResult; + curl_easy_getinfo(connectionHandle, CURLINFO_RESPONSE_CODE, &connectionServerResult.httpCode); + + if (serverResult != CURLE_OK){ + + return entryList; + + } + + entryList = ProcessXMLEntryList(); + + // Second query: Get the list of contact data for the contacts that have + // beenchanged. + + // Restore the original settings. + + string originalServerAddress = BuildServerAddress(&connectionData, "/principals/"); + + curl_easy_setopt(connectionHandle, CURLOPT_URL, originalServerAddress.c_str()); + curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, NULL); + curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 0L); + curl_easy_setopt(connectionHandle, CURLOPT_READDATA, NULL); + curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, NULL); + + return entryList; + +} + +CalDAVServerResult CalDAV::AddCalendar(string calendarName){ + + CalDAVServerResult serverResult; + + AddCalendar(&calendarName, nullptr); + + return serverResult; + +} + +CalDAVServerResult CalDAV::AddCalendar(string *calendarName, string *calendarShortName){ + + CalDAVServerResult serverResult; + CalDAVSendData calendarAddSendData; + + // Build the server address. + + string userPrincipalURI = ""; + userPrincipalURI = GetUserPrincipal(); + + if (userPrincipalURI.size() == 0){ + + return serverResult; + + } + + string calendarHomeURI = ""; + calendarHomeURI = GetCalendarHome(userPrincipalURI); + + // Generate the UUID. + + string UUIDValue = ""; + + if (calendarShortName == nullptr){ + + UUIDValue = GenerateUUID(); + UUIDValue.erase(UUIDValue.end()-1); + + } else { + + UUIDValue = *calendarShortName; + + } + + string calendarHomeURL = calendarHomeURI; + calendarHomeURL.append(UUIDValue); + calendarHomeURL.append("/"); + + // Build the calendar list address. + + string calendarListURLAddress = BuildServerAddress(&connectionData, calendarHomeURL); + + string calendarAddRequest = "\n" + "\n" + " \n" + " \n" + " "; + calendarAddRequest += *calendarName; + calendarAddRequest += "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + ""; + + calendarAddSendData.readptr = &calendarAddRequest; + calendarAddSendData.sizeleft = calendarAddRequest.size(); + + // Setup the header. + + struct curl_slist *calendarRequestHeader = NULL; + + //curl_easy_setopt(ConnectionHandle, CURLOPT_HTTPHEADER, CalendarRequestHeader); + curl_easy_setopt(connectionHandle, CURLOPT_URL, calendarListURLAddress.c_str()); + curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, "MKCALENDAR"); + curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 1L); + curl_easy_setopt(connectionHandle, CURLOPT_READDATA, &calendarAddSendData); + curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, CalDAVSend); + + // Process the data. + + serverData.clear(); + serverHeader.clear(); + + CURLcode serverConnectionResult = curl_easy_perform(connectionHandle); + + if (serverConnectionResult == CURLE_OK){ + serverResult.result = CALDAVQUERYRESULT_OK; + } else { + serverResult.result = CALDAVQUERYRESULT_SERVERERROR; + } + serverResult.code = serverConnectionResult; + curl_easy_getinfo(connectionHandle, CURLINFO_RESPONSE_CODE, &serverResult.httpCode); + + // Restore the original settings. + + string originalServerAddress = BuildServerAddress(&connectionData, "/principals/"); + curl_easy_setopt(connectionHandle, CURLOPT_URL, originalServerAddress.c_str()); + curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, NULL); + curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 0L); + curl_easy_setopt(connectionHandle, CURLOPT_READDATA, NULL); + curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, NULL); + + return serverResult; + +} + +CalDAVServerResult CalDAV::EditCalendarProcess(string *calendarHREF, + string *calendarName, + Colour *calendarColour, + string *calendarDescription, + int *calendarOrder){ + + CalDAVServerResult serverResult; + CalDAVSendData calendarEditSendData; + + // Build the server address. + + string userPrincipalURI = ""; + userPrincipalURI = GetUserPrincipal(); + + if (userPrincipalURI.size() == 0){ + + return serverResult; + + } + + string calendarHomeURI = ""; + calendarHomeURI = GetCalendarHome(userPrincipalURI); + + // Generate the UUID. + + string UUIDValue = GenerateUUID(); + UUIDValue.erase(UUIDValue.end()-1); + + string calendarHomeURL = calendarHomeURI; + calendarHomeURL.append(UUIDValue); + calendarHomeURL.append("/"); + + // Build the calendar list address. + + string calendarEditURLAddress = BuildServerAddress(&connectionData, (*calendarHREF)); + + string calendarEditRequest = "\n" + "\n" + " \n" + " \n"; + + // Update the calendar name. + + if (calendarName != nullptr){ + + calendarEditRequest += ""; + calendarEditRequest += (*calendarName); + calendarEditRequest += "\n"; + + } + + // Update the calendar colour. + + if (calendarColour != nullptr){ + + calendarEditRequest += ""; + calendarEditRequest += (*calendarColour); + calendarEditRequest += "\n"; + + } + + // Update the calendar description. + + if (calendarDescription != nullptr){ + + calendarEditRequest += ""; + calendarEditRequest += (*calendarDescription); + calendarEditRequest += "\n"; + + } + + // Update the calendar order. + + if (calendarOrder != nullptr){ + + calendarEditRequest += ""; + calendarEditRequest += to_string((*calendarOrder)); + calendarEditRequest += "\n"; + + } + + calendarEditRequest += " \n" + " \n" + ""; + + calendarEditSendData.readptr = &calendarEditRequest; + calendarEditSendData.sizeleft = calendarEditRequest.size(); + + // Setup the header. + + struct curl_slist *calendarRequestHeader = NULL; + + //curl_easy_setopt(ConnectionHandle, CURLOPT_HTTPHEADER, CalendarRequestHeader); + curl_easy_setopt(connectionHandle, CURLOPT_URL, calendarEditURLAddress.c_str()); + curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, "PROPPATCH"); + curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 1L); + curl_easy_setopt(connectionHandle, CURLOPT_READDATA, &calendarEditSendData); + curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, CalDAVSend); + + // Process the data. + + serverData.clear(); + serverHeader.clear(); + + CURLcode serverConnectionResult = curl_easy_perform(connectionHandle); + + if (serverConnectionResult == CURLE_OK){ + serverResult.result = CALDAVQUERYRESULT_OK; + } else { + serverResult.result = CALDAVQUERYRESULT_SERVERERROR; + } + serverResult.code = serverConnectionResult; + curl_easy_getinfo(connectionHandle, CURLINFO_RESPONSE_CODE, &serverResult.httpCode); + + // Restore the original settings. + + string originalServerAddress = BuildServerAddress(&connectionData, "/principals/"); + curl_easy_setopt(connectionHandle, CURLOPT_URL, originalServerAddress.c_str()); + curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, NULL); + curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 0L); + curl_easy_setopt(connectionHandle, CURLOPT_READDATA, NULL); + curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, NULL); + + return serverResult; + +} + +CalDAVServerResult CalDAV::EditCalendar(string *calendarHREF, + string *calendarName, + Colour *calendarColour, + string *calendarDescription, + int *calendarOrder){ + + CalDAVServerResult serverResult; + + serverResult = EditCalendarProcess(calendarHREF, + calendarName, + calendarColour, + calendarDescription, + calendarOrder); + + return serverResult; + +} + +CalDAVServerResult CalDAV::EditCalendar(string *calendarHREF, + Colour *calendarColour){ + + CalDAVServerResult serverResult; + + serverResult = EditCalendarProcess(calendarHREF, + nullptr, + calendarColour, + nullptr, + nullptr); + + return serverResult; + +} + +CalDAVServerResult CalDAV::EditCalendar(string *calendarHREF, + string *calendarName){ + + CalDAVServerResult serverResult; + + serverResult = EditCalendarProcess(calendarHREF, + calendarName, + nullptr, + nullptr, + nullptr); + + return serverResult; + +} + +CalDAVServerResult CalDAV::EditCalendar(string *calendarHREF, + int *calendarOrder){ + + CalDAVServerResult serverResult; + + serverResult = EditCalendarProcess(calendarHREF, + nullptr, + nullptr, + nullptr, + calendarOrder); + + return serverResult; + +} + +CalDAVServerResult CalDAV::EditCalendarDescription(string *calendarHREF, + string *calendarDescription){ + + CalDAVServerResult serverResult; + + serverResult = EditCalendarProcess(calendarHREF, + nullptr, + nullptr, + calendarDescription, + nullptr); + + return serverResult; + +} + +CalDAVServerResult CalDAV::DeleteCalendar(string *calendarHREF){ + + CalDAVServerResult serverResult; + + // Build the server address. + + string userPrincipalURI = ""; + userPrincipalURI = GetUserPrincipal(); + + if (userPrincipalURI.size() == 0){ + + return serverResult; + + } + + string calendarHomeURI = ""; + calendarHomeURI = GetCalendarHome(userPrincipalURI); + + // Generate the UUID. + + string UUIDValue = GenerateUUID(); + UUIDValue.erase(UUIDValue.end()-1); + + string calendarHomeURL = calendarHomeURI; + calendarHomeURL.append(UUIDValue); + calendarHomeURL.append("/"); + + // Build the calendar list address. + + struct curl_slist *deleteRequestHeader = NULL; + + deleteRequestHeader = curl_slist_append(deleteRequestHeader, "Depth: infinity"); + + string calendarDeleteURLAddress = BuildServerAddress(&connectionData, (*calendarHREF)); + + curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, deleteRequestHeader); + curl_easy_setopt(connectionHandle, CURLOPT_URL, calendarDeleteURLAddress.c_str()); + curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, "DELETE"); + + // Delete the calendar. + + serverData.clear(); + serverHeader.clear(); + + CURLcode serverConnectionResult = curl_easy_perform(connectionHandle); + + if (serverConnectionResult == CURLE_OK){ + serverResult.result = CALDAVQUERYRESULT_OK; + } else { + serverResult.result = CALDAVQUERYRESULT_SERVERERROR; + } + serverResult.code = serverConnectionResult; + curl_easy_getinfo(connectionHandle, CURLINFO_RESPONSE_CODE, &serverResult.httpCode); + + // Restore the original settings. + + string originalServerAddress = BuildServerAddress(&connectionData, "/principals/"); + curl_easy_setopt(connectionHandle, CURLOPT_URL, originalServerAddress.c_str()); + curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, NULL); + curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 0L); + curl_easy_setopt(connectionHandle, CURLOPT_READDATA, NULL); + curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, NULL); + curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, NULL); + + return serverResult; + +} + +CalDAVServerResult CalDAV::GetEntryETag(string *calendarEntryHREF, string *eTagValue){ + + CalDAVServerResult serverResult; + CalDAVSendData entryETagGetData; + + // Build the server address. + + string userPrincipalURI = ""; + userPrincipalURI = GetUserPrincipal(); + + if (userPrincipalURI.size() == 0){ + + return serverResult; + + } + + string calendarHomeURI = ""; + calendarHomeURI = GetCalendarHome(userPrincipalURI); + + // Split the path and filename. + + string entryURIPath; + string entryFilename; + + SplitPathFilename(calendarEntryHREF, &entryURIPath, &entryFilename); + + // Build the request for the server. + + string entryETagRequest = "\n" + "\n" + " \n" + " \n" + " \n" + " "; + entryETagRequest += (*calendarEntryHREF); + entryETagRequest += "\n" + ""; + + entryETagGetData.readptr = &entryETagRequest; + entryETagGetData.sizeleft = entryETagRequest.size(); + + // Build the calendar list address. + + struct curl_slist *getETagRequestHeader = NULL; + + getETagRequestHeader = curl_slist_append(getETagRequestHeader, "Depth: 1"); + getETagRequestHeader = curl_slist_append(getETagRequestHeader, "Prefer: return-minimal"); + getETagRequestHeader = curl_slist_append(getETagRequestHeader, "Content-Type: application/xml; charset=utf-8"); + + string getETagURLAddress = BuildServerAddress(&connectionData, entryURIPath); + + curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, getETagRequestHeader); + curl_easy_setopt(connectionHandle, CURLOPT_URL, getETagURLAddress.c_str()); + curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, "REPORT"); + curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 1L); + curl_easy_setopt(connectionHandle, CURLOPT_READDATA, &entryETagGetData); + curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, CalDAVSend); + + // Attempt to get the entity tag. + + serverData.clear(); + serverHeader.clear(); + + CURLcode serverConnectionResult = curl_easy_perform(connectionHandle); + + if (serverConnectionResult == CURLE_OK){ + serverResult.result = CALDAVQUERYRESULT_OK; + } else { + serverResult.result = CALDAVQUERYRESULT_SERVERERROR; + } + serverResult.code = serverConnectionResult; + curl_easy_getinfo(connectionHandle, CURLINFO_RESPONSE_CODE, &serverResult.httpCode); + + if (serverConnectionResult != CURLE_OK){ + return serverResult; + } + + // Get the entity tag from the result. + + *eTagValue = ProcessXMLEntryETag(); + + // Restore the original settings. + + string originalServerAddress = BuildServerAddress(&connectionData, "/principals/"); + curl_easy_setopt(connectionHandle, CURLOPT_URL, originalServerAddress.c_str()); + curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, NULL); + curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 0L); + curl_easy_setopt(connectionHandle, CURLOPT_READDATA, NULL); + curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, NULL); + curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, NULL); + + return serverResult; + +} + +CalDAVServerResult CalDAV::AddEntry(string *calendarEntryHREF, string *entryData){ + + // Add an entry to the calendar collection. + + CalDAVServerResult serverResult; + CalDAVSendData entryAddSendData; + + // Build the calendar list address. + + string entryAddURLAddress = BuildServerAddress(&connectionData, (*calendarEntryHREF)); + + entryAddSendData.readptr = entryData; + entryAddSendData.sizeleft = entryData->size(); + + struct curl_slist *calendarRequestHeader = NULL; + + calendarRequestHeader = curl_slist_append(calendarRequestHeader, "Content-Type: text/calendar; charset=utf-8"); + + curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, calendarRequestHeader); + curl_easy_setopt(connectionHandle, CURLOPT_URL, entryAddURLAddress.c_str()); + curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, "PUT"); + curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 1L); + curl_easy_setopt(connectionHandle, CURLOPT_READDATA, &entryAddSendData); + curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, CalDAVSend); + + // Process the data. + + serverData.clear(); + serverHeader.clear(); + + CURLcode serverConnectionResult = curl_easy_perform(connectionHandle); + + if (serverConnectionResult == CURLE_OK){ + serverResult.result = CALDAVQUERYRESULT_OK; + } else { + serverResult.result = CALDAVQUERYRESULT_SERVERERROR; + } + serverResult.code = serverConnectionResult; + curl_easy_getinfo(connectionHandle, CURLINFO_RESPONSE_CODE, &serverResult.httpCode); + + // Restore the original settings. + + string originalServerAddress = BuildServerAddress(&connectionData, "/principals/"); + curl_easy_setopt(connectionHandle, CURLOPT_URL, originalServerAddress.c_str()); + curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, NULL); + curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 0L); + curl_easy_setopt(connectionHandle, CURLOPT_READDATA, NULL); + curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, NULL); + curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, NULL); + + return serverResult; + +} + +CalDAVServerResult CalDAV::EditEntry(string *calendarEntryHREF, string *entryData, string *entryETag){ + + // Edit an entry in the calendar collection. + + // Add an entry to the calendar collection. + + CalDAVServerResult serverResult; + CalDAVSendData entryAddSendData; + + // Build the calendar list address. + + string entryAddURLAddress = BuildServerAddress(&connectionData, (*calendarEntryHREF)); + + entryAddSendData.readptr = entryData; + entryAddSendData.sizeleft = entryData->size(); + + string ifMatchHeader = "If-Match: \""; + ifMatchHeader.append(*entryETag); + ifMatchHeader.append("\""); + + struct curl_slist *calendarRequestHeader = NULL; + + calendarRequestHeader = curl_slist_append(calendarRequestHeader, "Content-Type: text/calendar; charset=utf-8"); + calendarRequestHeader = curl_slist_append(calendarRequestHeader, ifMatchHeader.c_str()); + + curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, calendarRequestHeader); + curl_easy_setopt(connectionHandle, CURLOPT_URL, entryAddURLAddress.c_str()); + curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, "PUT"); + curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 1L); + curl_easy_setopt(connectionHandle, CURLOPT_READDATA, &entryAddSendData); + curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, CalDAVSend); + + // Process the data. + + serverData.clear(); + serverHeader.clear(); + + CURLcode serverConnectionResult = curl_easy_perform(connectionHandle); + + if (serverConnectionResult == CURLE_OK){ + serverResult.result = CALDAVQUERYRESULT_OK; + } else { + serverResult.result = CALDAVQUERYRESULT_SERVERERROR; + } + serverResult.code = serverConnectionResult; + curl_easy_getinfo(connectionHandle, CURLINFO_RESPONSE_CODE, &serverResult.httpCode); + + // Restore the original settings. + + string originalServerAddress = BuildServerAddress(&connectionData, "/principals/"); + curl_easy_setopt(connectionHandle, CURLOPT_URL, originalServerAddress.c_str()); + curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, NULL); + curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 0L); + curl_easy_setopt(connectionHandle, CURLOPT_READDATA, NULL); + curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, NULL); + curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, NULL); + + return serverResult; + +} + +CalDAVServerResult CalDAV::DeleteEntry(string *calendarEntryHREF){ + + // Delete an entry in the calendar collection. + + CalDAVServerResult serverResult; + + // Build the calendar list address. + + string entryDeleteURLAddress = BuildServerAddress(&connectionData, (*calendarEntryHREF)); + + curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, NULL); + curl_easy_setopt(connectionHandle, CURLOPT_URL, entryDeleteURLAddress.c_str()); + curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, "DELETE"); + + // Delete the calendar. + + serverData.clear(); + serverHeader.clear(); + + CURLcode serverConnectionResult = curl_easy_perform(connectionHandle); + + if (serverConnectionResult == CURLE_OK){ + serverResult.result = CALDAVQUERYRESULT_OK; + } else { + serverResult.result = CALDAVQUERYRESULT_SERVERERROR; + } + serverResult.code = serverConnectionResult; + curl_easy_getinfo(connectionHandle, CURLINFO_RESPONSE_CODE, &serverResult.httpCode); + + // Restore the original settings. + + string originalServerAddress = BuildServerAddress(&connectionData, "/principals/"); + curl_easy_setopt(connectionHandle, CURLOPT_URL, originalServerAddress.c_str()); + curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, NULL); + curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 0L); + curl_easy_setopt(connectionHandle, CURLOPT_READDATA, NULL); + curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, NULL); + curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, NULL); + + return serverResult; + +} + +bool CalDAVObjectValidSettings(CalDAVConnectionData *connData){ // Check if the passed CalDAV Connection Data is has // an address set. Return false if nullptr is used. - if (ConnData == nullptr){ + if (connData == nullptr){ return false; @@ -14,7 +1474,7 @@ bool CalDAVObjectValidSettings(CalDAVConnectionData *ConnData){ // Check the server hostname. Return false // if no value has been set. - if (ConnData->Hostname.size() > 0){ + if (connData->hostname.size() == 0){ return false; @@ -24,7 +1484,7 @@ bool CalDAVObjectValidSettings(CalDAVConnectionData *ConnData){ // no value has been set or the port number // is less than 1 or higher than 65535. - if (ConnData->Port < 1 || ConnData->Port > 65535){ + if (connData->port < 1 || connData->port > 65535){ return false; @@ -32,16 +1492,20 @@ bool CalDAVObjectValidSettings(CalDAVConnectionData *ConnData){ // Check the server username. Return false // if no value has been set. - - if (ConnData->Username.size() > 0){ + + if (connData->username.size() == 0){ + return false; - } - + + } + // Check the server password. Return false // if no value has been set. - - if (ConnData->Password.size() > 0){ + + if (connData->password.size() == 0){ + return false; + } // Cannot check UseSSL: It is either true @@ -55,4 +1519,32 @@ bool CalDAVObjectValidSettings(CalDAVConnectionData *ConnData){ return true; +} + +string BuildServerAddress(CalDAVConnectionData *connData, string uriAddress){ + + string serverAddress; + + // Setup the server address. + + if (connData->useSSL == true){ + serverAddress += "https://"; + } else { + serverAddress += "http://"; + } + + serverAddress += connData->hostname; + + // Check if server port is 80, otherwise + // specifiy the port number in the address. + + if (connData->port != 80){ + serverAddress += ":"; + serverAddress += to_string(connData->port); + } + + serverAddress += uriAddress; + + return serverAddress; + } \ No newline at end of file