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