Home | News | Projects | Releases
Bugs | RFE | Repositories | Help
Added support to add a calendar using a shortname.
[xestiacalendar/.git] / source / objects / CalDAV / CalDAV.cpp
1 // CalDAV.cpp - CalDAV Connection Object.
2 //
3 // (c) 2016 Xestia Software Development.
4 //
5 // This file is part of Xestia Calendar.
6 //
7 // Xestia Address Book is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU General Public License as published by the
9 // Free Software Foundation, version 3 of the license.
10 //
11 // Xestia Address Book is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
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         string ReceivedBufferString = "";
27         ReceivedBufferString.append(ReceivedBuffer, NewMemoryBytes);
28         
29         StringPointer->append(ReceivedBufferString);
30         
31         return Size * NewMemoryBytes;
32         
33 }
35 size_t CalDAVSend(char *SendBuffer, size_t Size, size_t NewMemoryBytes, void *DataStruct){
37         struct CalDAVSendData *UploadPtr = (struct CalDAVSendData *)DataStruct;
38         
39         if (UploadPtr->sizeleft){
41                 UploadPtr->sizeleft--;
42                 char CharSend;
44                 CharSend = (*UploadPtr->readptr)[UploadPtr->seek];
45                 
46                 *SendBuffer = CharSend;
47                 
48                 UploadPtr->seek++;
50                 return 1;
52         }
54         return 0;
56 }
58 CalDAV::CalDAV(){
60         // Setup the objects within the CalDAV connection 
61         // object.
62         
63         ConnectionHandle = curl_easy_init();
64         
65 }
67 CalDAV::~CalDAV(){
68         
69         // Destory the objects within the CalDAV connection
70         // object.
71         
72         curl_easy_cleanup(ConnectionHandle);
73         ConnectionHandle = nullptr;
74         
75 }
77 void CalDAV::SetupConnectionData(CalDAVConnectionData *ConnData){
78         
79         // Check if ConnData is a nullptr, return if it is.
80         
81         if (ConnData == nullptr){
82                 return;
83         }
84         
85         // Set the connection settings to the values from ConnData.
87         ConnectionData = (*ConnData);
88         
89 }
91 CalDAVStatus CalDAV::GetConnectionData(){
92         
93         // Get the current connection settings for the CalDAV
94         // connection object and return a CalDAVStatus object.
95         
96         CalDAVStatus ConnectionStatus;
97         
98         ConnectionStatus.Hostname = ConnectionData.Hostname;
99         ConnectionStatus.Port = ConnectionData.Port;
100         ConnectionStatus.Username = ConnectionData.Username;
101         ConnectionStatus.Prefix = ConnectionData.Prefix;
102         ConnectionStatus.UseSSL = ConnectionData.UseSSL;
103         ConnectionStatus.Timeout = ConnectionData.Timeout;
104         
105         return ConnectionStatus;
106         
109 CalDAVServerResult CalDAV::Connect(){
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_FAILONERROR, 1L);
130         curl_easy_setopt(ConnectionHandle, CURLOPT_TIMEOUT, ConnectionData.Timeout);
131         curl_easy_setopt(ConnectionHandle, CURLOPT_WRITEFUNCTION, CalDAVReceive);
132         curl_easy_setopt(ConnectionHandle, CURLOPT_WRITEDATA, &ServerData);
133         curl_easy_setopt(ConnectionHandle, CURLOPT_WRITEHEADER, &ServerHeader);
134         
135         // Connect to the CalDAV server.
136         
137         ServerResult.Code = curl_easy_perform(ConnectionHandle);
139         // Process the result received from the server.
140         
141         if (ServerResult.Code != CURLE_OK){
142                 
143                 ServerResult.Result = CALDAVQUERYRESULT_SERVERERROR;
144                 
145         } else {
146                 
147                 ServerResult.Result = CALDAVQUERYRESULT_OK;
148                 
149         }
150         
151         // Get the HTTP code.
152         
153         curl_easy_getinfo(ConnectionHandle, CURLINFO_RESPONSE_CODE, &ServerResult.HTTPCode);
154         
155         return ServerResult;
156         
159 CalDAVServerResult CalDAV::GetServerResult(){
160         
161         return ConnectionServerResult;
162         
165 CalDAVServerSupport CalDAV::GetServerSupport(){
167         CalDAVServerSupport ServerStatus;
168         
169         // Setup the server connection.
170         
171         curl_easy_setopt(ConnectionHandle, CURLOPT_CUSTOMREQUEST, "OPTIONS");
172         
173         CURLcode ServerResult = curl_easy_perform(ConnectionHandle);
174         
175         // Set the results.
176         
177         if (ServerResult == CURLE_OK){
178                 ConnectionServerResult.Result = CALDAVQUERYRESULT_OK;
179         } else {
180                 ConnectionServerResult.Result = CALDAVQUERYRESULT_SERVERERROR;          
181         }
182         ConnectionServerResult.Code = ServerResult;
183         curl_easy_getinfo(ConnectionHandle, CURLINFO_RESPONSE_CODE, &ConnectionServerResult.HTTPCode);
184         
185         if (ServerResult != CURLE_OK){
186                 return ServerStatus;
187         }
188         
189         // Check that the server header has data in,
190         // otherwise return an "empty" CalDAVServerSupport.
191         
192         if (ServerHeader.size() == 0){
193                 return ServerStatus;
194         }
195         
196         // Process each line looking for the first DAV header 
197         // line.
198         
199         bool NewlineMode = true;
200         
201         string DAVLine;
202         
203         for (int CharSeek = 0; CharSeek < ServerHeader.size(); CharSeek++){
204                 
205                 if (NewlineMode == true){
206                         
207                         // Check if we have reached the end of the string.
208                         
209                         if (CharSeek >= ServerHeader.size()){
210                                 
211                                 break;
212                                 
213                         }
214                         
215                         // Check the first four letters to make sure
216                         // they are 'DAV:'.
217                         
218                         string DAVHeaderCheck = "";
219                         
220                         try {
221                                 DAVHeaderCheck = ServerHeader.substr(CharSeek, 4);
222                         }
223                         
224                         catch (out_of_range &oor){
225                                 break;
226                         }
227                         
228                         if (DAVHeaderCheck == "DAV:"){
229                                 
230                                 CharSeek += 5;
231                                 
232                                 for (; CharSeek < ServerHeader.size(); CharSeek++){
233                                         
234                                         if (ServerHeader[CharSeek] == '\n'){
235                                         
236                                                 break;
237                                                 
238                                         }
239                                         
240                                         DAVLine.push_back(ServerHeader[CharSeek]);
241                                         
242                                 }
243                                 
244                                 break;
245                                 
246                         }
247                         
248                         NewlineMode = false;
249                         
250                 }
251                 
252                 if (ServerHeader[CharSeek] == '\n'){
253                         
254                         NewlineMode = true;
255                         
256                 }
257                 
258         }
259         
260         // Process the DAV line.
261         
262         vector<string> DAVLineData;
263         string DAVSegmentString;
264         
265         for (int CharSeek = 0; CharSeek < DAVLine.size(); CharSeek++){
266                 
267                 if (DAVLine[CharSeek] == ' '){
268                         continue;
269                 }
270                 
271                 if (DAVLine[CharSeek] == ','){
272                         
273                         DAVLineData.push_back(DAVSegmentString);
274                         DAVSegmentString.clear();
275                         continue;
276                         
277                 }
278                 
279                 DAVSegmentString += DAVLine[CharSeek];
280                 
281         }
282         
283         // Process the DAV values and set each value
284         // to true as required.
285         
286         for (int DAVItemSeek = 0; 
287                 DAVItemSeek < DAVLineData.size();
288                 DAVItemSeek++){
289                         
290                 if (DAVLineData.at(DAVItemSeek) == "calendar-access"){
291                         
292                         ServerStatus.BasicSupport = true;
293                 
294                 }
295                         
296         }
297         
298         // Reset the connection status.
299         
300         curl_easy_setopt(ConnectionHandle, CURLOPT_CUSTOMREQUEST, NULL);
301         
302         return ServerStatus;
303         
306 string CalDAV::GetUserPrincipal(){
307         
308         string CurrentUserPrincipal = "";
309         string UserPrincipalRequest = "";
310         CalDAVSendData UserPrincipalSendData;
311         
312         UserPrincipalRequest = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
313         "<d:propfind xmlns:d=\"DAV:\">\n"
314         " <d:prop>\n"
315         "  <d:current-user-principal />\n"
316         " </d:prop>\n"
317         "</d:propfind>";
318         
319         UserPrincipalSendData.readptr = &UserPrincipalRequest;
320         UserPrincipalSendData.sizeleft = UserPrincipalRequest.size();
321         
322         // Setup the header.
323         
324         struct curl_slist *UserPrincipalRequestHeader = NULL;
325         
326         UserPrincipalRequestHeader = curl_slist_append(UserPrincipalRequestHeader, "Depth: 0");
327         UserPrincipalRequestHeader = curl_slist_append(UserPrincipalRequestHeader, "Prefer: return-minimal");
328         UserPrincipalRequestHeader = curl_slist_append(UserPrincipalRequestHeader, "Content-Type: application/xml; charset=utf-8");
329         
330         curl_easy_setopt(ConnectionHandle, CURLOPT_HTTPHEADER, UserPrincipalRequestHeader);
332         curl_easy_setopt(ConnectionHandle, CURLOPT_CUSTOMREQUEST, "PROPFIND");
333         curl_easy_setopt(ConnectionHandle, CURLOPT_UPLOAD, 1L);
334         curl_easy_setopt(ConnectionHandle, CURLOPT_READDATA, &UserPrincipalSendData);
335         curl_easy_setopt(ConnectionHandle, CURLOPT_READFUNCTION, CalDAVSend);
336         
337         // Process the data.
338         
339         ServerData.clear();
340         ServerHeader.clear();
341         
342         CURLcode ServerResult = curl_easy_perform(ConnectionHandle);
343         
344         // Set the results.
345         
346         if (ServerResult == CURLE_OK){
347                 ConnectionServerResult.Result = CALDAVQUERYRESULT_OK;
348         } else {
349                 ConnectionServerResult.Result = CALDAVQUERYRESULT_SERVERERROR;          
350         }
351         ConnectionServerResult.Code = ServerResult;
352         curl_easy_getinfo(ConnectionHandle, CURLINFO_RESPONSE_CODE, &ConnectionServerResult.HTTPCode);
353         
354         if (ServerResult != CURLE_OK){
355                 
356                 return CurrentUserPrincipal;
357                 
358         }
359         
360         // Process the User Principal from the ServerData.
362         CurrentUserPrincipal = ProcessXMLUserPrincipal();
363         
364         // Reset the changed settings.
365         
366         curl_easy_setopt(ConnectionHandle, CURLOPT_UPLOAD, 0L);
367         curl_easy_setopt(ConnectionHandle, CURLOPT_READDATA, NULL);
368         curl_easy_setopt(ConnectionHandle, CURLOPT_READFUNCTION, NULL);
370         return CurrentUserPrincipal;
374 string CalDAV::GetCalendarHome(string UserPrincipalURI){
375         
376         string CalendarHomeURI = "";
378         // Build the Calendar Home URL address.
379         
380         string CalendarHomeURL = BuildServerAddress(&ConnectionData, UserPrincipalURI);
381         
382         // Setup the header request.
383         
384         CalDAVSendData CalendarHomeSendData;
385         
386         string CalendarHomeRequest = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
387         "<d:propfind xmlns:d=\"DAV:\" xmlns:c=\"urn:ietf:params:xml:ns:caldav\">\n"
388         " <d:prop>\n"
389         "  <c:calendar-home-set />\n"
390         " </d:prop>\n"
391         "</d:propfind>";
392         
393         CalendarHomeSendData.readptr = &CalendarHomeRequest;
394         CalendarHomeSendData.sizeleft = CalendarHomeRequest.size();
395         
396         // Setup the header.
397         
398         struct curl_slist *CalendarRequestHeader = NULL;
399         
400         CalendarRequestHeader = curl_slist_append(CalendarRequestHeader, "Depth: 0");
401         CalendarRequestHeader = curl_slist_append(CalendarRequestHeader, "Prefer: return-minimal");
402         CalendarRequestHeader = curl_slist_append(CalendarRequestHeader, "Content-Type: application/xml; charset=utf-8");
403         
404         curl_easy_setopt(ConnectionHandle, CURLOPT_HTTPHEADER, CalendarRequestHeader);
405         curl_easy_setopt(ConnectionHandle, CURLOPT_URL, CalendarHomeURL.c_str());
406         curl_easy_setopt(ConnectionHandle, CURLOPT_CUSTOMREQUEST, "PROPFIND");
407         curl_easy_setopt(ConnectionHandle, CURLOPT_UPLOAD, 1L);
408         curl_easy_setopt(ConnectionHandle, CURLOPT_READDATA, &CalendarHomeSendData);
409         curl_easy_setopt(ConnectionHandle, CURLOPT_READFUNCTION, CalDAVSend);
410         
411         // Process the data.
412         
413         ServerData.clear();
414         ServerHeader.clear();
415         
416         CURLcode ServerResult = curl_easy_perform(ConnectionHandle);
417         
418         // Set the results.
419         
420         if (ServerResult == CURLE_OK){
421                 ConnectionServerResult.Result = CALDAVQUERYRESULT_OK;
422         } else {
423                 ConnectionServerResult.Result = CALDAVQUERYRESULT_SERVERERROR;          
424         }
425         ConnectionServerResult.Code = ServerResult;
426         curl_easy_getinfo(ConnectionHandle, CURLINFO_RESPONSE_CODE, &ConnectionServerResult.HTTPCode);
427         
428         if (ServerResult != CURLE_OK){
429                 
430                 return CalendarHomeURI;
431                 
432         }
433         
434         // Process the User Principal from the ServerData.
436         CalendarHomeURI = ProcessXMLCalendarHome();
437         
438         // Reset the changed settings.
439         
440         string OriginalServerAddress = BuildServerAddress(&ConnectionData, "/principals/");
441         curl_easy_setopt(ConnectionHandle, CURLOPT_URL, OriginalServerAddress.c_str());
442         
443         curl_easy_setopt(ConnectionHandle, CURLOPT_UPLOAD, 0L);
444         curl_easy_setopt(ConnectionHandle, CURLOPT_READDATA, NULL);
445         curl_easy_setopt(ConnectionHandle, CURLOPT_READFUNCTION, NULL);
446         curl_easy_setopt(ConnectionHandle, CURLOPT_HTTPHEADER, NULL);
447         
448         return CalendarHomeURI;
449         
452 CalDAVCalendarList CalDAV::GetCalendars(){
453         
454         CalDAVCalendarList ServerList;
455         CalDAVSendData CalendarListSendData;
456         
457         // Build the server address.
458         
459         string UserPrincipalURI = "";
460         UserPrincipalURI = GetUserPrincipal();
461         
462         if (UserPrincipalURI.size() == 0){
463                 
464                 return ServerList;
465                 
466         }
467         
468         string CalendarHomeURI = "";
469         CalendarHomeURI = GetCalendarHome(UserPrincipalURI);
470         
471         string CalendarListURLAddress = BuildServerAddress(&ConnectionData, CalendarHomeURI);
472         
473         string CalendarListRequest = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
474         "<d:propfind xmlns:d=\"DAV:\" xmlns:cs=\"http://calendarserver.org/ns/\""
475         " xmlns:c=\"urn:ietf:params:xml:ns:caldav\" xmlns:x0=\"http://apple.com/ns/ical/\">\n"
476         " <d:prop>\n"
477         "  <d:resourcetype />\n"
478         "  <d:displayname />\n"
479         "  <d:sync-token />\n"
480         "  <x0:calendar-color />\n"
481         "  <x0:calendar-order />\n"
482         "  <cs:getctag />\n"
483         "  <c:supported-calendar-component-set />\n"
484         "  <c:calendar-description />\n"
485         " </d:prop>\n"
486         "</d:propfind>";
487         
488         CalendarListSendData.readptr = &CalendarListRequest;
489         CalendarListSendData.sizeleft = CalendarListRequest.size();
490         
491         // Setup the header.
492         
493         struct curl_slist *CalendarListRequestHeader = NULL;
494         
495         CalendarListRequestHeader = curl_slist_append(CalendarListRequestHeader, "Depth: 1");
496         CalendarListRequestHeader = curl_slist_append(CalendarListRequestHeader, "Prefer: return-minimal");
497         CalendarListRequestHeader = curl_slist_append(CalendarListRequestHeader, "Content-Type: application/xml; charset=utf-8");
498         
499         curl_easy_setopt(ConnectionHandle, CURLOPT_HTTPHEADER, CalendarListRequestHeader);
500         curl_easy_setopt(ConnectionHandle, CURLOPT_URL, CalendarListURLAddress.c_str());
501         curl_easy_setopt(ConnectionHandle, CURLOPT_CUSTOMREQUEST, "PROPFIND");
502         curl_easy_setopt(ConnectionHandle, CURLOPT_UPLOAD, 1L);
503         curl_easy_setopt(ConnectionHandle, CURLOPT_READDATA, &CalendarListSendData);
504         curl_easy_setopt(ConnectionHandle, CURLOPT_READFUNCTION, CalDAVSend);
505         
506         // Process the data.
507         
508         ServerData.clear();
509         ServerHeader.clear();
510         
511         CURLcode ServerResult = curl_easy_perform(ConnectionHandle);
512         
513         //ServerList = ProcessXMLCalendarList();
514         
515         if (ServerResult == CURLE_OK){
516                 ConnectionServerResult.Result = CALDAVQUERYRESULT_OK;
517         } else {
518                 ConnectionServerResult.Result = CALDAVQUERYRESULT_SERVERERROR;          
519         }
520         ConnectionServerResult.Code = ServerResult;
521         curl_easy_getinfo(ConnectionHandle, CURLINFO_RESPONSE_CODE, &ConnectionServerResult.HTTPCode);
522         
523         if (ServerResult != CURLE_OK){
524                 
525                 return ServerList;
526                 
527         }
528         
529         // Process the received XML data into a list of calendars
530         // and locations.
531         
532         ServerList = ProcessXMLCalendarList();
533         
534         // Restore the original settings.
535         
536         string OriginalServerAddress = BuildServerAddress(&ConnectionData, "/principals/");
537         
538         curl_easy_setopt(ConnectionHandle, CURLOPT_URL, OriginalServerAddress.c_str());
539         curl_easy_setopt(ConnectionHandle, CURLOPT_CUSTOMREQUEST, NULL);        
540         curl_easy_setopt(ConnectionHandle, CURLOPT_UPLOAD, 0L);
541         curl_easy_setopt(ConnectionHandle, CURLOPT_READDATA, NULL);
542         curl_easy_setopt(ConnectionHandle, CURLOPT_READFUNCTION, NULL);
543         
544         return ServerList;
545         
548 CalDAVServerResult CalDAV::AddCalendar(string CalendarName){
549         
550         CalDAVServerResult ServerResult;
551         
552         AddCalendar(&CalendarName, nullptr);
553         
554         return ServerResult;
555         
558 CalDAVServerResult CalDAV::AddCalendar(string *CalendarName, string *CalendarShortName){
559         
560         CalDAVServerResult ServerResult;
561         CalDAVSendData CalendarAddSendData;
562         
563         // Build the server address.
564         
565         string UserPrincipalURI = "";
566         UserPrincipalURI = GetUserPrincipal();
567         
568         if (UserPrincipalURI.size() == 0){
569                 
570                 return ServerResult;
571                 
572         }
573         
574         string CalendarHomeURI = "";
575         CalendarHomeURI = GetCalendarHome(UserPrincipalURI);
576         
577         // Generate the UUID.
578         
579         string UUIDValue = "";
580         
581         if (CalendarShortName == nullptr){
582         
583                 UUIDValue = GenerateUUID();
584                 UUIDValue.erase(UUIDValue.end()-1);
586         } else {
587         
588                 UUIDValue = *CalendarShortName;
589                 
590         }
591                 
592         string CalendarHomeURL = CalendarHomeURI;
593         CalendarHomeURL.append(UUIDValue);
594         CalendarHomeURL.append("/");
595         
596         // Build the calendar list address.
597         
598         string CalendarListURLAddress = BuildServerAddress(&ConnectionData, CalendarHomeURL);
599         
600         string CalendarAddRequest = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
601         "<c:mkcalendar xmlns:d=\"DAV:\" xmlns:c=\"urn:ietf:params:xml:ns:caldav\">\n"
602         " <d:set>\n"
603         "  <d:prop>\n"
604         "   <d:displayname>";
605         CalendarAddRequest += *CalendarName;
606         CalendarAddRequest += "</d:displayname>\n"
607         "   <c:supported-calendar-component-set>\n"
608         "    <c:comp name=\"VTODO\"/>\n"
609         "    <c:comp name=\"VEVENT\"/>\n"
610         "   </c:supported-calendar-component-set>\n"
611         "  </d:prop>\n"
612         " </d:set>\n"
613         "</c:mkcalendar>";
614         
615         CalendarAddSendData.readptr = &CalendarAddRequest;
616         CalendarAddSendData.sizeleft = CalendarAddRequest.size();
617         
618         // Setup the header.
619         
620         struct curl_slist *CalendarRequestHeader = NULL;
621         
622         //curl_easy_setopt(ConnectionHandle, CURLOPT_HTTPHEADER, CalendarRequestHeader);
623         curl_easy_setopt(ConnectionHandle, CURLOPT_URL, CalendarListURLAddress.c_str());
624         curl_easy_setopt(ConnectionHandle, CURLOPT_CUSTOMREQUEST, "MKCALENDAR");
625         curl_easy_setopt(ConnectionHandle, CURLOPT_UPLOAD, 1L);
626         curl_easy_setopt(ConnectionHandle, CURLOPT_READDATA, &CalendarAddSendData);
627         curl_easy_setopt(ConnectionHandle, CURLOPT_READFUNCTION, CalDAVSend);
628         
629         // Process the data.
630         
631         ServerData.clear();
632         ServerHeader.clear();
633         
634         CURLcode ServerConnectionResult = curl_easy_perform(ConnectionHandle);
635         
636         if (ServerConnectionResult == CURLE_OK){
637                 ServerResult.Result = CALDAVQUERYRESULT_OK;
638         } else {
639                 ServerResult.Result = CALDAVQUERYRESULT_SERVERERROR;            
640         }
641         ServerResult.Code = ServerConnectionResult;
642         curl_easy_getinfo(ConnectionHandle, CURLINFO_RESPONSE_CODE, &ServerResult.HTTPCode);
643         
644         // Restore the original settings.
645         
646         string OriginalServerAddress = BuildServerAddress(&ConnectionData, "/principals/");
647         curl_easy_setopt(ConnectionHandle, CURLOPT_URL, OriginalServerAddress.c_str());
648         curl_easy_setopt(ConnectionHandle, CURLOPT_CUSTOMREQUEST, NULL);        
649         curl_easy_setopt(ConnectionHandle, CURLOPT_UPLOAD, 0L);
650         curl_easy_setopt(ConnectionHandle, CURLOPT_READDATA, NULL);
651         curl_easy_setopt(ConnectionHandle, CURLOPT_READFUNCTION, NULL);
652         
653         return ServerResult;
654         
657 CalDAVServerResult CalDAV::EditCalendarProcess(string *CalendarHREF,
658                         string *CalendarName,
659                         Colour *CalendarColour,
660                         string *CalendarDescription,
661                         int *CalendarOrder){
663         CalDAVServerResult ServerResult;
664         CalDAVSendData CalendarEditSendData;
665         
666         // Build the server address.
667         
668         string UserPrincipalURI = "";
669         UserPrincipalURI = GetUserPrincipal();
670         
671         if (UserPrincipalURI.size() == 0){
672                 
673                 return ServerResult;
674                 
675         }
676         
677         string CalendarHomeURI = "";
678         CalendarHomeURI = GetCalendarHome(UserPrincipalURI);
679         
680         // Generate the UUID.
681         
682         string UUIDValue = GenerateUUID();
683         UUIDValue.erase(UUIDValue.end()-1);
684         
685         string CalendarHomeURL = CalendarHomeURI;
686         CalendarHomeURL.append(UUIDValue);
687         CalendarHomeURL.append("/");
688         
689         // Build the calendar list address.
690         
691         string CalendarEditURLAddress = BuildServerAddress(&ConnectionData, (*CalendarHREF));
692         
693         string CalendarEditRequest = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
694         "<d:propertyupdate xmlns:d=\"DAV:\" xmlns:c=\"urn:ietf:params:xml:ns:caldav\"\n"
695         "       xmlns:x0=\"http://apple.com/ns/ical/\">\n"
696         " <d:set>\n"
697         "  <d:prop>\n";
698         
699         // Update the calendar name.
700         
701         if (CalendarName != nullptr){
702         
703                 CalendarEditRequest += "<d:displayname>";
704                 CalendarEditRequest += (*CalendarName);
705                 CalendarEditRequest += "</d:displayname>\n";
706                 
707         }
708         
709         // Update the calendar colour.
710         
711         if (CalendarColour != nullptr){
712                 
713                 CalendarEditRequest += "<x0:calendar-color>";
714                 CalendarEditRequest += (*CalendarColour);
715                 CalendarEditRequest += "</x0:calendar-color>\n";
716                 
717         }
718         
719         // Update the calendar description.
720         
721         if (CalendarDescription != nullptr){
722                 
723                 CalendarEditRequest += "<c:calendar-description>";
724                 CalendarEditRequest += (*CalendarDescription);
725                 CalendarEditRequest += "</c:calendar-description>\n";           
726                 
727         }
728         
729         // Update the calendar order.
730         
731         if (CalendarOrder != nullptr){
732                 
733                 CalendarEditRequest += "<x0:calendar-order>";
734                 CalendarEditRequest += to_string((*CalendarOrder));
735                 CalendarEditRequest += "</x0:calendar-order>\n";
736                 
737         }
738         
739         CalendarEditRequest += "  </d:prop>\n"
740         " </d:set>\n"
741         "</d:propertyupdate>";
742         
743         CalendarEditSendData.readptr = &CalendarEditRequest;
744         CalendarEditSendData.sizeleft = CalendarEditRequest.size();
745         
746         // Setup the header.
747         
748         struct curl_slist *CalendarRequestHeader = NULL;
749         
750         //curl_easy_setopt(ConnectionHandle, CURLOPT_HTTPHEADER, CalendarRequestHeader);
751         curl_easy_setopt(ConnectionHandle, CURLOPT_URL, CalendarEditURLAddress.c_str());
752         curl_easy_setopt(ConnectionHandle, CURLOPT_CUSTOMREQUEST, "PROPPATCH");
753         curl_easy_setopt(ConnectionHandle, CURLOPT_UPLOAD, 1L);
754         curl_easy_setopt(ConnectionHandle, CURLOPT_READDATA, &CalendarEditSendData);
755         curl_easy_setopt(ConnectionHandle, CURLOPT_READFUNCTION, CalDAVSend);
756         
757         // Process the data.
758         
759         ServerData.clear();
760         ServerHeader.clear();
761         
762         CURLcode ServerConnectionResult = curl_easy_perform(ConnectionHandle);
763         
764         if (ServerConnectionResult == CURLE_OK){
765                 ServerResult.Result = CALDAVQUERYRESULT_OK;
766         } else {
767                 ServerResult.Result = CALDAVQUERYRESULT_SERVERERROR;            
768         }
769         ServerResult.Code = ServerConnectionResult;
770         curl_easy_getinfo(ConnectionHandle, CURLINFO_RESPONSE_CODE, &ServerResult.HTTPCode);
771         
772         // Restore the original settings.
773         
774         string OriginalServerAddress = BuildServerAddress(&ConnectionData, "/principals/");
775         curl_easy_setopt(ConnectionHandle, CURLOPT_URL, OriginalServerAddress.c_str());
776         curl_easy_setopt(ConnectionHandle, CURLOPT_CUSTOMREQUEST, NULL);        
777         curl_easy_setopt(ConnectionHandle, CURLOPT_UPLOAD, 0L);
778         curl_easy_setopt(ConnectionHandle, CURLOPT_READDATA, NULL);
779         curl_easy_setopt(ConnectionHandle, CURLOPT_READFUNCTION, NULL);
780         
781         return ServerResult;
785 CalDAVServerResult CalDAV::EditCalendar(string *CalendarHREF,
786                         string *CalendarName,
787                         Colour *CalendarColour,
788                         string *CalendarDescription,
789                         int *CalendarOrder){
790         
791         CalDAVServerResult ServerResult;
792         
793         ServerResult = EditCalendarProcess(CalendarHREF,
794                 CalendarName,
795                 CalendarColour,
796                 CalendarDescription,
797                 CalendarOrder);
798                                 
799         return ServerResult;
800         
803 CalDAVServerResult CalDAV::EditCalendar(string *CalendarHREF,
804                         Colour *CalendarColour){
805         
807         CalDAVServerResult ServerResult;
809         ServerResult = EditCalendarProcess(CalendarHREF,
810                 nullptr,
811                 CalendarColour,
812                 nullptr,
813                 nullptr);
814                                 
815         return ServerResult;    
816         
819 CalDAVServerResult CalDAV::EditCalendar(string *CalendarHREF,
820                         string *CalendarName){
821         
822         CalDAVServerResult ServerResult;
823         
824         ServerResult = EditCalendarProcess(CalendarHREF,
825                 CalendarName,
826                 nullptr,
827                 nullptr,
828                 nullptr);       
829         
830         return ServerResult;
831         
834 CalDAVServerResult CalDAV::EditCalendar(string *CalendarHREF,
835                         int *CalendarOrder){
836         
837         CalDAVServerResult ServerResult;
838         
839         ServerResult = EditCalendarProcess(CalendarHREF,
840                 nullptr,
841                 nullptr,
842                 nullptr,
843                 CalendarOrder);
844         
845         return ServerResult;
846         
849 CalDAVServerResult CalDAV::EditCalendarDescription(string *CalendarHREF,
850                         string *CalendarDescription){
851         
852         CalDAVServerResult ServerResult;
853         
854         ServerResult = EditCalendarProcess(CalendarHREF,
855                 nullptr,
856                 nullptr,
857                 CalendarDescription,
858                 nullptr);
859         
860         return ServerResult;
861         
864 CalDAVServerResult CalDAV::DeleteCalendar(string *CalendarHREF){
866         CalDAVServerResult ServerResult;
867         
868         // Build the server address.
869         
870         string UserPrincipalURI = "";
871         UserPrincipalURI = GetUserPrincipal();
872         
873         if (UserPrincipalURI.size() == 0){
874                 
875                 return ServerResult;
876                 
877         }
878         
879         string CalendarHomeURI = "";
880         CalendarHomeURI = GetCalendarHome(UserPrincipalURI);
881         
882         // Generate the UUID.
883         
884         string UUIDValue = GenerateUUID();
885         UUIDValue.erase(UUIDValue.end()-1);
886         
887         string CalendarHomeURL = CalendarHomeURI;
888         CalendarHomeURL.append(UUIDValue);
889         CalendarHomeURL.append("/");
890         
891         // Build the calendar list address.
892         
893         struct curl_slist *DeleteRequestHeader = NULL;
894         
895         DeleteRequestHeader = curl_slist_append(DeleteRequestHeader, "Depth: infinity");
896         
897         string CalendarDeleteURLAddress = BuildServerAddress(&ConnectionData, (*CalendarHREF));
898         
899         curl_easy_setopt(ConnectionHandle, CURLOPT_HTTPHEADER, DeleteRequestHeader);
900         curl_easy_setopt(ConnectionHandle, CURLOPT_URL, CalendarDeleteURLAddress.c_str());
901         curl_easy_setopt(ConnectionHandle, CURLOPT_CUSTOMREQUEST, "DELETE");
902         
903         // Delete the calendar.
904         
905         ServerData.clear();
906         ServerHeader.clear();
907         
908         CURLcode ServerConnectionResult = curl_easy_perform(ConnectionHandle);
909         
910         if (ServerConnectionResult == CURLE_OK){
911                 ServerResult.Result = CALDAVQUERYRESULT_OK;
912         } else {
913                 ServerResult.Result = CALDAVQUERYRESULT_SERVERERROR;            
914         }
915         ServerResult.Code = ServerConnectionResult;
916         curl_easy_getinfo(ConnectionHandle, CURLINFO_RESPONSE_CODE, &ServerResult.HTTPCode);
917         
918         // Restore the original settings.
919         
920         string OriginalServerAddress = BuildServerAddress(&ConnectionData, "/principals/");
921         curl_easy_setopt(ConnectionHandle, CURLOPT_URL, OriginalServerAddress.c_str());
922         curl_easy_setopt(ConnectionHandle, CURLOPT_CUSTOMREQUEST, NULL);        
923         curl_easy_setopt(ConnectionHandle, CURLOPT_UPLOAD, 0L);
924         curl_easy_setopt(ConnectionHandle, CURLOPT_READDATA, NULL);
925         curl_easy_setopt(ConnectionHandle, CURLOPT_READFUNCTION, NULL);
926         curl_easy_setopt(ConnectionHandle, CURLOPT_HTTPHEADER, NULL);
927         
928         return ServerResult;
929         
932 CalDAVServerResult CalDAV::GetEntryETag(string *CalendarEntryHREF, string *ETagValue){
933         
934         CalDAVServerResult ServerResult;
935         CalDAVSendData EntryETagGetData;
936         
937         // Build the server address.
938         
939         string UserPrincipalURI = "";
940         UserPrincipalURI = GetUserPrincipal();
941         
942         if (UserPrincipalURI.size() == 0){
943                 
944                 return ServerResult;
945                 
946         }
947         
948         string CalendarHomeURI = "";
949         CalendarHomeURI = GetCalendarHome(UserPrincipalURI);
951         // Split the path and filename.
952         
953         string EntryURIPath;
954         string EntryFilename;
955         
956         SplitPathFilename(CalendarEntryHREF, &EntryURIPath, &EntryFilename);
957         
958         // Build the request for the server.
960         string EntryETagRequest = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
961         "<c:calendar-multiget xmlns:d=\"DAV:\" xmlns:c=\"urn:ietf:params:xml:ns:caldav\">\n"
962         " <d:prop>\n"
963         "  <d:getetag />\n"
964         " </d:prop>\n"
965         " <d:href>";
966         EntryETagRequest += (*CalendarEntryHREF);
967         EntryETagRequest += "</d:href>\n"
968         "</c:calendar-multiget>";
969         
970         EntryETagGetData.readptr = &EntryETagRequest;
971         EntryETagGetData.sizeleft = EntryETagRequest.size();
972         
973         // Build the calendar list address.
974         
975         struct curl_slist *GetETagRequestHeader = NULL;
977         GetETagRequestHeader = curl_slist_append(GetETagRequestHeader, "Depth: 1");     
978         GetETagRequestHeader = curl_slist_append(GetETagRequestHeader, "Prefer: return-minimal");
979         GetETagRequestHeader = curl_slist_append(GetETagRequestHeader, "Content-Type: application/xml; charset=utf-8");
980         
981         string GetETagURLAddress = BuildServerAddress(&ConnectionData, EntryURIPath);
982         
983         curl_easy_setopt(ConnectionHandle, CURLOPT_HTTPHEADER, GetETagRequestHeader);
984         curl_easy_setopt(ConnectionHandle, CURLOPT_URL, GetETagURLAddress.c_str());
985         curl_easy_setopt(ConnectionHandle, CURLOPT_CUSTOMREQUEST, "REPORT");
986         curl_easy_setopt(ConnectionHandle, CURLOPT_UPLOAD, 1L);
987         curl_easy_setopt(ConnectionHandle, CURLOPT_READDATA, &EntryETagGetData);
988         curl_easy_setopt(ConnectionHandle, CURLOPT_READFUNCTION, CalDAVSend);
989         
990         // Attempt to get the entity tag.
991         
992         ServerData.clear();
993         ServerHeader.clear();
994         
995         CURLcode ServerConnectionResult = curl_easy_perform(ConnectionHandle);
996         
997         if (ServerConnectionResult == CURLE_OK){
998                 ServerResult.Result = CALDAVQUERYRESULT_OK;
999         } else {
1000                 ServerResult.Result = CALDAVQUERYRESULT_SERVERERROR;            
1001         }
1002         ServerResult.Code = ServerConnectionResult;
1003         curl_easy_getinfo(ConnectionHandle, CURLINFO_RESPONSE_CODE, &ServerResult.HTTPCode);
1004         
1005         if (ServerConnectionResult != CURLE_OK){
1006                 return ServerResult;
1007         }
1008         
1009         // Get the entity tag from the result.
1010         
1011         *ETagValue = ProcessXMLEntryETag();
1012         
1013         // Restore the original settings.
1014         
1015         string OriginalServerAddress = BuildServerAddress(&ConnectionData, "/principals/");
1016         curl_easy_setopt(ConnectionHandle, CURLOPT_URL, OriginalServerAddress.c_str());
1017         curl_easy_setopt(ConnectionHandle, CURLOPT_CUSTOMREQUEST, NULL);        
1018         curl_easy_setopt(ConnectionHandle, CURLOPT_UPLOAD, 0L);
1019         curl_easy_setopt(ConnectionHandle, CURLOPT_READDATA, NULL);
1020         curl_easy_setopt(ConnectionHandle, CURLOPT_READFUNCTION, NULL);
1021         curl_easy_setopt(ConnectionHandle, CURLOPT_HTTPHEADER, NULL);
1022         
1023         return ServerResult;
1024         
1027 CalDAVServerResult CalDAV::AddEntry(string *CalendarEntryHREF, string *EntryData){
1028         
1029         // Add an entry to the calendar collection.
1030         
1031         CalDAVServerResult ServerResult;
1032         CalDAVSendData EntryAddSendData;
1033         
1034         // Build the calendar list address.
1035         
1036         string EntryAddURLAddress = BuildServerAddress(&ConnectionData, (*CalendarEntryHREF));
1037         
1038         EntryAddSendData.readptr = EntryData;
1039         EntryAddSendData.sizeleft = EntryData->size();
1040         
1041         struct curl_slist *CalendarRequestHeader = NULL;
1042         
1043         CalendarRequestHeader = curl_slist_append(CalendarRequestHeader, "Content-Type: text/calendar; charset=utf-8");
1044         
1045         curl_easy_setopt(ConnectionHandle, CURLOPT_HTTPHEADER, CalendarRequestHeader);
1046         curl_easy_setopt(ConnectionHandle, CURLOPT_URL, EntryAddURLAddress.c_str());
1047         curl_easy_setopt(ConnectionHandle, CURLOPT_CUSTOMREQUEST, "PUT");
1048         curl_easy_setopt(ConnectionHandle, CURLOPT_UPLOAD, 1L);
1049         curl_easy_setopt(ConnectionHandle, CURLOPT_READDATA, &EntryAddSendData);
1050         curl_easy_setopt(ConnectionHandle, CURLOPT_READFUNCTION, CalDAVSend);
1051         
1052         // Process the data.
1053         
1054         ServerData.clear();
1055         ServerHeader.clear();
1056         
1057         CURLcode ServerConnectionResult = curl_easy_perform(ConnectionHandle);
1058         
1059         if (ServerConnectionResult == CURLE_OK){
1060                 ServerResult.Result = CALDAVQUERYRESULT_OK;
1061         } else {
1062                 ServerResult.Result = CALDAVQUERYRESULT_SERVERERROR;            
1063         }
1064         ServerResult.Code = ServerConnectionResult;
1065         curl_easy_getinfo(ConnectionHandle, CURLINFO_RESPONSE_CODE, &ServerResult.HTTPCode);
1066         
1067         // Restore the original settings.
1068         
1069         string OriginalServerAddress = BuildServerAddress(&ConnectionData, "/principals/");
1070         curl_easy_setopt(ConnectionHandle, CURLOPT_URL, OriginalServerAddress.c_str());
1071         curl_easy_setopt(ConnectionHandle, CURLOPT_CUSTOMREQUEST, NULL);        
1072         curl_easy_setopt(ConnectionHandle, CURLOPT_UPLOAD, 0L);
1073         curl_easy_setopt(ConnectionHandle, CURLOPT_READDATA, NULL);
1074         curl_easy_setopt(ConnectionHandle, CURLOPT_READFUNCTION, NULL);
1075         curl_easy_setopt(ConnectionHandle, CURLOPT_HTTPHEADER, NULL);
1076         
1077         return ServerResult;
1078         
1081 CalDAVServerResult CalDAV::EditEntry(string *CalendarEntryHREF, string *EntryData, string *EntryETag){
1082         
1083         // Edit an entry in the calendar collection.
1085         // Add an entry to the calendar collection.
1086         
1087         CalDAVServerResult ServerResult;
1088         CalDAVSendData EntryAddSendData;
1089         
1090         // Build the calendar list address.
1091         
1092         string EntryAddURLAddress = BuildServerAddress(&ConnectionData, (*CalendarEntryHREF));
1093         
1094         EntryAddSendData.readptr = EntryData;
1095         EntryAddSendData.sizeleft = EntryData->size();
1096         
1097         string IfMatchHeader = "If-Match: \"";
1098         IfMatchHeader.append(*EntryETag);
1099         IfMatchHeader.append("\"");
1100         
1101         struct curl_slist *CalendarRequestHeader = NULL;
1102         
1103         CalendarRequestHeader = curl_slist_append(CalendarRequestHeader, "Content-Type: text/calendar; charset=utf-8");
1104         CalendarRequestHeader = curl_slist_append(CalendarRequestHeader, IfMatchHeader.c_str());        
1105         
1106         curl_easy_setopt(ConnectionHandle, CURLOPT_HTTPHEADER, CalendarRequestHeader);
1107         curl_easy_setopt(ConnectionHandle, CURLOPT_URL, EntryAddURLAddress.c_str());
1108         curl_easy_setopt(ConnectionHandle, CURLOPT_CUSTOMREQUEST, "PUT");
1109         curl_easy_setopt(ConnectionHandle, CURLOPT_UPLOAD, 1L);
1110         curl_easy_setopt(ConnectionHandle, CURLOPT_READDATA, &EntryAddSendData);
1111         curl_easy_setopt(ConnectionHandle, CURLOPT_READFUNCTION, CalDAVSend);
1112         
1113         // Process the data.
1114         
1115         ServerData.clear();
1116         ServerHeader.clear();
1117         
1118         CURLcode ServerConnectionResult = curl_easy_perform(ConnectionHandle);
1119         
1120         if (ServerConnectionResult == CURLE_OK){
1121                 ServerResult.Result = CALDAVQUERYRESULT_OK;
1122         } else {
1123                 ServerResult.Result = CALDAVQUERYRESULT_SERVERERROR;            
1124         }
1125         ServerResult.Code = ServerConnectionResult;
1126         curl_easy_getinfo(ConnectionHandle, CURLINFO_RESPONSE_CODE, &ServerResult.HTTPCode);
1127         
1128         // Restore the original settings.
1129         
1130         string OriginalServerAddress = BuildServerAddress(&ConnectionData, "/principals/");
1131         curl_easy_setopt(ConnectionHandle, CURLOPT_URL, OriginalServerAddress.c_str());
1132         curl_easy_setopt(ConnectionHandle, CURLOPT_CUSTOMREQUEST, NULL);        
1133         curl_easy_setopt(ConnectionHandle, CURLOPT_UPLOAD, 0L);
1134         curl_easy_setopt(ConnectionHandle, CURLOPT_READDATA, NULL);
1135         curl_easy_setopt(ConnectionHandle, CURLOPT_READFUNCTION, NULL);
1136         curl_easy_setopt(ConnectionHandle, CURLOPT_HTTPHEADER, NULL);
1137         
1138         return ServerResult;
1139         
1142 CalDAVServerResult CalDAV::DeleteEntry(string *CalendarEntryHREF){
1143         
1144         // Delete an entry in the calendar collection.
1145         
1146         CalDAVServerResult ServerResult;
1147         
1148         // Build the calendar list address.
1149         
1150         string EntryDeleteURLAddress = BuildServerAddress(&ConnectionData, (*CalendarEntryHREF));
1151         
1152         curl_easy_setopt(ConnectionHandle, CURLOPT_HTTPHEADER, NULL);
1153         curl_easy_setopt(ConnectionHandle, CURLOPT_URL, EntryDeleteURLAddress.c_str());
1154         curl_easy_setopt(ConnectionHandle, CURLOPT_CUSTOMREQUEST, "DELETE");
1155         
1156         // Delete the calendar.
1157         
1158         ServerData.clear();
1159         ServerHeader.clear();
1160         
1161         CURLcode ServerConnectionResult = curl_easy_perform(ConnectionHandle);
1162         
1163         if (ServerConnectionResult == CURLE_OK){
1164                 ServerResult.Result = CALDAVQUERYRESULT_OK;
1165         } else {
1166                 ServerResult.Result = CALDAVQUERYRESULT_SERVERERROR;            
1167         }
1168         ServerResult.Code = ServerConnectionResult;
1169         curl_easy_getinfo(ConnectionHandle, CURLINFO_RESPONSE_CODE, &ServerResult.HTTPCode);
1170         
1171         // Restore the original settings.
1172         
1173         string OriginalServerAddress = BuildServerAddress(&ConnectionData, "/principals/");
1174         curl_easy_setopt(ConnectionHandle, CURLOPT_URL, OriginalServerAddress.c_str());
1175         curl_easy_setopt(ConnectionHandle, CURLOPT_CUSTOMREQUEST, NULL);        
1176         curl_easy_setopt(ConnectionHandle, CURLOPT_UPLOAD, 0L);
1177         curl_easy_setopt(ConnectionHandle, CURLOPT_READDATA, NULL);
1178         curl_easy_setopt(ConnectionHandle, CURLOPT_READFUNCTION, NULL);
1179         curl_easy_setopt(ConnectionHandle, CURLOPT_HTTPHEADER, NULL);
1180         
1181         return ServerResult;
1182         
1185 bool CalDAVObjectValidSettings(CalDAVConnectionData *ConnData){
1187         // Check if the passed CalDAV Connection Data is has
1188         // an address set. Return false if nullptr is used.
1190         if (ConnData == nullptr){
1191         
1192                 return false;
1193         
1194         }
1195         
1196         // Check the server hostname. Return false
1197         // if no value has been set.
1198         
1199         if (ConnData->Hostname.size() == 0){
1200         
1201                 return false;
1202         
1203         }
1204         
1205         // Check the server port. Return false if
1206         // no value has been set or the port number
1207         // is less than 1 or higher than 65535.
1208         
1209         if (ConnData->Port < 1 || ConnData->Port > 65535){
1210         
1211                 return false;
1212         
1213         }
1214         
1215         // Check the server username. Return false
1216         // if no value has been set.
1217         
1218         if (ConnData->Username.size() == 0){
1219                 
1220                 return false;
1221                 
1222         }       
1223         
1224         // Check the server password. Return false
1225         // if no value has been set.
1226         
1227         if (ConnData->Password.size() == 0){
1228                 
1229                 return false;
1230                 
1231         }
1233         // Cannot check UseSSL: It is either true
1234         // or false.
1235         
1236         // Cannot check Prefix: The prefix may need
1237         // to be worked out first.
1239         // No errors were found whilst checking so
1240         // return true.
1241         
1242         return true;
1246 string BuildServerAddress(CalDAVConnectionData *ConnData, string URIAddress){
1247         
1248         string ServerAddress;
1249         
1250         // Setup the server address.
1251         
1252         if (ConnData->UseSSL == true){
1253                 ServerAddress += "https://";
1254         } else {
1255                 ServerAddress += "http://";
1256         }
1257         
1258         ServerAddress += ConnData->Hostname;
1259         
1260         // Check if server port is 80, otherwise
1261         // specifiy the port number in the address.
1262         
1263         if (ConnData->Port != 80){
1264                 ServerAddress += ":";
1265                 ServerAddress += to_string(ConnData->Port);
1266         }
1267         
1268         ServerAddress += URIAddress;
1269         
1270         return ServerAddress;
1271         
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