// CalDAV.cpp - CalDAV Connection Object. // // (c) 2016 Xestia Software Development. // // This file is part of Xestia Calendar. // // Xestia Address Book is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by the // Free Software Foundation, version 3 of the license. // // Xestia Address Book is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License along // with Xestia Calendar. If not, see #include "CalDAV.h" using namespace std; size_t CalDAVOutput(char *ReceivedBuffer, size_t Size, size_t NewMemoryBytes, string *StringPointer) { string ReceivedBufferString = ""; ReceivedBufferString.append(ReceivedBuffer, NewMemoryBytes); StringPointer->append(ReceivedBufferString); return Size * NewMemoryBytes; } 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, CalDAVOutput); 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; } CalDAVServerSupport CalDAV::GetServerSupport(){ CalDAVServerSupport ServerStatus; // Setup the server connection. curl_easy_setopt(ConnectionHandle, CURLOPT_CUSTOMREQUEST, "OPTIONS"); CURLcode ServerResult = curl_easy_perform(ConnectionHandle); 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; } } return ServerStatus; } 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){ return false; } // Check the server hostname. Return false // if no value has been set. if (ConnData->Hostname.size() == 0){ return false; } // Check the server port. Return false if // no value has been set or the port number // is less than 1 or higher than 65535. if (ConnData->Port < 1 || ConnData->Port > 65535){ return false; } // Check the server username. Return false // if no value has been set. if (ConnData->Username.size() == 0){ return false; } // Check the server password. Return false // if no value has been set. if (ConnData->Password.size() == 0){ return false; } // Cannot check UseSSL: It is either true // or false. // Cannot check Prefix: The prefix may need // to be worked out first. // No errors were found whilst checking so // return true. 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; }