Home | News | Projects | Releases
Bugs | RFE | Repositories | Help
CalDAV: Implemented SSL support (taken from XAB)
[xestiacalendar/.git] / source / objects / CalDAV / CalDAV.cpp
1 // CalDAV.cpp - CalDAV Connection Object.
2 //
3 // (c) 2016-2017 Xestia Software Development.
4 //
5 // This file is part of Xestia Calendar.
6 //
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.
10 //
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.
15 //
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/>
19 #include "CalDAV.h"
21 using namespace std;
23 size_t CalDAVReceive(char *receivedBuffer, size_t size, size_t newMemoryBytes, string *stringPointer)
24 {
25         
26         stringPointer->append(receivedBuffer, newMemoryBytes);
27         
28         return size * newMemoryBytes;
29         
30 }
32 size_t CalDAVSend(char *sendBuffer, size_t size, size_t newMemoryBytes, void *dataStruct){
34         struct CalDAVSendData *uploadPtr = (struct CalDAVSendData *)dataStruct;
35         
36         if (uploadPtr->sizeleft){
38                 uploadPtr->sizeleft--;
39                 char charSend;
41                 charSend = (*uploadPtr->readptr)[uploadPtr->seek];
42                 
43                 *sendBuffer = charSend;
44                 
45                 uploadPtr->seek++;
47                 return 1;
49         }
51         return 0;
53 }
55 CalDAV::CalDAV(){
57         // Setup the objects within the CalDAV connection 
58         // object.
59         
60         connectionHandle = curl_easy_init();
61         
62 }
64 CalDAV::~CalDAV(){
65         
66         // Destory the objects within the CalDAV connection
67         // object.
68         
69         curl_easy_cleanup(connectionHandle);
70         connectionHandle = nullptr;
71         
72 }
74 void CalDAV::SetupConnectionData(CalDAVConnectionData *connData){
75         
76         // Check if ConnData is a nullptr, return if it is.
77         
78         if (connData == nullptr){
79                 return;
80         }
81         
82         // Set the connection settings to the values from ConnData.
84         connectionData = (*connData);
85         
86 }
88 CalDAVStatus CalDAV::GetConnectionData(){
89         
90         // Get the current connection settings for the CalDAV
91         // connection object and return a CalDAVStatus object.
92         
93         CalDAVStatus connectionStatus;
94         
95         connectionStatus.hostname = connectionData.hostname;
96         connectionStatus.port = connectionData.port;
97         connectionStatus.username = connectionData.username;
98         connectionStatus.prefix = connectionData.prefix;
99         connectionStatus.useSSL = connectionData.useSSL;
100         connectionStatus.timeout = connectionData.timeout;
101         
102         return connectionStatus;
103         
106 CalDAVServerResult CalDAV::Connect(bool doAuthentication){
108         connectionData.useSSL ? SetupDefaultParametersSSL(doAuthentication) : SetupDefaultParametersNonSSL(doAuthentication);
109         ResetResults();
111         CalDAVServerResult serverResult;
113         string serverAddress = "";
114         string serverUserPass = "";
116         // Setup the server address.
117         
118         serverAddress = BuildServerAddress(&connectionData, "/principals/");
120         // Setup the server password.
121         
122         serverUserPass += connectionData.username;
123         serverUserPass += ":";
124         serverUserPass += connectionData.password;
125         
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_ERRORBUFFER, sessionErrorBuffer);
130         curl_easy_setopt(connectionHandle, CURLOPT_FAILONERROR, 1L);
131         curl_easy_setopt(connectionHandle, CURLOPT_TIMEOUT, connectionData.timeout);
132         curl_easy_setopt(connectionHandle, CURLOPT_WRITEFUNCTION, CalDAVReceive);
133         curl_easy_setopt(connectionHandle, CURLOPT_WRITEDATA, &serverData);
134         curl_easy_setopt(connectionHandle, CURLOPT_WRITEHEADER, &serverHeader);
135         
136         // Connect to the CalDAV server.
137         
138         serverResult.code = curl_easy_perform(connectionHandle);
140         // Process the result received from the server.
142         // Get the HTTP code.
143         
144         curl_easy_getinfo(connectionHandle, CURLINFO_RESPONSE_CODE, &serverResult.httpCode);
146         switch(serverResult.code){
147                 case CURLE_OK:
148                         authPassed = true;
149                 case CURLE_HTTP_RETURNED_ERROR:
150                         if (connectionData.useSSL)
151                         {
152                                 sslStatus = connectionData.useSSL;
153                                 sslVerified = COSSL_VERIFIED;
154                         }
155                         serverResult.result = CALDAVQUERYRESULT_OK;
156                         if (serverResult.httpCode == 401)
157                         {
158                                 authPassed = false;
159                         }
160                         break;
161                 case CURLE_SSL_CACERT:
162                 case CURLE_SSL_CONNECT_ERROR:
163                         if (connectionData.useSSL)
164                         {
165                                 sslStatus = connectionData.useSSL;
166                                 sslVerified = COSSL_UNABLETOVERIFY;
167                         }
168                         serverResult.result = CALDAVQUERYRESULT_SSLFAILURE;
169                         authPassed = false;
170                         break;
171                 default:
172                         serverResult.result = CALDAVQUERYRESULT_SERVERERROR;
173                         authPassed = false;
174                         break;
175         };
177         if (serverResult.httpCode >= 200 && serverResult.httpCode <= 299)
178         {
179                 validResponse = true;
180         }
181         
182         return serverResult;
183         
186 CalDAVServerResult CalDAV::GetServerResult(){
187         
188         return connectionServerResult;
189         
192 CalDAVServerSupport CalDAV::GetServerSupport(){
194         CalDAVServerSupport serverStatus;
195         
196         // Setup the server connection.
197         
198         curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, "OPTIONS");
199         
200         CURLcode serverResult = curl_easy_perform(connectionHandle);
201         
202         // Set the results.
203         
204         if (serverResult == CURLE_OK){
205                 connectionServerResult.result = CALDAVQUERYRESULT_OK;
206         } else {
207                 connectionServerResult.result = CALDAVQUERYRESULT_SERVERERROR;          
208         }
209         connectionServerResult.code = serverResult;
210         curl_easy_getinfo(connectionHandle, CURLINFO_RESPONSE_CODE, &connectionServerResult.httpCode);
211         
212         if (serverResult != CURLE_OK){
213                 return serverStatus;
214         }
215         
216         // Check that the server header has data in,
217         // otherwise return an "empty" CalDAVServerSupport.
218         
219         if (serverHeader.size() == 0){
220                 return serverStatus;
221         }
222         
223         // Process each line looking for the first DAV header 
224         // line.
225         
226         bool newlineMode = true;
227         
228         string davLine;
229         
230         for (int charSeek = 0; charSeek < serverHeader.size(); charSeek++){
231                 
232                 if (newlineMode == true){
233                         
234                         // Check if we have reached the end of the string.
235                         
236                         if (charSeek >= serverHeader.size()){
237                                 
238                                 break;
239                                 
240                         }
241                         
242                         // Check the first four letters to make sure
243                         // they are 'DAV:'.
244                         
245                         string davHeaderCheck = "";
246                         
247                         try {
248                                 davHeaderCheck = serverHeader.substr(charSeek, 4);
249                         }
250                         
251                         catch (out_of_range &oor){
252                                 break;
253                         }
254                         
255                         if (davHeaderCheck == "DAV:"){
256                                 
257                                 charSeek += 5;
258                                 
259                                 for (; charSeek < serverHeader.size(); charSeek++){
260                                         
261                                         if (serverHeader[charSeek] == '\n'){
262                                         
263                                                 break;
264                                                 
265                                         }
266                                         
267                                         davLine.push_back(serverHeader[charSeek]);
268                                         
269                                 }
270                                 
271                                 break;
272                                 
273                         }
274                         
275                         newlineMode = false;
276                         
277                 }
278                 
279                 if (serverHeader[charSeek] == '\n'){
280                         
281                         newlineMode = true;
282                         
283                 }
284                 
285         }
286         
287         // Process the DAV line.
288         
289         vector<string> davLineData;
290         string davSegmentString;
291         
292         for (int charSeek = 0; charSeek < davLine.size(); charSeek++){
293                 
294                 if (davLine[charSeek] == ' '){
295                         continue;
296                 }
297                 
298                 if (davLine[charSeek] == ','){
299                         
300                         davLineData.push_back(davSegmentString);
301                         davSegmentString.clear();
302                         continue;
303                         
304                 }
305                 
306                 davSegmentString += davLine[charSeek];
307                 
308         }
309         
310         // Process the DAV values and set each value
311         // to true as required.
312         
313         for (int davItemSeek = 0; 
314                 davItemSeek < davLineData.size();
315                 davItemSeek++){
316                         
317                 if (davLineData.at(davItemSeek) == "calendar-access"){
318                         
319                         serverStatus.basicSupport = true;
320                 
321                 }
322                         
323         }
324         
325         // Reset the connection status.
326         
327         curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, NULL);
328         
329         return serverStatus;
330         
333 string CalDAV::GetUserPrincipal(){
334         
335         string currentUserPrincipal = "";
336         string userPrincipalRequest = "";
337         CalDAVSendData userPrincipalSendData;
338         
339         userPrincipalRequest = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
340         "<d:propfind xmlns:d=\"DAV:\">\n"
341         " <d:prop>\n"
342         "  <d:current-user-principal />\n"
343         " </d:prop>\n"
344         "</d:propfind>";
345         
346         userPrincipalSendData.readptr = &userPrincipalRequest;
347         userPrincipalSendData.sizeleft = userPrincipalRequest.size();
348         
349         // Setup the header.
350         
351         struct curl_slist *userPrincipalRequestHeader = NULL;
352         
353         userPrincipalRequestHeader = curl_slist_append(userPrincipalRequestHeader, "Depth: 0");
354         userPrincipalRequestHeader = curl_slist_append(userPrincipalRequestHeader, "Prefer: return-minimal");
355         userPrincipalRequestHeader = curl_slist_append(userPrincipalRequestHeader, "Content-Type: application/xml; charset=utf-8");
356         
357         curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, userPrincipalRequestHeader);
359         curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, "PROPFIND");
360         curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 1L);
361         curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
362         curl_easy_setopt(connectionHandle, CURLOPT_READDATA, &userPrincipalSendData);
363         curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, CalDAVSend);
364         
365         // Process the data.
366         
367         serverData.clear();
368         serverHeader.clear();
369         
370         CURLcode serverResult = curl_easy_perform(connectionHandle);
371         
372         // Set the results.
373         
374         if (serverResult == CURLE_OK){
375                 connectionServerResult.result = CALDAVQUERYRESULT_OK;
376         } else {
377                 connectionServerResult.result = CALDAVQUERYRESULT_SERVERERROR;          
378         }
379         connectionServerResult.code = serverResult;
380         curl_easy_getinfo(connectionHandle, CURLINFO_RESPONSE_CODE, &connectionServerResult.httpCode);
381         
382         if (serverResult != CURLE_OK){
383                 
384                 return currentUserPrincipal;
385                 
386         }
387         
388         // Process the User Principal from the ServerData.
390         currentUserPrincipal = ProcessXMLUserPrincipal();
391         
392         // Reset the changed settings.
393         
394         curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 0L);
395         curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
396         curl_easy_setopt(connectionHandle, CURLOPT_READDATA, NULL);
397         curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, NULL);
399         return currentUserPrincipal;
403 string CalDAV::GetCalendarHome(string userPrincipalURI){
404         
405         string calendarHomeURI = "";
407         // Build the Calendar Home URL address.
408         
409         string calendarHomeURL = BuildServerAddress(&connectionData, userPrincipalURI);
410         
411         // Setup the header request.
412         
413         CalDAVSendData calendarHomeSendData;
414         
415         string calendarHomeRequest = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
416         "<d:propfind xmlns:d=\"DAV:\" xmlns:c=\"urn:ietf:params:xml:ns:caldav\">\n"
417         " <d:prop>\n"
418         "  <c:calendar-home-set />\n"
419         " </d:prop>\n"
420         "</d:propfind>";
421         
422         calendarHomeSendData.readptr = &calendarHomeRequest;
423         calendarHomeSendData.sizeleft = calendarHomeRequest.size();
424         
425         // Setup the header.
426         
427         struct curl_slist *calendarRequestHeader = NULL;
428         
429         calendarRequestHeader = curl_slist_append(calendarRequestHeader, "Depth: 0");
430         calendarRequestHeader = curl_slist_append(calendarRequestHeader, "Prefer: return-minimal");
431         calendarRequestHeader = curl_slist_append(calendarRequestHeader, "Content-Type: application/xml; charset=utf-8");
432         
433         curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, calendarRequestHeader);
434         curl_easy_setopt(connectionHandle, CURLOPT_URL, calendarHomeURL.c_str());
435         curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, "PROPFIND");
436         curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 1L);
437         curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
438         curl_easy_setopt(connectionHandle, CURLOPT_READDATA, &calendarHomeSendData);
439         curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, CalDAVSend);
440         
441         // Process the data.
442         
443         serverData.clear();
444         serverHeader.clear();
445         
446         CURLcode serverResult = curl_easy_perform(connectionHandle);
447         
448         // Set the results.
449         
450         if (serverResult == CURLE_OK){
451                 connectionServerResult.result = CALDAVQUERYRESULT_OK;
452         } else {
453                 connectionServerResult.result = CALDAVQUERYRESULT_SERVERERROR;          
454         }
455         connectionServerResult.code = serverResult;
456         curl_easy_getinfo(connectionHandle, CURLINFO_RESPONSE_CODE, &connectionServerResult.httpCode);
457         
458         if (serverResult != CURLE_OK){
459                 
460                 return calendarHomeURI;
461                 
462         }
463         
464         // Process the User Principal from the ServerData.
466         calendarHomeURI = ProcessXMLCalendarHome();
467         
468         // Reset the changed settings.
469         
470         string originalServerAddress = BuildServerAddress(&connectionData, "/principals/");
471         curl_easy_setopt(connectionHandle, CURLOPT_URL, originalServerAddress.c_str());
472         
473         curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 0L);
474         curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
475         curl_easy_setopt(connectionHandle, CURLOPT_READDATA, NULL);
476         curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, NULL);
477         curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, NULL);
478         
479         return calendarHomeURI;
480         
483 CalDAVCalendarList CalDAV::GetCalendars(){
484         
485         CalDAVCalendarList serverList;
486         CalDAVSendData calendarListSendData;
487         
488         // Build the server address.
489         
490         string userPrincipalURI = "";
491         userPrincipalURI = GetUserPrincipal();
492         
493         if (userPrincipalURI.size() == 0){
494                 
495                 return serverList;
496                 
497         }
498         
499         string calendarHomeURI = "";
500         calendarHomeURI = GetCalendarHome(userPrincipalURI);
501         
502         string calendarListURLAddress = BuildServerAddress(&connectionData, calendarHomeURI);
503         
504         string calendarListRequest = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
505         "<d:propfind xmlns:d=\"DAV:\" xmlns:cs=\"http://calendarserver.org/ns/\""
506         " xmlns:c=\"urn:ietf:params:xml:ns:caldav\" xmlns:x0=\"http://apple.com/ns/ical/\">\n"
507         " <d:prop>\n"
508         "  <d:resourcetype />\n"
509         "  <d:displayname />\n"
510         "  <d:sync-token />\n"
511         "  <x0:calendar-color />\n"
512         "  <x0:calendar-order />\n"
513         "  <cs:getctag />\n"
514         "  <c:supported-calendar-component-set />\n"
515         "  <c:calendar-description />\n"
516         " </d:prop>\n"
517         "</d:propfind>";
518         
519         calendarListSendData.readptr = &calendarListRequest;
520         calendarListSendData.sizeleft = calendarListRequest.size();
521         
522         // Setup the header.
523         
524         struct curl_slist *calendarListRequestHeader = NULL;
525         
526         calendarListRequestHeader = curl_slist_append(calendarListRequestHeader, "Depth: 1");
527         calendarListRequestHeader = curl_slist_append(calendarListRequestHeader, "Prefer: return-minimal");
528         calendarListRequestHeader = curl_slist_append(calendarListRequestHeader, "Content-Type: application/xml; charset=utf-8");
529         
530         curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, calendarListRequestHeader);
531         curl_easy_setopt(connectionHandle, CURLOPT_URL, calendarListURLAddress.c_str());
532         curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, "PROPFIND");
533         curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 1L);
534         curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
535         curl_easy_setopt(connectionHandle, CURLOPT_READDATA, &calendarListSendData);
536         curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, CalDAVSend);
537         
538         // Process the data.
539         
540         serverData.clear();
541         serverHeader.clear();
542         
543         CURLcode serverResult = curl_easy_perform(connectionHandle);
544         
545         //ServerList = ProcessXMLCalendarList();
546         
547         if (serverResult == CURLE_OK){
548                 connectionServerResult.result = CALDAVQUERYRESULT_OK;
549         } else {
550                 connectionServerResult.result = CALDAVQUERYRESULT_SERVERERROR;          
551         }
552         connectionServerResult.code = serverResult;
553         curl_easy_getinfo(connectionHandle, CURLINFO_RESPONSE_CODE, &connectionServerResult.httpCode);
554         
555         if (serverResult != CURLE_OK){
556                 
557                 return serverList;
558                 
559         }
560         
561         // Process the received XML data into a list of calendars
562         // and locations.
563         
564         serverList = ProcessXMLCalendarList();
565         
566         // Restore the original settings.
567         
568         string originalServerAddress = BuildServerAddress(&connectionData, "/principals/");
569         
570         curl_easy_setopt(connectionHandle, CURLOPT_URL, originalServerAddress.c_str());
571         curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, NULL);        
572         curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 0L);
573         curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
574         curl_easy_setopt(connectionHandle, CURLOPT_READDATA, NULL);
575         curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, NULL);
576         
577         return serverList;
578         
581 CalDAVEntryList CalDAV::GetEntryList(string *calendarHREF){
582         
583         CalDAVEntryList entryList;
584         CalDAVSendData entryListSendData;
585         
586         if (calendarHREF->size() == 0){
587                 
588                 return entryList;
589                 
590         }
591         
592         string entryListURLAddress = BuildServerAddress(&connectionData, *calendarHREF);
593         
594         string entryListRequest = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
595         
596         /*if (CalendarTag == nullptr){*/
597                 
598         entryListRequest += "<c:calendar-query xmlns:d=\"DAV:\" xmlns:cs=\"http://calendarserver.org/ns/\""
599         " xmlns:c=\"urn:ietf:params:xml:ns:caldav\" xmlns:x0=\"http://apple.com/ns/ical/\">\n"
600         " <d:prop>\n"
601         "  <d:getetag />\n"
602         "  <c:calendar-data />\n"
603         " </d:prop>\n"
604         " <c:filter>\n"
605         "  <c:comp-filter name=\"VCALENDAR\" />\n"
606         " </c:filter>\n"
607         "</c:calendar-query>";
608                 
609         /*} else {
611                 EntryListRequest += "<d:sync-collection xmlns:d=\"DAV:\" xmlns:cs=\"http://calendarserver.org/ns/\""
612                 " xmlns:c=\"urn:ietf:params:xml:ns:caldav\" xmlns:x0=\"http://apple.com/ns/ical/\">\n"          
613                 " <d:sync-token>";
614                 EntryListRequest += *CalendarTag;
615                 EntryListRequest += "</d:sync-token>\n"
616                 " <d:sync-level>1</d:sync-level>\n"
617                 " <d:prop>\n"
618                 "  <d:getetag />\n"
619                 "  <c:calendar-data />\n"
620                 " </d:prop>\n"
621                 "</d:sync-collection>";
622                 
623         }*/
624         
625         entryListSendData.readptr = &entryListRequest;
626         entryListSendData.sizeleft = entryListRequest.size();
627         
628         struct curl_slist *entryListRequestHeader = NULL;
629         
630         entryListRequestHeader = curl_slist_append(entryListRequestHeader, "Content-Type: application/xml; charset=utf-8");
631         
632         /*if (CalendarTag != nullptr){
633         
634                 EntryListRequestHeader = curl_slist_append(EntryListRequestHeader, "Content-Type: application/xml; charset=utf-8");
635                 EntryListRequestHeader = curl_slist_append(EntryListRequestHeader, "Content-Type: application/xml; charset=utf-8");
636                 
637         }*/
638         
639         curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, entryListRequestHeader);
640         curl_easy_setopt(connectionHandle, CURLOPT_URL, entryListURLAddress.c_str());
641         curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, "REPORT");
642         curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 1L);
643         curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
644         curl_easy_setopt(connectionHandle, CURLOPT_READDATA, &entryListSendData);
645         curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, CalDAVSend);
646         
647         // Process the data.
648         
649         serverData.clear();
650         serverHeader.clear();
651         
652         CURLcode serverResult = curl_easy_perform(connectionHandle);
653         
654         //ServerList = ProcessXMLCalendarList();
655         
656         if (serverResult == CURLE_OK){
657                 connectionServerResult.result = CALDAVQUERYRESULT_OK;
658         } else {
659                 connectionServerResult.result = CALDAVQUERYRESULT_SERVERERROR;          
660         }
661         connectionServerResult.code = serverResult;
662         curl_easy_getinfo(connectionHandle, CURLINFO_RESPONSE_CODE, &connectionServerResult.httpCode);
663         
664         if (serverResult != CURLE_OK){
665                 
666                 return entryList;
667                 
668         }
669         
670         // Process the received XML data into a list of calendars
671         // and locations.
672         
673         entryList = ProcessXMLEntryList();
674         
675         // Restore the original settings.
676         
677         string originalServerAddress = BuildServerAddress(&connectionData, "/principals/");
678         
679         curl_easy_setopt(connectionHandle, CURLOPT_URL, originalServerAddress.c_str());
680         curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, NULL);        
681         curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 0L);
682         curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
683         curl_easy_setopt(connectionHandle, CURLOPT_READDATA, NULL);
684         curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, NULL);
685         
686         return entryList;
687         
690 CalDAVEntryList CalDAV::GetEntryList(string *calendarHREF, string *calendarTag){
691         
692         CalDAVEntryList entryList;
693         CalDAVSendData entryListSendData;
694         
695         if (calendarHREF->size() == 0){
696                 
697                 return entryList;
698                 
699         }
700         
701         string entryListURLAddress = BuildServerAddress(&connectionData, *calendarHREF);
702         
703         // First query: Get the list of contacts that need to be updated.
704         
705         string entryListRequest = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
707         entryListRequest += "<d:sync-collection xmlns:d=\"DAV:\" xmlns:cs=\"http://calendarserver.org/ns/\""
708         " xmlns:c=\"urn:ietf:params:xml:ns:caldav\" xmlns:x0=\"http://apple.com/ns/ical/\">\n"
709         " <d:sync-token>";
710         
711         if (calendarTag != nullptr){
712         
713                 entryListRequest += *calendarTag;
714                 
715         } else {
716         
717                 entryListRequest += "";
718                 
719         }
721         entryListRequest += "</d:sync-token>\n"
722         " <d:sync-level>1</d:sync-level>\n"
723         " <d:prop>\n"
724         "  <d:getetag />\n"
725         " </d:prop>\n"
726         "</d:sync-collection>";
727         
728         entryListSendData.readptr = &entryListRequest;
729         entryListSendData.sizeleft = entryListRequest.size();
730         
731         struct curl_slist *entryListRequestHeader = NULL;
732         
733         entryListRequestHeader = curl_slist_append(entryListRequestHeader, "Content-Type: application/xml; charset=utf-8");
734         
735         curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, entryListRequestHeader);
736         curl_easy_setopt(connectionHandle, CURLOPT_URL, entryListURLAddress.c_str());
737         curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, "REPORT");
738         curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 1L);
739         curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
740         curl_easy_setopt(connectionHandle, CURLOPT_READDATA, &entryListSendData);
741         curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, CalDAVSend);
742         
743         // Process the data.
744         
745         serverData.clear();
746         serverHeader.clear();
747         
748         CURLcode serverResult = curl_easy_perform(connectionHandle);
749         
750         if (serverResult == CURLE_OK){
751                 connectionServerResult.result = CALDAVQUERYRESULT_OK;
752         } else {
753                 connectionServerResult.result = CALDAVQUERYRESULT_SERVERERROR;          
754         }
755         connectionServerResult.code = serverResult;
756         curl_easy_getinfo(connectionHandle, CURLINFO_RESPONSE_CODE, &connectionServerResult.httpCode);
757         
758         if (serverResult != CURLE_OK){
759                 
760                 return entryList;
761                 
762         }
763         
764         entryList = ProcessXMLSyncTokenList();
765         
766         // Check the last entry matches the HREF and if it 
767         // does then delete it.
768         
769         if (entryList.href.size() > 0) {
770         
771                 if (entryList.href.rbegin()->second == *calendarHREF){
772                         
773                         entryList.href.erase((entryList.href.size() - 1));
774                         entryList.tag.erase((entryList.href.size() - 1));
775                         entryList.data.erase((entryList.href.size() - 1));
776                 
777                 }
778         
779         }
780         
781         // Build the list into a new list for getting the new 
782         // calendar data with.
783         
784         entryListRequest.clear();
785         
786         entryListRequest = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
788         entryListRequest += "<c:calendar-multiget xmlns:d=\"DAV:\" "
789         " xmlns:c=\"urn:ietf:params:xml:ns:caldav\">\n"
790         " <d:prop>\n"
791         "  <d:getetag />\n"
792         "  <c:calendar-data />\n"
793         " </d:prop>\n";
794         
795         for (std::map<int,string>::iterator hrefIter = entryList.href.begin(); 
796                 hrefIter != entryList.href.end(); hrefIter++){
797                 
798                 string entryListHREFString = hrefIter->second;
799                         
800                 entryListRequest += " <d:href>";
801                 entryListRequest += entryListHREFString;
802                 entryListRequest += "</d:href>\n";
803                         
804         }
805         
806         entryListRequest += "</c:calendar-multiget>";
807         
808         CalDAVSendData updatedEntryListSendData;        
809         
810         updatedEntryListSendData.readptr = &entryListRequest;
811         updatedEntryListSendData.sizeleft = entryListRequest.size();
812         
813         curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, entryListRequestHeader);
814         curl_easy_setopt(connectionHandle, CURLOPT_URL, entryListURLAddress.c_str());
815         curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, "REPORT");
816         curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 1L);
817         curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
818         curl_easy_setopt(connectionHandle, CURLOPT_READDATA, &updatedEntryListSendData);
819         curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, CalDAVSend);
820         
821         // Get the updated calendar data.
822         
823         serverData.clear();
824         serverHeader.clear();
825         entryList.href.clear();
826         entryList.tag.clear();
827         entryList.data.clear();
828         
829         serverResult = curl_easy_perform(connectionHandle);
831         // Check the last entry matches the HREF and if it 
832         // does then delete it.
833         
834         if (serverResult == CURLE_OK){
835                 connectionServerResult.result = CALDAVQUERYRESULT_OK;
836         } else {
837                 connectionServerResult.result = CALDAVQUERYRESULT_SERVERERROR;          
838         }
839         connectionServerResult.code = serverResult;
840         curl_easy_getinfo(connectionHandle, CURLINFO_RESPONSE_CODE, &connectionServerResult.httpCode);
841         
842         if (serverResult != CURLE_OK){
843                 
844                 return entryList;
845                 
846         }
847         
848         entryList = ProcessXMLEntryList();
849         
850         // Second query: Get the list of contact data for the contacts that have
851         // beenchanged.
852         
853         // Restore the original settings.
854         
855         string originalServerAddress = BuildServerAddress(&connectionData, "/principals/");
856         
857         curl_easy_setopt(connectionHandle, CURLOPT_URL, originalServerAddress.c_str());
858         curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, NULL);        
859         curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 0L);
860         curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
861         curl_easy_setopt(connectionHandle, CURLOPT_READDATA, NULL);
862         curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, NULL);
863         
864         return entryList;
865         
868 CalDAVServerResult CalDAV::AddCalendar(string calendarName){
869         
870         CalDAVServerResult serverResult;
871         
872         AddCalendar(&calendarName, nullptr);
873         
874         return serverResult;
875         
878 CalDAVServerResult CalDAV::AddCalendar(string *calendarName, string *calendarShortName){
879         
880         CalDAVServerResult serverResult;
881         CalDAVSendData calendarAddSendData;
882         
883         // Build the server address.
884         
885         string userPrincipalURI = "";
886         userPrincipalURI = GetUserPrincipal();
887         
888         if (userPrincipalURI.size() == 0){
889                 
890                 return serverResult;
891                 
892         }
893         
894         string calendarHomeURI = "";
895         calendarHomeURI = GetCalendarHome(userPrincipalURI);
896         
897         // Generate the UUID.
898         
899         string UUIDValue = "";
900         
901         if (calendarShortName == nullptr){
902         
903                 UUIDValue = GenerateUUID();
904                 UUIDValue.erase(UUIDValue.end()-1);
906         } else {
907         
908                 UUIDValue = *calendarShortName;
909                 
910         }
911                 
912         string calendarHomeURL = calendarHomeURI;
913         calendarHomeURL.append(UUIDValue);
914         calendarHomeURL.append("/");
915         
916         // Build the calendar list address.
917         
918         string calendarListURLAddress = BuildServerAddress(&connectionData, calendarHomeURL);
919         
920         string calendarAddRequest = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
921         "<c:mkcalendar xmlns:d=\"DAV:\" xmlns:c=\"urn:ietf:params:xml:ns:caldav\">\n"
922         " <d:set>\n"
923         "  <d:prop>\n"
924         "   <d:displayname>";
925         calendarAddRequest += *calendarName;
926         calendarAddRequest += "</d:displayname>\n"
927         "   <c:supported-calendar-component-set>\n"
928         "    <c:comp name=\"VTODO\"/>\n"
929         "    <c:comp name=\"VEVENT\"/>\n"
930         "   </c:supported-calendar-component-set>\n"
931         "  </d:prop>\n"
932         " </d:set>\n"
933         "</c:mkcalendar>";
934         
935         calendarAddSendData.readptr = &calendarAddRequest;
936         calendarAddSendData.sizeleft = calendarAddRequest.size();
937         
938         // Setup the header.
939         
940         struct curl_slist *calendarRequestHeader = NULL;
941         
942         //curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, CalendarRequestHeader);
943         curl_easy_setopt(connectionHandle, CURLOPT_URL, calendarListURLAddress.c_str());
944         curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, "MKCALENDAR");
945         curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 1L);
946         curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
947         curl_easy_setopt(connectionHandle, CURLOPT_READDATA, &calendarAddSendData);
948         curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, CalDAVSend);
949         
950         // Process the data.
951         
952         serverData.clear();
953         serverHeader.clear();
954         
955         CURLcode serverConnectionResult = curl_easy_perform(connectionHandle);
956         
957         if (serverConnectionResult == CURLE_OK){
958                 serverResult.result = CALDAVQUERYRESULT_OK;
959         } else {
960                 serverResult.result = CALDAVQUERYRESULT_SERVERERROR;            
961         }
962         serverResult.code = serverConnectionResult;
963         curl_easy_getinfo(connectionHandle, CURLINFO_RESPONSE_CODE, &serverResult.httpCode);
964         
965         // Restore the original settings.
966         
967         string originalServerAddress = BuildServerAddress(&connectionData, "/principals/");
968         curl_easy_setopt(connectionHandle, CURLOPT_URL, originalServerAddress.c_str());
969         curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, NULL);        
970         curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 0L);
971         curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
972         curl_easy_setopt(connectionHandle, CURLOPT_READDATA, NULL);
973         curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, NULL);
974         
975         return serverResult;
976         
979 CalDAVServerResult CalDAV::EditCalendarProcess(string *calendarHREF,
980                         string *calendarName,
981                         Colour *calendarColour,
982                         string *calendarDescription,
983                         int *calendarOrder){
985         CalDAVServerResult serverResult;
986         CalDAVSendData calendarEditSendData;
987         
988         // Build the server address.
989         
990         string userPrincipalURI = "";
991         userPrincipalURI = GetUserPrincipal();
992         
993         if (userPrincipalURI.size() == 0){
994                 
995                 return serverResult;
996                 
997         }
998         
999         string calendarHomeURI = "";
1000         calendarHomeURI = GetCalendarHome(userPrincipalURI);
1001         
1002         // Generate the UUID.
1003         
1004         string UUIDValue = GenerateUUID();
1005         UUIDValue.erase(UUIDValue.end()-1);
1006         
1007         string calendarHomeURL = calendarHomeURI;
1008         calendarHomeURL.append(UUIDValue);
1009         calendarHomeURL.append("/");
1010         
1011         // Build the calendar list address.
1012         
1013         string calendarEditURLAddress = BuildServerAddress(&connectionData, (*calendarHREF));
1014         
1015         string calendarEditRequest = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
1016         "<d:propertyupdate xmlns:d=\"DAV:\" xmlns:c=\"urn:ietf:params:xml:ns:caldav\"\n"
1017         "       xmlns:x0=\"http://apple.com/ns/ical/\">\n"
1018         " <d:set>\n"
1019         "  <d:prop>\n";
1020         
1021         // Update the calendar name.
1022         
1023         if (calendarName != nullptr){
1024         
1025                 calendarEditRequest += "<d:displayname>";
1026                 calendarEditRequest += (*calendarName);
1027                 calendarEditRequest += "</d:displayname>\n";
1028                 
1029         }
1030         
1031         // Update the calendar colour.
1032         
1033         if (calendarColour != nullptr){
1034                 
1035                 calendarEditRequest += "<x0:calendar-color>";
1036                 calendarEditRequest += (*calendarColour);
1037                 calendarEditRequest += "</x0:calendar-color>\n";
1038                 
1039         }
1040         
1041         // Update the calendar description.
1042         
1043         if (calendarDescription != nullptr){
1044                 
1045                 calendarEditRequest += "<c:calendar-description>";
1046                 calendarEditRequest += (*calendarDescription);
1047                 calendarEditRequest += "</c:calendar-description>\n";           
1048                 
1049         }
1050         
1051         // Update the calendar order.
1052         
1053         if (calendarOrder != nullptr){
1054                 
1055                 calendarEditRequest += "<x0:calendar-order>";
1056                 calendarEditRequest += to_string((*calendarOrder));
1057                 calendarEditRequest += "</x0:calendar-order>\n";
1058                 
1059         }
1060         
1061         calendarEditRequest += "  </d:prop>\n"
1062         " </d:set>\n"
1063         "</d:propertyupdate>";
1064         
1065         calendarEditSendData.readptr = &calendarEditRequest;
1066         calendarEditSendData.sizeleft = calendarEditRequest.size();
1067         
1068         // Setup the header.
1069         
1070         struct curl_slist *calendarRequestHeader = NULL;
1071         
1072         //curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, CalendarRequestHeader);
1073         curl_easy_setopt(connectionHandle, CURLOPT_URL, calendarEditURLAddress.c_str());
1074         curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, "PROPPATCH");
1075         curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 1L);
1076         curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
1077         curl_easy_setopt(connectionHandle, CURLOPT_READDATA, &calendarEditSendData);
1078         curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, CalDAVSend);
1079         
1080         // Process the data.
1081         
1082         serverData.clear();
1083         serverHeader.clear();
1084         
1085         CURLcode serverConnectionResult = curl_easy_perform(connectionHandle);
1086         
1087         if (serverConnectionResult == CURLE_OK){
1088                 serverResult.result = CALDAVQUERYRESULT_OK;
1089         } else {
1090                 serverResult.result = CALDAVQUERYRESULT_SERVERERROR;            
1091         }
1092         serverResult.code = serverConnectionResult;
1093         curl_easy_getinfo(connectionHandle, CURLINFO_RESPONSE_CODE, &serverResult.httpCode);
1094         
1095         // Restore the original settings.
1096         
1097         string originalServerAddress = BuildServerAddress(&connectionData, "/principals/");
1098         curl_easy_setopt(connectionHandle, CURLOPT_URL, originalServerAddress.c_str());
1099         curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, NULL);        
1100         curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 0L);
1101         curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
1102         curl_easy_setopt(connectionHandle, CURLOPT_READDATA, NULL);
1103         curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, NULL);
1104         
1105         return serverResult;
1109 CalDAVServerResult CalDAV::EditCalendar(string *calendarHREF,
1110                         string *calendarName,
1111                         Colour *calendarColour,
1112                         string *calendarDescription,
1113                         int *calendarOrder){
1114         
1115         CalDAVServerResult serverResult;
1116         
1117         serverResult = EditCalendarProcess(calendarHREF,
1118                 calendarName,
1119                 calendarColour,
1120                 calendarDescription,
1121                 calendarOrder);
1122                                 
1123         return serverResult;
1124         
1127 CalDAVServerResult CalDAV::EditCalendar(string *calendarHREF,
1128                         Colour *calendarColour){
1130         CalDAVServerResult serverResult;
1132         serverResult = EditCalendarProcess(calendarHREF,
1133                 nullptr,
1134                 calendarColour,
1135                 nullptr,
1136                 nullptr);
1137                                 
1138         return serverResult;    
1139         
1142 CalDAVServerResult CalDAV::EditCalendar(string *calendarHREF,
1143                         string *calendarName){
1144         
1145         CalDAVServerResult serverResult;
1146         
1147         serverResult = EditCalendarProcess(calendarHREF,
1148                 calendarName,
1149                 nullptr,
1150                 nullptr,
1151                 nullptr);       
1152         
1153         return serverResult;
1154         
1157 CalDAVServerResult CalDAV::EditCalendar(string *calendarHREF,
1158                         int *calendarOrder){
1159         
1160         CalDAVServerResult serverResult;
1161         
1162         serverResult = EditCalendarProcess(calendarHREF,
1163                 nullptr,
1164                 nullptr,
1165                 nullptr,
1166                 calendarOrder);
1167         
1168         return serverResult;
1169         
1172 CalDAVServerResult CalDAV::EditCalendarDescription(string *calendarHREF,
1173                         string *calendarDescription){
1174         
1175         CalDAVServerResult serverResult;
1176         
1177         serverResult = EditCalendarProcess(calendarHREF,
1178                 nullptr,
1179                 nullptr,
1180                 calendarDescription,
1181                 nullptr);
1182         
1183         return serverResult;
1184         
1187 CalDAVServerResult CalDAV::DeleteCalendar(string *calendarHREF){
1189         CalDAVServerResult serverResult;
1190         
1191         // Build the server address.
1192         
1193         string userPrincipalURI = "";
1194         userPrincipalURI = GetUserPrincipal();
1195         
1196         if (userPrincipalURI.size() == 0){
1197                 
1198                 return serverResult;
1199                 
1200         }
1201         
1202         string calendarHomeURI = "";
1203         calendarHomeURI = GetCalendarHome(userPrincipalURI);
1204         
1205         // Generate the UUID.
1206         
1207         string UUIDValue = GenerateUUID();
1208         UUIDValue.erase(UUIDValue.end()-1);
1209         
1210         string calendarHomeURL = calendarHomeURI;
1211         calendarHomeURL.append(UUIDValue);
1212         calendarHomeURL.append("/");
1213         
1214         // Build the calendar list address.
1215         
1216         struct curl_slist *deleteRequestHeader = NULL;
1217         
1218         deleteRequestHeader = curl_slist_append(deleteRequestHeader, "Depth: infinity");
1219         
1220         string calendarDeleteURLAddress = BuildServerAddress(&connectionData, (*calendarHREF));
1221         
1222         curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, deleteRequestHeader);
1223         curl_easy_setopt(connectionHandle, CURLOPT_URL, calendarDeleteURLAddress.c_str());
1224         curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, "DELETE");
1225         
1226         // Delete the calendar.
1227         
1228         serverData.clear();
1229         serverHeader.clear();
1230         
1231         CURLcode serverConnectionResult = curl_easy_perform(connectionHandle);
1232         
1233         if (serverConnectionResult == CURLE_OK){
1234                 serverResult.result = CALDAVQUERYRESULT_OK;
1235         } else {
1236                 serverResult.result = CALDAVQUERYRESULT_SERVERERROR;            
1237         }
1238         serverResult.code = serverConnectionResult;
1239         curl_easy_getinfo(connectionHandle, CURLINFO_RESPONSE_CODE, &serverResult.httpCode);
1240         
1241         // Restore the original settings.
1242         
1243         string originalServerAddress = BuildServerAddress(&connectionData, "/principals/");
1244         curl_easy_setopt(connectionHandle, CURLOPT_URL, originalServerAddress.c_str());
1245         curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, NULL);        
1246         curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 0L);
1247         curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
1248         curl_easy_setopt(connectionHandle, CURLOPT_READDATA, NULL);
1249         curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, NULL);
1250         curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, NULL);
1251         
1252         return serverResult;
1253         
1256 CalDAVServerResult CalDAV::GetEntryETag(string *calendarEntryHREF, string *eTagValue){
1257         
1258         CalDAVServerResult serverResult;
1259         CalDAVSendData entryETagGetData;
1260         
1261         // Build the server address.
1262         
1263         string userPrincipalURI = "";
1264         userPrincipalURI = GetUserPrincipal();
1265         
1266         if (userPrincipalURI.size() == 0){
1267                 
1268                 return serverResult;
1269                 
1270         }
1271         
1272         string calendarHomeURI = "";
1273         calendarHomeURI = GetCalendarHome(userPrincipalURI);
1275         // Split the path and filename.
1276         
1277         string entryURIPath;
1278         string entryFilename;
1279         
1280         SplitPathFilename(calendarEntryHREF, &entryURIPath, &entryFilename);
1281         
1282         // Build the request for the server.
1284         string entryETagRequest = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
1285         "<c:calendar-multiget xmlns:d=\"DAV:\" xmlns:c=\"urn:ietf:params:xml:ns:caldav\">\n"
1286         " <d:prop>\n"
1287         "  <d:getetag />\n"
1288         " </d:prop>\n"
1289         " <d:href>";
1290         entryETagRequest += (*calendarEntryHREF);
1291         entryETagRequest += "</d:href>\n"
1292         "</c:calendar-multiget>";
1293         
1294         entryETagGetData.readptr = &entryETagRequest;
1295         entryETagGetData.sizeleft = entryETagRequest.size();
1296         
1297         // Build the calendar list address.
1298         
1299         struct curl_slist *getETagRequestHeader = NULL;
1301         getETagRequestHeader = curl_slist_append(getETagRequestHeader, "Depth: 1");     
1302         getETagRequestHeader = curl_slist_append(getETagRequestHeader, "Prefer: return-minimal");
1303         getETagRequestHeader = curl_slist_append(getETagRequestHeader, "Content-Type: application/xml; charset=utf-8");
1304         
1305         string getETagURLAddress = BuildServerAddress(&connectionData, entryURIPath);
1306         
1307         curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, getETagRequestHeader);
1308         curl_easy_setopt(connectionHandle, CURLOPT_URL, getETagURLAddress.c_str());
1309         curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, "REPORT");
1310         curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 1L);
1311         curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
1312         curl_easy_setopt(connectionHandle, CURLOPT_READDATA, &entryETagGetData);
1313         curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, CalDAVSend);
1314         
1315         // Attempt to get the entity tag.
1316         
1317         serverData.clear();
1318         serverHeader.clear();
1319         
1320         CURLcode serverConnectionResult = curl_easy_perform(connectionHandle);
1321         
1322         if (serverConnectionResult == CURLE_OK){
1323                 serverResult.result = CALDAVQUERYRESULT_OK;
1324         } else {
1325                 serverResult.result = CALDAVQUERYRESULT_SERVERERROR;            
1326         }
1327         serverResult.code = serverConnectionResult;
1328         curl_easy_getinfo(connectionHandle, CURLINFO_RESPONSE_CODE, &serverResult.httpCode);
1329         
1330         if (serverConnectionResult != CURLE_OK){
1331                 return serverResult;
1332         }
1333         
1334         // Get the entity tag from the result.
1335         
1336         *eTagValue = ProcessXMLEntryETag();
1337         
1338         // Restore the original settings.
1339         
1340         string originalServerAddress = BuildServerAddress(&connectionData, "/principals/");
1341         curl_easy_setopt(connectionHandle, CURLOPT_URL, originalServerAddress.c_str());
1342         curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, NULL);        
1343         curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 0L);
1344         curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
1345         curl_easy_setopt(connectionHandle, CURLOPT_READDATA, NULL);
1346         curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, NULL);
1347         curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, NULL);
1348         
1349         return serverResult;
1350         
1353 CalDAVServerResult CalDAV::AddEntry(string *calendarEntryHREF, string *entryData){
1354         
1355         // Add an entry to the calendar collection.
1356         
1357         CalDAVServerResult serverResult;
1358         CalDAVSendData entryAddSendData;
1359         
1360         // Build the calendar list address.
1361         
1362         string entryAddURLAddress = BuildServerAddress(&connectionData, (*calendarEntryHREF));
1363         
1364         entryAddSendData.readptr = entryData;
1365         entryAddSendData.sizeleft = entryData->size();
1366         
1367         struct curl_slist *calendarRequestHeader = NULL;
1368         
1369         calendarRequestHeader = curl_slist_append(calendarRequestHeader, "Content-Type: text/calendar; charset=utf-8");
1370         
1371         curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, calendarRequestHeader);
1372         curl_easy_setopt(connectionHandle, CURLOPT_URL, entryAddURLAddress.c_str());
1373         curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, "PUT");
1374         curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 1L);
1375         curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
1376         curl_easy_setopt(connectionHandle, CURLOPT_READDATA, &entryAddSendData);
1377         curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, CalDAVSend);
1378         
1379         // Process the data.
1380         
1381         serverData.clear();
1382         serverHeader.clear();
1383         
1384         CURLcode serverConnectionResult = curl_easy_perform(connectionHandle);
1385         
1386         if (serverConnectionResult == CURLE_OK){
1387                 serverResult.result = CALDAVQUERYRESULT_OK;
1388         } else {
1389                 serverResult.result = CALDAVQUERYRESULT_SERVERERROR;            
1390         }
1391         serverResult.code = serverConnectionResult;
1392         curl_easy_getinfo(connectionHandle, CURLINFO_RESPONSE_CODE, &serverResult.httpCode);
1393         
1394         // Restore the original settings.
1395         
1396         string originalServerAddress = BuildServerAddress(&connectionData, "/principals/");
1397         curl_easy_setopt(connectionHandle, CURLOPT_URL, originalServerAddress.c_str());
1398         curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, NULL);        
1399         curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 0L);
1400         curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
1401         curl_easy_setopt(connectionHandle, CURLOPT_READDATA, NULL);
1402         curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, NULL);
1403         curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, NULL);
1404         
1405         return serverResult;
1406         
1409 CalDAVServerResult CalDAV::EditEntry(string *calendarEntryHREF, string *entryData, string *entryETag){
1410         
1411         // Edit an entry in the calendar collection.
1413         // Add an entry to the calendar collection.
1414         
1415         CalDAVServerResult serverResult;
1416         CalDAVSendData entryAddSendData;
1417         
1418         // Build the calendar list address.
1419         
1420         string entryAddURLAddress = BuildServerAddress(&connectionData, (*calendarEntryHREF));
1421         
1422         entryAddSendData.readptr = entryData;
1423         entryAddSendData.sizeleft = entryData->size();
1424         
1425         string ifMatchHeader = "If-Match: \"";
1426         ifMatchHeader.append(*entryETag);
1427         ifMatchHeader.append("\"");
1428         
1429         struct curl_slist *calendarRequestHeader = NULL;
1430         
1431         calendarRequestHeader = curl_slist_append(calendarRequestHeader, "Content-Type: text/calendar; charset=utf-8");
1432         calendarRequestHeader = curl_slist_append(calendarRequestHeader, ifMatchHeader.c_str());        
1433         
1434         curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, calendarRequestHeader);
1435         curl_easy_setopt(connectionHandle, CURLOPT_URL, entryAddURLAddress.c_str());
1436         curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, "PUT");
1437         curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 1L);
1438         curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
1439         curl_easy_setopt(connectionHandle, CURLOPT_READDATA, &entryAddSendData);
1440         curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, CalDAVSend);
1441         
1442         // Process the data.
1443         
1444         serverData.clear();
1445         serverHeader.clear();
1446         
1447         CURLcode serverConnectionResult = curl_easy_perform(connectionHandle);
1448         
1449         if (serverConnectionResult == CURLE_OK){
1450                 serverResult.result = CALDAVQUERYRESULT_OK;
1451         } else {
1452                 serverResult.result = CALDAVQUERYRESULT_SERVERERROR;            
1453         }
1454         serverResult.code = serverConnectionResult;
1455         curl_easy_getinfo(connectionHandle, CURLINFO_RESPONSE_CODE, &serverResult.httpCode);
1456         
1457         // Restore the original settings.
1458         
1459         string originalServerAddress = BuildServerAddress(&connectionData, "/principals/");
1460         curl_easy_setopt(connectionHandle, CURLOPT_URL, originalServerAddress.c_str());
1461         curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, NULL);        
1462         curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 0L);
1463         curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
1464         curl_easy_setopt(connectionHandle, CURLOPT_READDATA, NULL);
1465         curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, NULL);
1466         curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, NULL);
1467         
1468         return serverResult;
1469         
1472 CalDAVServerResult CalDAV::DeleteEntry(string *calendarEntryHREF){
1473         
1474         // Delete an entry in the calendar collection.
1475         
1476         CalDAVServerResult serverResult;
1477         
1478         // Build the calendar list address.
1479         
1480         string entryDeleteURLAddress = BuildServerAddress(&connectionData, (*calendarEntryHREF));
1481         
1482         curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, NULL);
1483         curl_easy_setopt(connectionHandle, CURLOPT_URL, entryDeleteURLAddress.c_str());
1484         curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, "DELETE");
1485         
1486         // Delete the calendar.
1487         
1488         serverData.clear();
1489         serverHeader.clear();
1490         
1491         CURLcode serverConnectionResult = curl_easy_perform(connectionHandle);
1492         
1493         if (serverConnectionResult == CURLE_OK){
1494                 serverResult.result = CALDAVQUERYRESULT_OK;
1495         } else {
1496                 serverResult.result = CALDAVQUERYRESULT_SERVERERROR;            
1497         }
1498         serverResult.code = serverConnectionResult;
1499         curl_easy_getinfo(connectionHandle, CURLINFO_RESPONSE_CODE, &serverResult.httpCode);
1500         
1501         // Restore the original settings.
1502         
1503         string originalServerAddress = BuildServerAddress(&connectionData, "/principals/");
1504         curl_easy_setopt(connectionHandle, CURLOPT_URL, originalServerAddress.c_str());
1505         curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, NULL);        
1506         curl_easy_setopt(connectionHandle, CURLOPT_UPLOAD, 0L);
1507         curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
1508         curl_easy_setopt(connectionHandle, CURLOPT_READDATA, NULL);
1509         curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, NULL);
1510         curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, NULL);
1511         
1512         return serverResult;
1513         
1516 COSSLVerified CalDAV::SSLVerify()
1518         return sslVerified;
1521 void CalDAV::BypassSSLVerification(bool enableBypass){
1522         enableSSLBypass = enableBypass;
1523         sslSelfSigned = enableBypass;
1526 #if defined(__APPLE__)
1528 SecTrustRef CalDAV::BuildSSLCollection(){
1529         
1530         return certificateData;
1531         
1534 #elif defined(__WIN32__)
1536 PCCERT_CONTEXT CalDAV::BuildSSLCollection(){
1538         return certificateData;
1542 #else
1544 SSLCertCollectionString CalDAV::BuildSSLCollection(){
1546         // Build and return the SSL collection.
1547         
1548         SSLCertCollectionString sslCertInfo;
1550         // Grab the certificate data.
1552         union {
1553                 struct curl_slist *certdata;
1554                 struct curl_certinfo *certinfo;
1555         } certptr;
1557         certptr.certdata = NULL;
1558         
1559         CURLcode result = curl_easy_getinfo(connectionHandle, CURLINFO_CERTINFO, &certptr.certinfo);
1560         
1561         std::string certPropName;
1562         std::string certPropValue;
1563         
1564         for (int i = 0; i < certptr.certinfo->num_of_certs; i++){
1565                 
1566                 struct curl_slist *slist;
1567                 SSLCertDataString sslCertDataInc;
1568                 
1569                 for (slist = certptr.certinfo->certinfo[i]; slist; slist = slist->next){
1570                         
1571                         // Using wxStringTokenizer from wxWidgets.
1572                         
1573                         wxStringTokenizer certDataInc(wxString::FromUTF8(slist->data), ":");
1574                         
1575                         // Get first token as the property name.
1576                         
1577                         certPropName = certDataInc.GetNextToken().ToStdString();
1578                         
1579                         // Get remaining tokens as the property value.
1580                         
1581                         while(certDataInc.HasMoreTokens()){
1582                         
1583                                 certPropValue.append(certDataInc.GetNextToken());
1584                         
1585                         }
1586                         
1587                         sslCertDataInc.CertData.insert(std::make_pair(certPropName, certPropValue));
1588                         certPropName.clear();
1589                         certPropValue.clear();
1590                         
1591                 }
1592         
1593                 sslCertInfo.SSLCollection.insert(std::make_pair(i, sslCertDataInc));
1594         
1595         }
1596         
1597         return sslCertInfo;
1601 #endif
1603 bool CalDAV::CanDoSSL(){
1604         return sslStatus;
1607 bool CalDAV::HasValidResponse(){
1608         return validResponse;
1611 bool CalDAV::AbleToLogin(){
1612         return authPassed;
1615 bool CalDAV::IsSelfSigned(){
1616         return sslSelfSigned;
1619 string CalDAV::GetErrorMessage(){
1620         
1621         errorMessage = sessionErrorBuffer;      
1622         return errorMessage;
1623         
1626 static bool CalDAVObjectValidSettings(CalDAVConnectionData *connData){
1628         // Check if the passed CalDAV Connection Data is has
1629         // an address set. Return false if nullptr is used.
1631         if (connData == nullptr){
1632         
1633                 return false;
1634         
1635         }
1636         
1637         // Check the server hostname. Return false
1638         // if no value has been set.
1639         
1640         if (connData->hostname.size() == 0){
1641         
1642                 return false;
1643         
1644         }
1645         
1646         // Check the server port. Return false if
1647         // no value has been set or the port number
1648         // is less than 1 or higher than 65535.
1649         
1650         if (connData->port < 1 || connData->port > 65535){
1651         
1652                 return false;
1653         
1654         }
1655         
1656         // Check the server username. Return false
1657         // if no value has been set.
1658         
1659         if (connData->username.size() == 0){
1660                 
1661                 return false;
1662                 
1663         }       
1664         
1665         // Check the server password. Return false
1666         // if no value has been set.
1667         
1668         if (connData->password.size() == 0){
1669                 
1670                 return false;
1671                 
1672         }
1674         // Cannot check UseSSL: It is either true
1675         // or false.
1676         
1677         // Cannot check Prefix: The prefix may need
1678         // to be worked out first.
1680         // No errors were found whilst checking so
1681         // return true.
1682         
1683         return true;
1687 string CalDAV::BuildServerAddress(CalDAVConnectionData *connData, string uriAddress){
1688         
1689         string serverAddress;
1690         
1691         // Setup the server address.
1692         
1693         if (connData->useSSL == true){
1694                 serverAddress += "https://";
1695         } else {
1696                 serverAddress += "http://";
1697         }
1698         
1699         serverAddress += connData->hostname;
1700         
1701         // Check if server port is 80, otherwise
1702         // specifiy the port number in the address.
1703         
1704         if (connData->port != 80){
1705                 serverAddress += ":";
1706                 serverAddress += to_string(connData->port);
1707         }
1708         
1709         serverAddress += uriAddress;
1710         
1711         return serverAddress;
1712         
1715 void CalDAV::SetupDefaultParametersNonSSL(bool doAuthentication){
1716         
1717         std::string serverAddress = "";
1719         string serverAddressURL = "http://" + connectionData.hostname + ":" + to_string(connectionData.port) + "/";
1720         string usernamePassword = connectionData.username + ":" + connectionData.password;
1721         
1722         curl_easy_setopt(connectionHandle, CURLOPT_URL, serverAddressURL.c_str());
1723         curl_easy_setopt(connectionHandle, CURLOPT_NOPROGRESS, 1L);
1724         curl_easy_setopt(connectionHandle, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST|CURLAUTH_BASIC);
1725         curl_easy_setopt(connectionHandle, CURLOPT_TIMEOUT, 60);
1726         curl_easy_setopt(connectionHandle, CURLOPT_FAILONERROR, true);
1727         curl_easy_setopt(connectionHandle, CURLOPT_USERAGENT, XSDCAL_USERAGENT);
1728         curl_easy_setopt(connectionHandle, CURLOPT_NOSIGNAL, 1L);
1729         curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, "GET");
1730         curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, nullptr);
1731         curl_easy_setopt(connectionHandle, CURLOPT_POSTFIELDS, nullptr);
1732         curl_easy_setopt(connectionHandle, CURLOPT_POSTFIELDSIZE, 0L);
1734         if (doAuthentication == true){
1735                 curl_easy_setopt(connectionHandle, CURLOPT_USERPWD, usernamePassword.c_str());
1736         } else {
1737                 curl_easy_setopt(connectionHandle, CURLOPT_USERPWD, NULL);              
1738         }
1739         
1742 void CalDAV::SetupDefaultParametersSSL(bool doAuthentication){
1743         
1744         // Setup the default parameters.
1745         
1746         string ServerAddressURL = "https://" + connectionData.hostname + ":" + to_string(connectionData.port) + "/";
1747         string UsernamePassword = connectionData.username + ":" + connectionData.password;
1748         
1749         curl_easy_setopt(connectionHandle, CURLOPT_URL, ServerAddressURL.c_str());
1750         curl_easy_setopt(connectionHandle, CURLOPT_NOPROGRESS, 1L);
1751         curl_easy_setopt(connectionHandle, CURLOPT_CERTINFO, 1L);
1752         curl_easy_setopt(connectionHandle, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST|CURLAUTH_BASIC);
1753         curl_easy_setopt(connectionHandle, CURLOPT_TIMEOUT, 60);
1754         curl_easy_setopt(connectionHandle, CURLOPT_FAILONERROR, 0L);
1755         curl_easy_setopt(connectionHandle, CURLOPT_USERAGENT, XSDCAL_USERAGENT);
1756         curl_easy_setopt(connectionHandle, CURLOPT_ERRORBUFFER, sessionErrorBuffer);
1757         curl_easy_setopt(connectionHandle, CURLOPT_CUSTOMREQUEST, "GET");
1758         curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, nullptr);
1759         curl_easy_setopt(connectionHandle, CURLOPT_POSTFIELDS, nullptr);
1760         curl_easy_setopt(connectionHandle, CURLOPT_POSTFIELDSIZE, 0L);
1762         if (doAuthentication == true){
1763                 curl_easy_setopt(connectionHandle, CURLOPT_USERPWD, UsernamePassword.c_str());
1764         } else {
1765                 curl_easy_setopt(connectionHandle, CURLOPT_USERPWD, NULL);              
1766         }
1767         
1768         if (enableSSLBypass == true){
1769                 curl_easy_setopt(connectionHandle, CURLOPT_SSL_VERIFYHOST, 0L);
1770                 curl_easy_setopt(connectionHandle, CURLOPT_SSL_VERIFYPEER, 0L);
1771                 curl_easy_setopt(connectionHandle, CURLOPT_SSL_VERIFYSTATUS, 0L);
1772         } else {
1773                 curl_easy_setopt(connectionHandle, CURLOPT_SSL_VERIFYHOST, 2L);
1774                 curl_easy_setopt(connectionHandle, CURLOPT_SSL_VERIFYPEER, 1L);
1775                 curl_easy_setopt(connectionHandle, CURLOPT_SSL_VERIFYSTATUS, 1L);
1776         }
1777         
1778 #if !defined(__APPLE__) || defined(__WIN32__)
1779         
1780         if (connectionData.account.size() > 0){
1781                 
1782                 // Check if the server certificate file exists.
1783                 
1784                 string certificateFilename = GetAccountDir(connectionData.account, true);
1785                 
1786                 if (wxFile::Exists(certificateFilename)){
1787                         
1788                         curl_easy_setopt(connectionHandle, CURLOPT_CAINFO, certificateFilename.c_str());
1789                         
1790                 }
1791                 
1792         }
1794 #endif
1795         
1798 void CalDAV::ResetResults(){
1799         
1800         sslStatus = false;
1801         COSSLVerified SSLVerified = COSSL_NORESULT;
1802         validResponse = false;
1803         authPassed = false;
1804         sslSelfSigned = false;
1805         //taskCompleted = false;
1806         errorMessage = "";
1807         sessionErrorBuffer[0] = '\0';
1808         //sessionResult = CURLE_OK;
1809         serverData = "";
1810         serverHeader = "";
1811         /*if (headerList != nullptr){
1812                 curl_slist_free_all(headerList);
1813                 headerList = nullptr;
1814         }*/
1815         
Xestia Software Development
Yn Maystri
© 2006 - 2019 Xestia Software Development
Software

Xestia Address Book
Xestia Calendar
Development

Xestia Gelforn
Everything else

About
News
Privacy Policy