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 CalDAVReceive(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;
35 size_t CalDAVSend(char *SendBuffer, size_t Size, size_t NewMemoryBytes, void *DataStruct){
37 struct CalDAVSendData *UploadPtr = (struct CalDAVSendData *)DataStruct;
39 if (UploadPtr->sizeleft){
41 UploadPtr->sizeleft--;
44 CharSend = (*UploadPtr->readptr)[UploadPtr->seek];
46 *SendBuffer = CharSend;
60 // Setup the objects within the CalDAV connection
63 ConnectionHandle = curl_easy_init();
69 // Destory the objects within the CalDAV connection
72 curl_easy_cleanup(ConnectionHandle);
73 ConnectionHandle = nullptr;
77 void CalDAV::SetupConnectionData(CalDAVConnectionData *ConnData){
79 // Check if ConnData is a nullptr, return if it is.
81 if (ConnData == nullptr){
85 // Set the connection settings to the values from ConnData.
87 ConnectionData = (*ConnData);
91 CalDAVStatus CalDAV::GetConnectionData(){
93 // Get the current connection settings for the CalDAV
94 // connection object and return a CalDAVStatus object.
96 CalDAVStatus ConnectionStatus;
98 ConnectionStatus.Hostname = ConnectionData.Hostname;
99 ConnectionStatus.Port = ConnectionData.Port;
100 ConnectionStatus.Username = ConnectionData.Username;
101 ConnectionStatus.Prefix = ConnectionData.Prefix;
102 ConnectionStatus.UseSSL = ConnectionData.UseSSL;
103 ConnectionStatus.Timeout = ConnectionData.Timeout;
105 return ConnectionStatus;
109 CalDAVServerResult CalDAV::Connect(){
111 CalDAVServerResult ServerResult;
113 string ServerAddress = "";
114 string ServerUserPass = "";
116 // Setup the server address.
118 ServerAddress = BuildServerAddress(&ConnectionData, "/principals/");
120 // Setup the server password.
122 ServerUserPass += ConnectionData.Username;
123 ServerUserPass += ":";
124 ServerUserPass += ConnectionData.Password;
126 curl_easy_setopt(ConnectionHandle, CURLOPT_URL, ServerAddress.c_str());
127 curl_easy_setopt(ConnectionHandle, CURLOPT_USERPWD, ServerUserPass.c_str());
128 curl_easy_setopt(ConnectionHandle, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST);
129 curl_easy_setopt(ConnectionHandle, CURLOPT_FAILONERROR, 1L);
130 curl_easy_setopt(ConnectionHandle, CURLOPT_TIMEOUT, ConnectionData.Timeout);
131 curl_easy_setopt(ConnectionHandle, CURLOPT_WRITEFUNCTION, CalDAVReceive);
132 curl_easy_setopt(ConnectionHandle, CURLOPT_WRITEDATA, &ServerData);
133 curl_easy_setopt(ConnectionHandle, CURLOPT_WRITEHEADER, &ServerHeader);
135 // Connect to the CalDAV server.
137 ServerResult.Code = curl_easy_perform(ConnectionHandle);
139 // Process the result received from the server.
141 if (ServerResult.Code != CURLE_OK){
143 ServerResult.Result = CALDAVQUERYRESULT_SERVERERROR;
147 ServerResult.Result = CALDAVQUERYRESULT_OK;
151 // Get the HTTP code.
153 curl_easy_getinfo(ConnectionHandle, CURLINFO_RESPONSE_CODE, &ServerResult.HTTPCode);
159 CalDAVServerResult CalDAV::GetServerResult(){
161 return ConnectionServerResult;
165 CalDAVServerSupport CalDAV::GetServerSupport(){
167 CalDAVServerSupport ServerStatus;
169 // Setup the server connection.
171 curl_easy_setopt(ConnectionHandle, CURLOPT_CUSTOMREQUEST, "OPTIONS");
173 CURLcode ServerResult = curl_easy_perform(ConnectionHandle);
175 if (ServerResult != CURLE_OK){
179 // Check that the server header has data in,
180 // otherwise return an "empty" CalDAVServerSupport.
182 if (ServerHeader.size() == 0){
186 // Process each line looking for the first DAV header
189 bool NewlineMode = true;
193 for (int CharSeek = 0; CharSeek < ServerHeader.size(); CharSeek++){
195 if (NewlineMode == true){
197 // Check if we have reached the end of the string.
199 if (CharSeek >= ServerHeader.size()){
205 // Check the first four letters to make sure
208 string DAVHeaderCheck = "";
211 DAVHeaderCheck = ServerHeader.substr(CharSeek, 4);
214 catch (out_of_range &oor){
218 if (DAVHeaderCheck == "DAV:"){
222 for (; CharSeek < ServerHeader.size(); CharSeek++){
224 if (ServerHeader[CharSeek] == '\n'){
230 DAVLine.push_back(ServerHeader[CharSeek]);
242 if (ServerHeader[CharSeek] == '\n'){
250 // Process the DAV line.
252 vector<string> DAVLineData;
253 string DAVSegmentString;
255 for (int CharSeek = 0; CharSeek < DAVLine.size(); CharSeek++){
257 if (DAVLine[CharSeek] == ' '){
261 if (DAVLine[CharSeek] == ','){
263 DAVLineData.push_back(DAVSegmentString);
264 DAVSegmentString.clear();
269 DAVSegmentString += DAVLine[CharSeek];
273 // Process the DAV values and set each value
274 // to true as required.
276 for (int DAVItemSeek = 0;
277 DAVItemSeek < DAVLineData.size();
280 if (DAVLineData.at(DAVItemSeek) == "calendar-access"){
282 ServerStatus.BasicSupport = true;
292 bool CalDAVObjectValidSettings(CalDAVConnectionData *ConnData){
294 // Check if the passed CalDAV Connection Data is has
295 // an address set. Return false if nullptr is used.
297 if (ConnData == nullptr){
303 // Check the server hostname. Return false
304 // if no value has been set.
306 if (ConnData->Hostname.size() == 0){
312 // Check the server port. Return false if
313 // no value has been set or the port number
314 // is less than 1 or higher than 65535.
316 if (ConnData->Port < 1 || ConnData->Port > 65535){
322 // Check the server username. Return false
323 // if no value has been set.
325 if (ConnData->Username.size() == 0){
331 // Check the server password. Return false
332 // if no value has been set.
334 if (ConnData->Password.size() == 0){
340 // Cannot check UseSSL: It is either true
343 // Cannot check Prefix: The prefix may need
344 // to be worked out first.
346 // No errors were found whilst checking so
353 string BuildServerAddress(CalDAVConnectionData *ConnData, string URIAddress){
355 string ServerAddress;
357 // Setup the server address.
359 if (ConnData->UseSSL == true){
360 ServerAddress += "https://";
362 ServerAddress += "http://";
365 ServerAddress += ConnData->Hostname;
367 // Check if server port is 80, otherwise
368 // specifiy the port number in the address.
370 if (ConnData->Port != 80){
371 ServerAddress += ":";
372 ServerAddress += to_string(ConnData->Port);
375 ServerAddress += URIAddress;
377 return ServerAddress;