]>
git.datanom.net - caldav.git/blob - src/caldav.c
4 * Copyright 2016 Michael Rasmussen <mir@datanom.net>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
32 static gchar
* get_timerange(Runtime
* runtime
) {
33 gchar
* timerange
= NULL
;
35 if (runtime
->start
&& runtime
->finish
) {
36 GDateTime
* s_utc
= g_date_time_to_utc(runtime
->start
);
37 GDateTime
* f_utc
= g_date_time_to_utc(runtime
->finish
);
38 gchar
* start
= g_date_time_format(s_utc
, "%Y%m%dT%H%M%SZ");
39 gchar
* finish
= g_date_time_format(f_utc
, "%Y%m%dT%H%M%SZ");
40 g_date_time_unref(s_utc
);
41 g_date_time_unref(f_utc
);
43 timerange
= g_strconcat(
44 "<c:time-range start=\"", start
, "\"",
45 " end=\"", finish
, "\"/>",
55 * Operation Depth RequestType
56 * CALENDARINFO 0 PROPFIND
61 * DELETEOBJECTS - DELETE
63 * OPTIONSINFO 0 OPTIONS
66 static Request
* request_init(Runtime
* r
) {
67 Request
* rq
= request_new();
68 GString
* href
= g_string_new("");
69 gchar
* timerange
= NULL
;
71 switch (*r
->operation
) {
73 rq
->request
= PROPFIND
;
74 rq
->headers
= g_slist_append(rq
->headers
, g_strdup("Depth: 0"));
75 rq
->headers
= g_slist_append(rq
->headers
, g_strdup("Prefer: return-minimal"));
76 rq
->data
= g_strconcat(
77 "<?xml version=\"1.0\" encoding=\"utf-8\" ?>",
78 "<d:propfind xmlns:d=\"DAV:\" xmlns:cs=\"http://calendarserver.org/ns/\">",
79 "<d:prop><d:displayname /><cs:getctag /></d:prop></d:propfind>",
84 rq
->headers
= g_slist_append(rq
->headers
, g_strdup("Depth: 1"));
85 rq
->headers
= g_slist_append(rq
->headers
, g_strdup("Prefer: return-minimal"));
87 for (GSList
* l
= r
->hrefs
; l
; l
= g_slist_next(l
)) {
88 HrefData
* h
= (HrefData
*) l
->data
;
89 gchar
* elem
= g_strconcat("<d:href>", h
->href
, "</d:href>", NULL
);
90 href
= g_string_append(href
, elem
);
94 rq
->data
= g_strconcat(
95 "<?xml version=\"1.0\" encoding=\"utf-8\" ?>",
96 "<c:calendar-multiget xmlns:d=\"DAV:\" xmlns:c=\"urn:ietf:params:xml:ns:caldav\">",
97 "<d:prop><d:getetag /><c:calendar-data /></d:prop>",
98 g_string_free(href
, FALSE
), "</c:calendar-multiget>",
102 rq
->request
= REPORT
;
103 rq
->headers
= g_slist_append(rq
->headers
, g_strdup("Depth: 1"));
104 rq
->headers
= g_slist_append(rq
->headers
, g_strdup("Prefer: return-minimal"));
105 timerange
= get_timerange(r
);
106 rq
->data
= g_strconcat(
107 "<?xml version=\"1.0\" encoding=\"utf-8\" ?>",
108 "<c:calendar-query xmlns:d=\"DAV:\" xmlns:c=\"urn:ietf:params:xml:ns:caldav\">",
109 "<d:prop><d:getetag /><c:calendar-data /></d:prop>",
110 "<c:filter><c:comp-filter name=\"VCALENDAR\">",
111 "<c:comp-filter name=\"VEVENT\">",timerange
? timerange
: "",
112 "</c:comp-filter></c:comp-filter>",
113 "</c:filter></c:calendar-query>",
119 rq
->request
= REPORT
;
120 rq
->headers
= g_slist_append(rq
->headers
, g_strdup("Depth: 1"));
121 rq
->headers
= g_slist_append(rq
->headers
, g_strdup("Prefer: return-minimal"));
122 timerange
= get_timerange(r
);
123 rq
->data
= g_strconcat(
124 "<?xml version=\"1.0\" encoding=\"utf-8\" ?>",
125 "<c:calendar-query xmlns:d=\"DAV:\" xmlns:c=\"urn:ietf:params:xml:ns:caldav\">",
126 "<d:prop><d:getetag /></d:prop><c:filter><c:comp-filter name=\"VCALENDAR\">",
127 "<c:comp-filter name=\"VEVENT\">",timerange
? timerange
: "",
128 "</c:comp-filter></c:comp-filter>",
129 "</c:filter></c:calendar-query>",
136 rq
->headers
= g_slist_append(rq
->headers
, g_strconcat("If-Match: \"", r
->etag
? r
->etag
: "", "\"", NULL
));
137 rq
->data
= g_strdup(r
->component
? r
->component
: "");
141 rq
->headers
= g_slist_append(rq
->headers
, g_strdup("If-None-Match: *"));
142 rq
->data
= g_strdup(r
->component
? r
->component
: "");
145 rq
->request
= DELETE
;
146 rq
->headers
= g_slist_append(rq
->headers
, g_strconcat("If-Match: \"", r
->etag
? r
->etag
: "", "\"", NULL
));
149 rq
->request
= PROPFIND
;
150 rq
->headers
= g_slist_append(rq
->headers
, g_strdup("Depth: 0"));
151 rq
->headers
= g_slist_append(rq
->headers
, g_strdup("Prefer: return-minimal"));
155 rq
->headers
= g_slist_append(rq
->headers
, g_strdup("Depth: 0"));
156 rq
->headers
= g_slist_append(rq
->headers
, g_strdup("Prefer: return-minimal"));
159 rq
->request
= OPTIONS
;
160 rq
->headers
= g_slist_append(rq
->headers
, g_strdup("Depth: 0"));
161 rq
->headers
= g_slist_append(rq
->headers
, g_strdup("Prefer: return-minimal"));
165 rq
->headers
= g_slist_append(rq
->headers
, g_strdup("Depth: 0"));
166 rq
->headers
= g_slist_append(rq
->headers
, g_strdup("Prefer: return-minimal"));
167 rq
->headers
= g_slist_append(rq
->headers
, g_strdup("Timeout: Second-60"));
168 rq
->data
= g_strconcat(
169 "<?xml version=\"1.0\" encoding=\"utf-8\" ?>",
170 "<D:lockinfo xmlns:D=\"DAV:\"><D:lockscope><D:exclusive/></D:lockscope>",
171 " <D:locktype><D:write/></D:locktype></D:lockinfo>",
175 rq
->request
= UNLOCK
;
176 rq
->headers
= g_slist_append(rq
->headers
, g_strdup("Depth: 0"));
177 rq
->headers
= g_slist_append(rq
->headers
, g_strdup("Prefer: return-minimal"));
180 rq
->request
= REPORT
;
181 rq
->headers
= g_slist_append(rq
->headers
, g_strdup("Depth: 1"));
182 rq
->headers
= g_slist_append(rq
->headers
, g_strdup("Prefer: return-minimal"));
183 timerange
= get_timerange(r
);
184 rq
->data
= g_strconcat(
185 "<?xml version=\"1.0\" encoding=\"utf-8\" ?>",
186 "<c:free-busy-query xmlns:D=\"DAV:\"",
187 " xmlns:c=\"urn:ietf:params:xml:ns:caldav\">",
188 timerange
? timerange
: "", "</c:free-busy-query>",
199 rq
->headers
= g_slist_append(rq
->headers
, g_strdup("Content-Type: application/xml; charset=utf-8"));
200 rq
->username
= g_strdup(r
->username
);
201 rq
->password
= g_strdup(r
->password
);
202 rq
->url
= g_strdup(r
->url
);
208 static gchar
* get_host_part(const gchar
* url
) {
209 gchar
* host_part
= NULL
;
211 gchar
* s
= g_strstr_len(url
, -1, "://");
218 gchar
* s1
= g_strstr_len(s
, -1, "/");
221 host_part
= g_strndup(url
, s1
- url
);
223 host_part
= g_strdup(url
);
229 static GSList
* gchar_list_copy(GSList
* list
) {
230 GSList
* headers
= NULL
;
231 for (GSList
* l
= list
; l
; l
= g_slist_next(l
)) {
232 gchar
* h
= g_strdup((gchar
*) l
->data
);
233 headers
= g_slist_append(headers
, h
);
239 static void debug_request(Request
* rq
) {
240 printf("HTTP Headers:\n");
241 for (GSList
* l
= rq
->headers
; l
; l
= g_slist_next(l
)) {
242 printf("%s\n", (gchar
*) l
->data
);
244 switch (rq
->request
) {
245 case DELETE
: printf("DELETE "); break;
246 case PROPFIND
: printf("PROPFIND "); break;
247 case PUT
: printf("PUT "); break;
248 case REPORT
: printf("REPORT "); break;
249 case GET
: printf("GET "); break;
250 case OPTIONS
: printf("OPTIONS "); break;
251 case LOCK
: printf("LOCK "); break;
252 case UNLOCK
: printf("UNLOCK "); break;
254 printf("%s\n", rq
->url
);
255 printf("DATA:\n%s\n", rq
->data
? rq
->data
: "None");
258 static void debug_response(Response
* r
) {
259 printf("HTTP Status: %i\nHTTP headers:\n", r
->status
);
260 for (GSList
* l
= r
->headers
; l
; l
= g_slist_next(l
)) {
261 printf("%s\n", (gchar
*) l
->data
);
265 static guint
execute_options(gpointer ptr
);
266 static void caldav_response_free(Operation op
, CaldavResponse
* cr
);
268 static gchar
* execute_locking(Runtime
* runtime
, const gchar
* lock_token
, guint
* status
) {
273 Runtime
* tmp
= runtime_copy(runtime
);
275 *tmp
->operation
= OPTIONSINFO
;
276 guint status
= execute_options((gpointer
) tmp
);
279 caldav_response_free(*tmp
->operation
, tmp
->output
);
280 runtime
->options
= slist_copy_gchar(tmp
->options
);
283 if (tmp
->options
&& has_option(tmp
, "lock")) {
285 *tmp
->operation
= UNLOCKING
;
286 rq
= request_init(tmp
);
287 rq
->headers
= g_slist_append(rq
->headers
,
288 g_strconcat("Lock-Token: ", lock_token
, NULL
));
290 if (runtime
->debug
) {
293 r
= request_send(rq
, runtime
->debug
);
295 if (runtime
->debug
) {
300 *tmp
->operation
= LOCKING
;
301 rq
= request_init(tmp
);
303 if (runtime
->debug
) {
306 r
= request_send(rq
, runtime
->debug
);
308 if (runtime
->debug
) {
312 if (r
->status
!= 423)
313 token
= find_header(r
->headers
, "Lock-Token");
315 token
= g_strdup(r
->data
);
330 static guint
execute_default(gpointer ptr
) {
331 Runtime
* runtime
= (Runtime
*) ptr
;
332 Request
* rq
= request_init(runtime
);
334 gchar
* lock_token
= NULL
;
337 if (runtime
->debug
) {
341 if (*runtime
->operation
== DELETEOBJECTS
) {
342 lock_token
= execute_locking(runtime
, NULL
, &status
);
344 runtime
->output
= g_new0(CaldavResponse
, 1);
345 runtime
->output
->data
= (gpointer
) g_strdup(lock_token
);
346 runtime
->output
->status
= status
;
353 rq
->headers
= g_slist_append(rq
->headers
,
354 g_strconcat("Lock-Token: ", lock_token
, NULL
));
356 Response
* r
= request_send(rq
, runtime
->debug
);
358 execute_locking(runtime
, lock_token
, &status
);
364 if (runtime
->debug
) {
368 runtime
->output
= g_new0(CaldavResponse
, 1);
369 runtime
->output
->data
= (gpointer
) g_strdup(r
->data
);
372 fprintf(runtime
->file
, r
->data
);
374 runtime
->output
->status
= status
= r
->status
;
376 runtime
->output
->headers
= gchar_list_copy(r
->headers
);
384 static guint
execute_options(gpointer ptr
) {
385 Runtime
* runtime
= (Runtime
*) ptr
;
386 Request
* rq
= request_init(runtime
);
390 if (runtime
->debug
) {
393 Response
* r
= request_send(rq
, runtime
->debug
);
396 if (runtime
->debug
) {
400 gchar
* headers
= find_header(r
->headers
, "Allow");
402 gchar
** options
= g_strsplit(headers
, ",", 0);
403 for (int i
= 0; options
[i
]; i
++) {
404 gchar
* tmp
= g_strdup(options
[i
]);
405 tmp
= g_strstrip(tmp
);
406 runtime
->options
= g_slist_append(runtime
->options
, g_strdup(tmp
));
414 for (GSList
* l
= runtime
->options
; l
; l
= g_slist_next(l
)) {
415 fprintf(runtime
->file
, "%s\n", (gchar
*) l
->data
);
419 runtime
->output
= g_new0(CaldavResponse
, 1);
420 runtime
->output
->status
= status
= r
->status
;
422 runtime
->output
->headers
= gchar_list_copy(r
->headers
);
430 static guint
execute_freebusy(gpointer ptr
) {
431 Runtime
* runtime
= (Runtime
*) ptr
;
433 Request
* rq
= request_init(runtime
);
437 if (runtime
->debug
) {
440 Response
* r
= request_send(rq
, runtime
->debug
);
443 if (runtime
->debug
) {
447 runtime
->output
= g_new0(CaldavResponse
, 1);
448 runtime
->output
->data
= (gpointer
) g_strdup(r
->data
);
451 fprintf(runtime
->file
, r
->data
);
453 runtime
->output
->status
= status
= r
->status
;
455 runtime
->output
->headers
= gchar_list_copy(r
->headers
);
463 static guint
execute_discover(gpointer ptr
) {
464 Runtime
* runtime
= (Runtime
*) ptr
;
470 rq
= request_init(runtime
);
472 rq
->data
= g_strconcat(
473 "<?xml version=\"1.0\" encoding=\"utf-8\" ?>",
474 "<d:propfind xmlns:d=\"DAV:\">",
475 "<d:prop><d:current-user-principal /></d:prop></d:propfind>",
477 if (runtime
->debug
) {
480 r
= request_send(rq
, runtime
->debug
);
482 if (runtime
->debug
) {
485 list
= find_element("//d:current-user-principal/*", r
->data
, "d", "DAV:");
488 /* Change URL to where "current-user-principal" is located */
489 gchar
* s
= get_host_part(runtime
->url
);
490 g_free(runtime
->url
);
491 runtime
->url
= g_strconcat(s
, list
->data
, NULL
);
493 slist_free_gchar(list
);
497 rq
->data
= g_strconcat(
498 "<?xml version=\"1.0\" encoding=\"utf-8\" ?>",
499 "<d:propfind xmlns:d=\"DAV:\" xmlns:c=\"urn:ietf:params:xml:ns:caldav\">",
500 "<d:prop><c:calendar-home-set /></d:prop></d:propfind>",
502 r
= request_send(rq
, runtime
->debug
);
503 list
= find_element("//c:calendar-home-set/*", r
->data
,
504 "c", "urn:ietf:params:xml:ns:caldav");
507 /* Change URL to where "calendar-home-set" is located */
508 gchar
* s
= get_host_part(runtime
->url
);
509 g_free(runtime
->url
);
510 runtime
->url
= g_strconcat(s
, list
->data
, NULL
);
512 slist_free_gchar(list
);
516 rq
->data
= g_strconcat(
517 "<?xml version=\"1.0\" encoding=\"utf-8\" ?>",
518 "<d:propfind xmlns:d=\"DAV:\" xmlns:cs=\"http://calendarserver.org/ns/\" ",
519 "xmlns:c=\"urn:ietf:params:xml:ns:caldav\">",
520 "<d:prop><d:resourcetype/><d:displayname/><cs:getctag/>",
521 "<c:supported-calendar-component-set/></d:prop></d:propfind>",
523 for (GSList
* l
= rq
->headers
; l
; l
= g_slist_next(l
)) {
524 if (g_strcmp0(l
->data
, "Depth: 0") == 0) {
526 l
->data
= g_strdup("Depth: 1");
530 r
= request_send(rq
, runtime
->debug
);
531 gchar
* s
= get_host_part(runtime
->url
);
532 list
= find_calendars(s
, r
->data
);
535 runtime
->output
= g_new0(CaldavResponse
, 1);
537 for (GSList
* l
= list
; l
; l
= g_slist_next(l
)) {
538 Calendar
* c
= calendar_copy((Calendar
*) l
->data
);
539 data
= g_slist_append(data
, c
);
541 runtime
->output
->data
= (gpointer
) data
;
544 for (GSList
* l
= list
; l
; l
= g_slist_next(l
)) {
545 calendar_dump(runtime
->file
, (Calendar
*) l
->data
);
548 g_slist_foreach(list
, (GFunc
)calendar_free
, NULL
);
552 runtime
->output
->headers
= gchar_list_copy(r
->headers
);
554 runtime
->output
->status
= status
= r
->status
;
563 static guint
execute_add_update(gpointer ptr
) {
564 Runtime
* runtime
= (Runtime
*) ptr
;
565 Request
* rq
= request_init(runtime
);
567 gchar
* lock_token
= NULL
;
570 if (runtime
->debug
) {
574 if (*runtime
->operation
== UPDATEOBJECTS
) {
575 lock_token
= execute_locking(runtime
, NULL
, &status
);
577 runtime
->output
= g_new0(CaldavResponse
, 1);
578 runtime
->output
->data
= (gpointer
) g_strdup(lock_token
);
579 runtime
->output
->status
= status
;
586 rq
->headers
= g_slist_append(rq
->headers
,
587 g_strconcat("Lock-Token: ", lock_token
, NULL
));
589 Response
* r
= request_send(rq
, runtime
->debug
);
591 execute_locking(runtime
, lock_token
, &status
);
597 if (runtime
->debug
) {
601 runtime
->output
= g_new0(CaldavResponse
, 1);
602 if (r
->status
== 201 || r
->status
== 204) {
603 gchar
* etag
= find_header(r
->headers
, "ETag");
605 Runtime
* r_new
= runtime_copy(runtime
);
606 *r_new
->operation
= SIMPLEGET
;
607 guint s
= execute(r_new
);
608 if (s
== 200 && r_new
->output
&& r_new
->output
->headers
) {
609 etag
= find_header(r_new
->output
->headers
, "ETag");
613 runtime
->output
->data
= (gpointer
) g_strdup(etag
);
616 fprintf(runtime
->file
, "ETag: %s\n", etag
);
618 fprintf(runtime
->file
, "%s\n", "No ETag returned");
622 runtime
->output
->data
= (gpointer
) g_strdup(r
->data
);
624 fprintf(runtime
->file
, "%s\n", r
->data
);
627 runtime
->output
->status
= status
= r
->status
;
629 runtime
->output
->headers
= gchar_list_copy(r
->headers
);
637 static void caldav_response_free(Operation op
, CaldavResponse
* cr
) {
642 slist_free_gchar(cr
->headers
);
648 list
= (GSList
*) cr
->data
;
649 g_slist_foreach(list
, (GFunc
)calendar_free
, NULL
);
653 list
= (GSList
*) cr
->data
;
654 slist_free_gchar(list
);
657 g_free((gchar
*)cr
->data
);
664 gchar
* find_header(GSList
* list
, const gchar
* header
) {
665 g_return_val_if_fail(header
!= NULL
, NULL
);
669 for (GSList
* l
= list
; l
; l
= g_slist_next(l
)) {
670 gchar
* s
= (gchar
*) l
->data
;
671 gchar
** t
= g_strsplit(s
, ":", 2);
672 for (int i
= 0; t
[i
]; i
++) {
673 gchar
* s1
= g_utf8_casefold(g_strstrip(t
[i
]), -1);
674 gchar
* s2
= g_utf8_casefold(header
, -1);
675 if (g_strcmp0(s1
, s2
) == 0) {
677 hit
= g_string_append(hit
, ", ");
678 hit
= g_string_append(hit
, g_strstrip(t
[i
+1]));
680 hit
= g_string_new(g_strstrip(t
[i
+1]));
688 return (hit
) ? g_string_free(hit
, FALSE
) : NULL
;
691 void slist_free_gchar(GSList
* list
) {
693 g_slist_foreach(list
, (GFunc
)g_free
, NULL
);
699 Runtime
* runtime_new() {
700 Runtime
* r
= g_new0(Runtime
, 1);
701 r
->default_executor
= TRUE
;
706 Calendar
* calendar_copy(Calendar
* cal
) {
707 Calendar
* new_cal
= NULL
;
712 new_cal
= g_new0(Calendar
, 1);
713 new_cal
->displayname
= g_strdup(cal
->displayname
);
714 new_cal
->url
= g_strdup(cal
->url
);
715 new_cal
->ctag
= g_strdup(cal
->ctag
);
716 new_cal
->components
= g_slist_copy(cal
->components
);
721 void calendar_dump(FILE* file
, Calendar
* cal
) {
722 g_return_if_fail(file
&& cal
);
724 fprintf(file
, "------- Display Name: %s -------\n", cal
->displayname
);
725 fprintf(file
, "URL: %s\n", cal
->url
);
726 fprintf(file
, "CTAG: %s\n", cal
->ctag
);
727 fprintf(file
, "Supported components\n");
728 for (GSList
* l
= cal
->components
; l
; l
= g_slist_next(l
)) {
729 Component c
= GPOINTER_TO_UINT(l
->data
);
730 gchar
* value
= component_to_string(c
);
731 fprintf(file
, "\t%s\n", value
);
736 void calendar_free(Calendar
* cal
) {
746 if (cal
->displayname
) {
747 g_free(cal
->displayname
);
748 cal
->displayname
= NULL
;
750 if (cal
->components
) {
751 g_slist_free(cal
->components
);
752 cal
->components
= NULL
;
759 void runtime_free(Runtime
* runtime
) {
761 if (runtime
->username
) {
762 g_free(runtime
->username
);
763 runtime
->username
= NULL
;
765 if (runtime
->password
) {
766 g_free(runtime
->password
);
767 runtime
->password
= NULL
;
770 g_free(runtime
->url
);
774 g_free(runtime
->etag
);
775 runtime
->etag
= NULL
;
777 if (runtime
->component
) {
778 g_free(runtime
->component
);
779 runtime
->component
= NULL
;
781 if (runtime
->hrefs
) {
782 slist_free_gchar(runtime
->hrefs
);
783 runtime
->hrefs
= NULL
;
785 if (runtime
->options
) {
786 slist_free_gchar(runtime
->options
);
787 runtime
->options
= NULL
;
789 if (runtime
->output
&& runtime
->default_executor
) {
790 caldav_response_free(*runtime
->operation
, runtime
->output
);
791 runtime
->output
= NULL
;
793 if (runtime
->operation
) {
794 g_free(runtime
->operation
);
795 runtime
->operation
= NULL
;
797 if (runtime
->executor
) {
798 runtime
->executor
= NULL
;
800 if (runtime
->start
) {
801 g_date_time_unref(runtime
->start
);
802 runtime
->start
= NULL
;
804 if (runtime
->finish
) {
805 g_date_time_unref(runtime
->finish
);
806 runtime
->finish
= NULL
;
813 guint
execute(Runtime
* runtime
) {
814 g_return_val_if_fail(runtime
&& runtime
->operation
, 500);
816 switch (*runtime
->operation
) {
818 runtime
->executor
= execute_discover
;
822 runtime
->executor
= execute_add_update
;
825 runtime
->executor
= execute_options
;
828 runtime
->executor
= execute_freebusy
;
831 runtime
->executor
= execute_default
;
834 return runtime
->executor(runtime
);
837 gboolean
is_component(const gchar
* value
, Component component
) {
838 g_return_val_if_fail(value
!= NULL
, FALSE
);
840 if (g_strcmp0(value
, "VEVENT") == 0 && component
== VEVENT
)
842 else if (g_strcmp0(value
, "VTODO") == 0 && component
== VTODO
)
844 else if (g_strcmp0(value
, "VFREEBUSY") == 0 && component
== VFREEBUSY
)
846 else if (g_strcmp0(value
, "VJOURNAL") == 0 && component
== VJOURNAL
)
852 gchar
* component_to_string(Component component
) {
853 if (component
== VEVENT
)
854 return g_strdup("VEVENT");
855 else if (component
== VTODO
)
856 return g_strdup("VTODO");
857 else if (component
== VFREEBUSY
)
858 return g_strdup("VFREEBUSY");
859 else if (component
== VJOURNAL
)
860 return g_strdup("VJOURNAL");
865 Component
string_to_component(const gchar
* value
) {
866 g_return_val_if_fail(value
!= NULL
, VUNKNOWN
);
868 if (g_strcmp0(value
, "VEVENT") == 0)
870 else if (g_strcmp0(value
, "VTODO") == 0)
872 else if (g_strcmp0(value
, "VFREEBUSY") == 0)
874 else if (g_strcmp0(value
, "VJOURNAL") == 0)
880 gchar
* status_str(Runtime
* runtime
) {
883 g_return_val_if_fail(runtime
&& runtime
->output
, NULL
);
885 switch (runtime
->output
->status
) {
886 case 200: str
= g_strdup("OK"); break;
887 case 201: str
= g_strdup("Created"); break;
888 case 204: str
= g_strdup("No Content"); break;
889 case 207: str
= g_strdup("Multi-Status"); break;
890 case 400: str
= g_strdup("Bad Request"); break;
891 case 401: str
= g_strdup("Unauthorized"); break;
892 case 403: str
= g_strdup("Forbidden"); break;
893 case 404: str
= g_strdup("Not Found"); break;
894 case 405: str
= g_strdup("Method Not Allowed"); break;
895 case 406: str
= g_strdup("Not Acceptable"); break;
896 case 409: str
= g_strdup("Conflict"); break;
897 case 410: str
= g_strdup("Gone"); break;
898 case 412: str
= g_strdup("Precondition Failed"); break;
899 case 415: str
= g_strdup("Unsupported Media Type"); break;
900 case 423: str
= g_strdup("Locked"); break;
901 case 424: str
= g_strdup("Failed Dependency"); break;
902 case 500: str
= g_strdup("Internal Server Error"); break;
903 case 501: str
= g_strdup("Not Implemented"); break;
904 case 503: str
= g_strdup("Service Unavailable"); break;
905 case 507: str
= g_strdup("Insufficient Storage"); break;
906 default: str
= g_strdup_printf("%d: Unexpected status", runtime
->output
->status
);
912 HrefData
* href_data_new(const gchar
* href
, const gchar
* data
) {
913 g_return_val_if_fail(href
!= NULL
, NULL
);
915 HrefData
* h
= g_new0(HrefData
, 1);
916 h
->href
= g_strdup(href
);
917 h
->data
= data
? g_strdup(data
) : NULL
;
922 void href_data_free(HrefData
* href_data
) {
924 if (href_data
->href
) {
925 g_free(href_data
->href
);
926 href_data
->href
= NULL
;
928 if (href_data
->data
) {
929 g_free(href_data
->data
);
930 href_data
->data
= NULL
;
937 gboolean
has_option(Runtime
* runtime
, const gchar
* option
) {
938 g_return_val_if_fail(runtime
&& option
, FALSE
);
939 gboolean has
= FALSE
;
941 gchar
* s2
= g_utf8_casefold(option
, -1);
942 if (runtime
->options
) {
943 for (GSList
* l
= runtime
->options
; l
&& ! has
; l
= g_slist_next(l
)) {
944 gchar
* s1
= g_utf8_casefold((gchar
*) l
->data
, -1);
945 if (g_strcmp0(s1
, s2
) == 0) {
956 Runtime
* runtime_copy(Runtime
* runtime
) {
959 g_return_val_if_fail(runtime
!= NULL
, NULL
);
962 new->username
= g_strdup(runtime
->username
);
963 new->password
= g_strdup(runtime
->password
);
964 new->url
= g_strdup(runtime
->url
);
965 new->debug
= runtime
->debug
;
966 new->operation
= g_new0(Operation
, 1);
967 *new->operation
= *runtime
->operation
;
968 new->executor
= runtime
->executor
;
969 new->default_executor
= runtime
->default_executor
;
970 new->etag
= g_strdup(runtime
->etag
);
971 new->component
= g_strdup(runtime
->component
);
972 new->hrefs
= slist_copy_gchar(runtime
->hrefs
);
973 new->options
= slist_copy_gchar(runtime
->options
);
978 GSList
* slist_copy_gchar(GSList
* list
) {
981 for (GSList
* l
= list
; l
; l
= g_slist_next(l
)) {
982 new = g_slist_append(new, g_strdup(l
->data
));
988 GDateTime
* get_date_time_from_string(const gchar
* datetime
) {
989 GDateTime
* dt
= NULL
;
990 g_return_val_if_fail(datetime
!= NULL
, NULL
);
992 gchar
** dt_part
= g_strsplit(datetime
, "T", 0);
993 if (!dt_part
|| dt_part
[2] != NULL
) {
998 gchar
** d_part
= g_strsplit(dt_part
[0], "-", 0);
999 if (!d_part
|| d_part
[3] != NULL
) {
1000 g_strfreev(dt_part
);
1005 gchar
** t_part
= g_strsplit(dt_part
[1], ":", 0);
1006 if (!t_part
|| t_part
[3] != NULL
) {
1007 g_strfreev(dt_part
);
1012 g_strfreev(dt_part
);
1014 dt
= g_date_time_new_local(
1015 atoi(d_part
[0]), atoi(d_part
[1]), atoi(d_part
[2]),
1016 atoi(t_part
[0]), atoi(t_part
[1]), strtod(t_part
[2], &endptr
));
This page took 0.148344 seconds and 6 git commands to generate.