1 // CalDAV.cpp - CalDAV Connection Object.
3 // (c) 2016 Xestia Software Development.
5 // This file is part of Xestia Calendar.
7 // Xestia Address Book 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 Address Book 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 CalDAVOutput(char *ReceivedBuffer, size_t Size, size_t NewMemoryBytes, string *StringPointer)
26 string ReceivedBufferString = "";
27 ReceivedBufferString.append(ReceivedBuffer, NewMemoryBytes);
29 StringPointer->append(ReceivedBufferString);
31 return Size * NewMemoryBytes;
37 // Setup the objects within the CalDAV connection
40 ConnectionHandle = curl_easy_init();
46 // Destory the objects within the CalDAV connection
49 curl_easy_cleanup(ConnectionHandle);
50 ConnectionHandle = nullptr;
54 void CalDAV::SetupConnectionData(CalDAVConnectionData *ConnData){
56 // Check if ConnData is a nullptr, return if it is.
58 if (ConnData == nullptr){
62 // Set the connection settings to the values from ConnData.
64 ConnectionData = (*ConnData);
68 CalDAVStatus CalDAV::GetConnectionData(){
70 // Get the current connection settings for the CalDAV
71 // connection object and return a CalDAVStatus object.
73 CalDAVStatus ConnectionStatus;
75 ConnectionStatus.Hostname = ConnectionData.Hostname;
76 ConnectionStatus.Port = ConnectionData.Port;
77 ConnectionStatus.Username = ConnectionData.Username;
78 ConnectionStatus.Prefix = ConnectionData.Prefix;
79 ConnectionStatus.UseSSL = ConnectionData.UseSSL;
80 ConnectionStatus.Timeout = ConnectionData.Timeout;
82 return ConnectionStatus;
86 CalDAVServerResult CalDAV::Connect(){
88 CalDAVServerResult ServerResult;
90 string ServerAddress = "";
91 string ServerUserPass = "";
93 // Setup the server address.
95 ServerAddress = BuildServerAddress(&ConnectionData, "/principals/");
97 // Setup the server password.
99 ServerUserPass += ConnectionData.Username;
100 ServerUserPass += ":";
101 ServerUserPass += ConnectionData.Password;
103 curl_easy_setopt(ConnectionHandle, CURLOPT_URL, ServerAddress.c_str());
104 curl_easy_setopt(ConnectionHandle, CURLOPT_USERPWD, ServerUserPass.c_str());
105 curl_easy_setopt(ConnectionHandle, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST);
106 curl_easy_setopt(ConnectionHandle, CURLOPT_FAILONERROR, 1L);
107 curl_easy_setopt(ConnectionHandle, CURLOPT_TIMEOUT, ConnectionData.Timeout);
108 curl_easy_setopt(ConnectionHandle, CURLOPT_WRITEFUNCTION, CalDAVOutput);
109 curl_easy_setopt(ConnectionHandle, CURLOPT_WRITEDATA, &ServerData);
110 curl_easy_setopt(ConnectionHandle, CURLOPT_WRITEHEADER, &ServerHeader);
112 // Connect to the CalDAV server.
114 ServerResult.Code = curl_easy_perform(ConnectionHandle);
116 // Process the result received from the server.
118 if (ServerResult.Code != CURLE_OK){
120 ServerResult.Result = CALDAVQUERYRESULT_SERVERERROR;
124 ServerResult.Result = CALDAVQUERYRESULT_OK;
128 // Get the HTTP code.
130 curl_easy_getinfo(ConnectionHandle, CURLINFO_RESPONSE_CODE, &ServerResult.HTTPCode);
136 CalDAVServerSupport CalDAV::GetServerSupport(){
138 CalDAVServerSupport ServerStatus;
140 // Setup the server connection.
142 curl_easy_setopt(ConnectionHandle, CURLOPT_CUSTOMREQUEST, "OPTIONS");
144 CURLcode ServerResult = curl_easy_perform(ConnectionHandle);
146 if (ServerResult != CURLE_OK){
150 // Check that the server header has data in,
151 // otherwise return an "empty" CalDAVServerSupport.
153 if (ServerHeader.size() == 0){
157 // Process each line looking for the first DAV header
160 bool NewlineMode = true;
164 for (int CharSeek = 0; CharSeek < ServerHeader.size(); CharSeek++){
166 if (NewlineMode == true){
168 // Check if we have reached the end of the string.
170 if (CharSeek >= ServerHeader.size()){
176 // Check the first four letters to make sure
179 string DAVHeaderCheck = "";
182 DAVHeaderCheck = ServerHeader.substr(CharSeek, 4);
185 catch (out_of_range &oor){
189 if (DAVHeaderCheck == "DAV:"){
193 for (; CharSeek < ServerHeader.size(); CharSeek++){
195 if (ServerHeader[CharSeek] == '\n'){
201 DAVLine.push_back(ServerHeader[CharSeek]);
213 if (ServerHeader[CharSeek] == '\n'){
221 // Process the DAV line.
223 vector<string> DAVLineData;
224 string DAVSegmentString;
226 for (int CharSeek = 0; CharSeek < DAVLine.size(); CharSeek++){
228 if (DAVLine[CharSeek] == ' '){
232 if (DAVLine[CharSeek] == ','){
234 DAVLineData.push_back(DAVSegmentString);
235 DAVSegmentString.clear();
240 DAVSegmentString += DAVLine[CharSeek];
244 // Process the DAV values and set each value
245 // to true as required.
247 for (int DAVItemSeek = 0;
248 DAVItemSeek < DAVLineData.size();
251 if (DAVLineData.at(DAVItemSeek) == "calendar-access"){
253 ServerStatus.BasicSupport = true;
263 bool CalDAVObjectValidSettings(CalDAVConnectionData *ConnData){
265 // Check if the passed CalDAV Connection Data is has
266 // an address set. Return false if nullptr is used.
268 if (ConnData == nullptr){
274 // Check the server hostname. Return false
275 // if no value has been set.
277 if (ConnData->Hostname.size() == 0){
283 // Check the server port. Return false if
284 // no value has been set or the port number
285 // is less than 1 or higher than 65535.
287 if (ConnData->Port < 1 || ConnData->Port > 65535){
293 // Check the server username. Return false
294 // if no value has been set.
296 if (ConnData->Username.size() == 0){
302 // Check the server password. Return false
303 // if no value has been set.
305 if (ConnData->Password.size() == 0){
311 // Cannot check UseSSL: It is either true
314 // Cannot check Prefix: The prefix may need
315 // to be worked out first.
317 // No errors were found whilst checking so
324 string BuildServerAddress(CalDAVConnectionData *ConnData, string URIAddress){
326 string ServerAddress;
328 // Setup the server address.
330 if (ConnData->UseSSL == true){
331 ServerAddress += "https://";
333 ServerAddress += "http://";
336 ServerAddress += ConnData->Hostname;
338 // Check if server port is 80, otherwise
339 // specifiy the port number in the address.
341 if (ConnData->Port != 80){
342 ServerAddress += ":";
343 ServerAddress += to_string(ConnData->Port);
346 ServerAddress += URIAddress;
348 return ServerAddress;