Added new user api unit test for the new fields.
[libgcal.git] / src / gcalendar.c
blob7688c9058f542b7c4d066f549785d713fc35c821
1 /*
2 Copyright (c) 2008 Instituto Nokia de Tecnologia
3 All rights reserved.
5 Redistribution and use in source and binary forms, with or without modification,
6 are permitted provided that the following conditions are met:
8 * Redistributions of source code must retain the above copyright notice,
9 this list of conditions and the following disclaimer.
10 * Redistributions in binary form must reproduce the above copyright notice,
11 this list of conditions and the following disclaimer in the documentation
12 and/or other materials provided with the distribution.
13 * Neither the name of the INdT nor the names of its contributors
14 may be used to endorse or promote products derived from this software
15 without specific prior written permission.
17 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 POSSIBILITY OF SUCH DAMAGE.
29 /**
30 * @file gcalendar.c
31 * @author Adenilson Cavalcanti da Silva <adenilson.silva@indt.org.br>
32 * @date Tue Jun 24 16:17:25 2008
34 * @brief libgcal calendar user public API.
36 * Use this functions to handle common tasks when dealing with google calendar.
39 #ifdef HAVE_CONFIG_H
40 #include "config.h"
41 #else
42 #define _GNU_SOURCE
43 #endif
45 #include <string.h>
46 #include <stdio.h>
47 #include "gcalendar.h"
48 #include "internal_gcal.h"
49 #include "gcal_parser.h"
50 #include "msvc_hacks.h"
52 gcal_t gcal_new(gservice mode)
54 return gcal_construct(mode);
57 void gcal_delete(gcal_t gcal_obj)
59 gcal_destroy(gcal_obj);
62 gcal_event_t gcal_event_new(char *raw_xml)
64 gcal_event_t event = NULL;
65 dom_document *doc;
66 int result = -1;
68 event = malloc(sizeof(struct gcal_event));
69 if (!event)
70 goto exit;
71 gcal_init_event(event);
72 if (!raw_xml)
73 goto exit;
75 /* Builds a doc, parse and init object */
76 doc = build_dom_document(raw_xml);
77 if (!doc)
78 goto cleanup;
80 result = extract_all_entries(doc, event, 1);
81 clean_dom_document(doc);
83 cleanup:
84 if (result) {
85 free(event);
86 event = NULL;
89 exit:
90 return event;
93 void gcal_event_delete(gcal_event_t event)
96 if (!event)
97 return;
99 gcal_destroy_entry(event);
100 free(event);
103 int gcal_get_edit_url(char *entry, char **extracted_url)
105 int result = -1;
106 if (!entry)
107 goto exit;
109 result = get_edit_url(entry, strlen(entry), extracted_url);
111 exit:
112 return result;
116 int gcal_get_extract_etag(char *entry, char **extracted_etag)
118 int result = -1;
119 if (!entry)
120 goto exit;
122 result = get_edit_etag(entry, strlen(entry), extracted_etag);
124 exit:
125 return result;
129 int gcal_add_xmlentry(gcal_t gcal_obj, char *xml_entry, char **xml_updated)
131 int result = -1, length = 0;
132 char *buffer = NULL;
134 if ((!gcal_obj) || (!xml_entry))
135 goto exit;
137 if (!(strcmp(gcal_obj->service, "cl")))
138 result = up_entry(xml_entry, strlen(xml_entry), gcal_obj,
139 GCAL_EDIT_URL, NULL,
140 POST, NULL, GCAL_EDIT_ANSWER);
142 else {
143 /* Mounts URL */
144 length = sizeof(GCONTACT_START) + sizeof(GCONTACT_END) +
145 strlen(gcal_obj->user) + sizeof(GCAL_DELIMITER) +
146 strlen(gcal_obj->domain) + 1;
147 buffer = (char *) malloc(length);
148 if (!buffer)
149 goto cleanup;
150 snprintf(buffer, length - 1, "%s%s%s%s%s", GCONTACT_START,
151 gcal_obj->user, GCAL_DELIMITER, gcal_obj->domain,
152 GCONTACT_END);
154 result = up_entry(xml_entry, strlen(xml_entry), gcal_obj,
155 buffer, NULL,
156 POST, NULL, GCAL_EDIT_ANSWER);
159 if (!result)
160 if (xml_updated)
161 *xml_updated = strdup(gcal_obj->buffer);
163 cleanup:
164 if (buffer)
165 free(buffer);
167 exit:
168 return result;
171 int gcal_update_xmlentry(gcal_t gcal_obj, char *xml_entry, char **xml_updated,
172 char *edit_url, char *etag)
174 char *url = NULL, *pvt_etag = NULL;
175 int result = -1;
176 char buffer[512];
177 const char if_match[] = "If-Match: ";
179 memset(buffer, '\0', sizeof(buffer));
181 if ((!gcal_obj) || (!xml_entry))
182 goto exit;
184 if (!edit_url) {
185 result = get_edit_url(xml_entry, strlen(xml_entry), &url);
186 if (result)
187 goto exit;
189 } else
190 if (!(url = strdup(edit_url)))
191 goto exit;
193 if (!etag) {
194 if ((result = get_edit_etag(xml_entry, strlen(xml_entry),
195 &pvt_etag)))
196 goto exit;
197 else
198 etag = pvt_etag;
201 /* Mounts costum HTTP header using ETag */
202 snprintf(buffer, sizeof(buffer) - 1, "%s\%s",
203 if_match, etag);
205 result = up_entry(xml_entry, strlen(xml_entry), gcal_obj, url, buffer,
206 PUT, NULL, GCAL_DEFAULT_ANSWER);
208 if (!result)
209 if (xml_updated)
210 *xml_updated = strdup(gcal_obj->buffer);
212 if (url)
213 free(url);
215 if (pvt_etag)
216 free(pvt_etag);
217 exit:
219 return result;
222 int gcal_erase_xmlentry(gcal_t gcal_obj, char *xml_entry)
224 char *edit_url = NULL;
225 int result = -1;
226 /* I could use just 1 structure object and benefit from the fact
227 * that both have the same field type/name alignment (that would
228 * save 1 structure from the stack). But it would break with any
229 * change in the field type/alignment, I don't think its worthwhile.
231 struct gcal_event event;
232 struct gcal_contact contact;
234 if ((!gcal_obj) || (!xml_entry))
235 goto exit;
237 result = get_edit_url(xml_entry, strlen(xml_entry), &edit_url);
238 if (result)
239 goto exit;
240 event.common.edit_uri = edit_url;
241 contact.common.edit_uri = edit_url;
243 if (!(strcmp(gcal_obj->service, "cl")))
244 result = gcal_delete_event(gcal_obj, &event);
246 else
247 result = gcal_delete_contact(gcal_obj, &contact);
249 if (edit_url)
250 free(edit_url);
252 exit:
253 return result;
257 int gcal_add_event(gcal_t gcal_obj, gcal_event_t event)
259 int result = -1;
260 struct gcal_event updated;
261 gcal_init_event(&updated);
263 if ((!gcal_obj) || (!event))
264 goto exit;
266 result = gcal_create_event(gcal_obj, event, &updated);
267 if (result)
268 goto exit;
270 /* Swap updated fields: id, updated, edit_uri, etag */
271 if (event->common.id)
272 free(event->common.id);
273 event->common.id = updated.common.id;
274 updated.common.id = NULL;
276 if (event->common.updated)
277 free(event->common.updated);
278 event->common.updated = updated.common.updated;
279 updated.common.updated = NULL;
281 if (event->common.edit_uri)
282 free(event->common.edit_uri);
283 event->common.edit_uri = updated.common.edit_uri;
284 updated.common.edit_uri = NULL;
286 if (event->common.etag)
287 free(event->common.etag);
288 event->common.etag = updated.common.etag;
289 updated.common.etag = NULL;
291 /* Cleanup updated event */
292 gcal_destroy_entry(&updated);
293 exit:
294 return result;
297 int gcal_update_event(gcal_t gcal_obj, gcal_event_t event)
299 int result = -1;
300 struct gcal_event updated;
302 if ((!gcal_obj) || (!event))
303 goto exit;
305 result = gcal_edit_event(gcal_obj, event, &updated);
306 if (result)
307 goto exit;
309 /* Swap updated fields: updated, edit_uri, etag */
310 if (event->common.updated)
311 free(event->common.updated);
312 event->common.updated = updated.common.updated;
313 updated.common.updated = NULL;
315 if (event->common.edit_uri)
316 free(event->common.edit_uri);
317 event->common.edit_uri = updated.common.edit_uri;
318 updated.common.edit_uri = NULL;
320 if (event->common.etag)
321 free(event->common.etag);
322 event->common.etag = updated.common.etag;
323 updated.common.etag = NULL;
325 /* Cleanup updated event */
326 gcal_destroy_entry(&updated);
327 exit:
328 return result;
332 int gcal_erase_event(gcal_t gcal_obj, gcal_event_t event)
334 int result = -1;
335 if ((!gcal_obj) || (!event))
336 goto exit;
338 result = gcal_delete_event(gcal_obj, event);
339 exit:
340 return result;
343 int gcal_get_updated_events(gcal_t gcal_obj, struct gcal_event_array *events,
344 char *timestamp)
346 int result = -1;
347 if (events)
348 events->length = 0;
350 if ((!gcal_obj) || (!events))
351 return result;
353 result = gcal_query_updated(gcal_obj, timestamp, "GData-Version: 2");
354 if (result) {
355 events->entries = NULL;
356 events->length = 0;
357 return result;
360 events->entries = gcal_get_entries(gcal_obj, &events->length);
361 if (events->entries)
362 result = 0;
364 return result;
367 int gcal_get_events(gcal_t gcalobj, struct gcal_event_array *events_array)
369 int result = -1;
370 if (events_array)
371 events_array->length = 0;
373 if ((!gcalobj) || (!events_array))
374 goto exit;
376 result = gcal_dump(gcalobj, "GData-Version: 2");
377 if (result == -1) {
378 events_array->entries = NULL;
379 events_array->length = 0;
380 goto exit;
383 events_array->entries = gcal_get_entries(gcalobj, &events_array->length);
384 if (!events_array->entries)
385 result = -1;
387 exit:
388 return result;
391 void gcal_cleanup_events(struct gcal_event_array *events)
393 if (!events)
394 return;
396 gcal_destroy_entries(events->entries, events->length);
397 events->length = 0;
398 events->entries = NULL;
401 gcal_event_t gcal_event_element(struct gcal_event_array *events, size_t _index)
403 struct gcal_event *event = NULL;
404 if ((!events) || (_index > (events->length - 1)) ||
405 (events->length == 0))
406 return event;
408 event = &events->entries[_index];
409 return event;
412 char *gcal_event_get_xml(gcal_event_t event)
414 if ((!event))
415 return NULL;
416 return gcal_get_xml(&(event->common));
419 char gcal_event_is_deleted(gcal_event_t event)
421 if ((!event))
422 return -1;
423 return gcal_get_deleted(&(event->common));
426 char *gcal_event_get_id(gcal_event_t event)
428 if ((!event))
429 return NULL;
430 return gcal_get_id(&(event->common));
433 char *gcal_event_get_updated(gcal_event_t event)
435 if ((!event))
436 return NULL;
437 return gcal_get_updated(&(event->common));
440 char *gcal_event_get_title(gcal_event_t event)
442 if ((!event))
443 return NULL;
444 return gcal_get_title(&(event->common));
447 char *gcal_event_get_url(gcal_event_t event)
449 if ((!event))
450 return NULL;
451 return gcal_get_url(&(event->common));
454 char *gcal_event_get_etag(gcal_event_t event)
456 if ((!event))
457 return NULL;
458 return gcal_get_etag(&(event->common));
461 /* This are the fields unique to calendar events */
462 char *gcal_event_get_content(gcal_event_t event)
464 if ((!event))
465 return NULL;
466 return event->content;
469 char *gcal_event_get_recurrent(gcal_event_t event)
471 if ((!event))
472 return NULL;
473 return event->dt_recurrent;
476 char *gcal_event_get_start(gcal_event_t event)
478 if ((!event))
479 return NULL;
480 return event->dt_start;
483 char *gcal_event_get_end(gcal_event_t event)
485 if ((!event))
486 return NULL;
487 return event->dt_end;
490 char *gcal_event_get_where(gcal_event_t event)
492 if ((!event))
493 return NULL;
494 return event->where;
497 char *gcal_event_get_status(gcal_event_t event)
499 if ((!event))
500 return NULL;
501 return event->status;
505 /* Here starts the setters */
506 int gcal_event_set_title(gcal_event_t event, const char *field)
508 int result = -1;
510 if ((!event) || (!field))
511 return result;
513 if (event->common.title)
514 free(event->common.title);
516 event->common.title = strdup(field);
517 if (event->common.title)
518 result = 0;
520 return result;
523 int gcal_event_set_content(gcal_event_t event, const char *field)
525 int result = -1;
527 if ((!event) || (!field))
528 return result;
530 if (event->content)
531 free(event->content);
533 event->content = strdup(field);
534 if (event->content)
535 result = 0;
537 return result;
540 int gcal_event_set_start(gcal_event_t event, const char *field)
542 int result = -1;
544 if ((!event) || (!field))
545 return result;
547 if (event->dt_start)
548 free(event->dt_start);
550 event->dt_start = strdup(field);
551 if (event->dt_start)
552 result = 0;
554 return result;
557 int gcal_event_set_end(gcal_event_t event, const char *field)
559 int result = -1;
561 if ((!event) || (!field))
562 return result;
564 if (event->dt_end)
565 free(event->dt_end);
567 event->dt_end = strdup(field);
568 if (event->dt_end)
569 result = 0;
571 return result;
574 int gcal_event_set_where(gcal_event_t event, const char *field)
576 int result = -1;
578 if ((!event) || (!field))
579 return result;
581 if (event->where)
582 free(event->where);
584 event->where = strdup(field);
585 if (event->where)
586 result = 0;
588 return result;
592 int gcal_event_set_url(gcal_event_t event, const char *field)
594 int result = -1;
596 if ((!event) || (!field))
597 return result;
599 if (event->common.edit_uri)
600 free(event->common.edit_uri);
602 event->common.edit_uri = strdup(field);
603 if (event->common.edit_uri)
604 result = 0;
606 return result;
610 int gcal_event_set_id(gcal_event_t event, const char *field)
612 int result = -1;
614 if ((!event) || (!field))
615 return result;
617 if (event->common.id)
618 free(event->common.id);
620 event->common.id = strdup(field);
621 if (event->common.id)
622 result = 0;
624 return result;
628 int gcal_event_set_etag(gcal_event_t event, const char *field)
630 int result = -1;
632 if ((!event) || (!field))
633 return result;
635 if (event->common.etag)
636 free(event->common.etag);
638 event->common.etag = strdup(field);
639 if (event->common.etag)
640 result = 0;
642 return result;