Changing plugin license to be LGPL (just as opensync itself).
[gdataplugin.git] / src / gcalendar.c
blobe63d48838f80049667e2acf34e04f0f86fde9690
1 /** Google Calendar plugin
3 * Copyright (c) 2006 Eduardo Pereira Habkost <ehabkost@raisama.net>
4 * Copyright (c) 2008 Adenilson Cavalcanti da Silva <adenilson.silva@indt.org.br>
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 Lesser 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, MA
19 * 02110-1301 USA
23 /* TODO:
24 * - find a way to report changes to opensync and make it work
25 * - review code for leaks (I'm not sure if I'm using opensync API correctly...)
29 #define _XOPEN_SOURCE /* man page say: glibc2 needs this */
30 #include <time.h>
31 #include <sys/time.h>
33 #include <opensync/opensync.h>
34 #include <opensync/opensync-plugin.h>
35 #include <opensync/opensync-helper.h>
36 #include <opensync/opensync-merger.h>
37 #include <opensync/opensync-format.h>
38 #include <opensync/opensync-data.h>
39 #include <opensync/opensync-version.h>
41 #include <glib.h>
43 #include <libxml/tree.h>
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <sys/types.h>
49 #include <signal.h>
50 #include <sys/wait.h>
51 #include <gcal_status.h>
52 #include <gcalendar.h>
53 #include <gcontact.h>
54 #include "xslt_aux.h"
57 static int timestamp_cmp(char *timestamp1, char *timestamp2)
59 /* timestamp (RFC3339) formating string */
60 char format[] = "%FT%T";
61 struct tm first, second;
62 time_t t_first, t_second;
63 int result = 0;
65 /* From timestamp string to time structure */
66 strptime(timestamp1, format, &first);
67 strptime(timestamp2, format, &second);
69 /* From time structure to calendar time (since
70 * Epoch (00:00:00 UTC, January 1, 1970)
72 t_first = mktime(&first);
73 t_second = mktime(&second);
75 if (t_first == t_second)
76 result = 0;
77 else if (t_first > t_second)
78 result = 1;
79 else if (t_first < t_second)
80 result = -1;
82 return result;
86 struct gc_plgdata
88 char *url;
89 char *username;
90 char *password;
91 char *gcal_anchor_path;
92 char *gcont_anchor_path;
93 char *timezone;
94 char *xslt_path;
95 /* libgcal resources */
96 char *cal_timestamp;
97 char *cont_timestamp;
98 gcal_t calendar;
99 gcal_t contacts;
100 struct gcal_event_array all_events;
101 struct gcal_contact_array all_contacts;
102 /* calendar sink/format */
103 OSyncObjTypeSink *gcal_sink;
104 OSyncObjFormat *gcal_format;
105 /* contact sink/format */
106 OSyncObjTypeSink *gcont_sink;
107 OSyncObjFormat *gcont_format;
108 /* XSLT context resource struct */
109 struct xslt_resources *xslt_ctx_gcal;
110 struct xslt_resources *xslt_ctx_gcont;
113 static void free_plg(struct gc_plgdata *plgdata)
115 if (plgdata->calendar) {
116 gcal_delete(plgdata->calendar);
117 gcal_cleanup_events(&(plgdata->all_events));
119 if (plgdata->contacts) {
120 gcal_delete(plgdata->contacts);
121 gcal_cleanup_contacts(&(plgdata->all_contacts));
124 if (plgdata->gcal_anchor_path)
125 g_free(plgdata->gcal_anchor_path);
126 if (plgdata->gcont_anchor_path)
127 g_free(plgdata->gcont_anchor_path);
128 if (plgdata->xslt_path)
129 free(plgdata->xslt_path);
130 if (plgdata->xslt_ctx_gcal)
131 xslt_delete(plgdata->xslt_ctx_gcal);
132 if (plgdata->xslt_ctx_gcont)
133 xslt_delete(plgdata->xslt_ctx_gcont);
134 if (plgdata->cal_timestamp)
135 free(plgdata->cal_timestamp);
136 if (plgdata->cont_timestamp)
137 free(plgdata->cont_timestamp);
138 if (plgdata->timezone)
139 free(plgdata->timezone);
140 if (plgdata->url)
141 xmlFree(plgdata->url);
142 if (plgdata->username)
143 xmlFree(plgdata->username);
144 if (plgdata->password)
145 xmlFree(plgdata->password);
146 if (plgdata->gcal_sink)
147 osync_objtype_sink_unref(plgdata->gcal_sink);
148 if (plgdata->gcal_format)
149 osync_objformat_unref(plgdata->gcal_format);
150 g_free(plgdata);
153 static void gc_connect(void *data, OSyncPluginInfo *info, OSyncContext *ctx)
155 osync_trace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, data, info, ctx);
156 static int counter = 0;
157 int result;
158 struct gc_plgdata *plgdata = data;
159 OSyncObjTypeSink *sink = osync_plugin_info_get_sink(info);
160 OSyncError *error = NULL;
161 char buffer[512];
163 if ((plgdata->calendar) && (counter == 0)) {
164 result = gcal_get_authentication(plgdata->calendar, plgdata->username,
165 plgdata->password);
166 ++counter;
167 if (result == -1)
168 goto error;
170 snprintf(buffer, sizeof(buffer) - 1, "%s/gcal2osync.xslt",
171 plgdata->xslt_path);
172 if ((result = xslt_initialize(plgdata->xslt_ctx_gcal, buffer)))
173 goto error;
174 osync_trace(TRACE_INTERNAL, "\ndone calendar: %s\n", buffer);
177 if (((plgdata->contacts) && (counter == 1)) ||
178 ((plgdata->gcont_sink) && (!plgdata->gcal_sink))) {
179 result = gcal_get_authentication(plgdata->contacts, plgdata->username,
180 plgdata->password);
181 counter++;
182 if (result == -1)
183 goto error;
185 snprintf(buffer, sizeof(buffer) - 1, "%s/gcont2osync.xslt",
186 plgdata->xslt_path);
187 if ((result = xslt_initialize(plgdata->xslt_ctx_gcont, buffer)))
188 goto error;
189 osync_trace(TRACE_INTERNAL, "\ndone contact: %s\n", buffer);
192 osync_context_report_success(ctx);
193 osync_trace(TRACE_EXIT, "%s", __func__);
194 return;
196 error:
197 osync_trace(TRACE_INTERNAL, "\nGood bye, cruel world...\n");
198 osync_context_report_osyncerror(ctx, &error);
201 static void gc_get_changes_calendar(void *data, OSyncPluginInfo *info, OSyncContext *ctx)
203 osync_trace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, data, info, ctx);
204 char buffer[512];
205 static int counter = 0;
206 struct gc_plgdata *plgdata = data;
207 char slow_sync_flag = 0;
208 OSyncObjTypeSink *sink = osync_plugin_info_get_sink(info);
209 OSyncError *error = NULL;
210 OSyncXMLFormat *xmlformat;
211 OSyncData *odata = NULL;
212 OSyncChange *chg = NULL;
213 int result = 0, i;
214 char *timestamp = NULL, *msg, *raw_xml = NULL;
215 gcal_event event;
217 if (!plgdata->gcal_sink)
218 return;
219 timestamp = osync_anchor_retrieve(plgdata->gcal_anchor_path, "gcalendar");
220 if (timestamp)
221 osync_trace(TRACE_INTERNAL, "timestamp is: %s\n", timestamp);
222 else
223 osync_trace(TRACE_INTERNAL, "first sync!\n");
225 if (osync_objtype_sink_get_slowsync(plgdata->gcal_sink)) {
226 osync_trace(TRACE_INTERNAL, "\n\t\tgcal: Client asked for slow syncing...\n");
227 slow_sync_flag = 1;
228 result = gcal_get_events(plgdata->calendar, &(plgdata->all_events));
230 } else {
231 osync_trace(TRACE_INTERNAL, "\n\t\tgcal: Client asked for fast syncing...\n");
232 result = gcal_get_updated_events(plgdata->calendar,
233 &(plgdata->all_events),
234 timestamp);
237 if (result) {
238 msg = "Failed getting events!";
239 goto error;
242 osync_trace(TRACE_INTERNAL, "gcalendar: got then all!\n");
243 if (plgdata->all_events.length == 0) {
244 osync_trace(TRACE_INTERNAL, "gcalendar: no changes...\n");
245 goto no_changes;
246 } else
247 osync_trace(TRACE_INTERNAL, "gcalendar: changes count: %d\n",
248 plgdata->all_events.length);
251 /* Calendar returns most recently updated event as first element */
252 event = gcal_event_element(&(plgdata->all_events), 0);
253 if (!event) {
254 msg = "Cannot access last updated event!\n";
255 goto error;
257 plgdata->cont_timestamp = strdup(gcal_event_get_updated(event));
258 if (!plgdata->cont_timestamp) {
259 msg = "Failed copying event timestamp!\n";
260 goto error;
263 for (i = 0; i < plgdata->all_events.length; ++i) {
264 event = gcal_event_element(&(plgdata->all_events), i);
265 if (!event)
266 goto error;
268 raw_xml = gcal_event_get_xml(event);
269 if ((result = xslt_transform(plgdata->xslt_ctx_gcal,
270 raw_xml)))
271 goto error;
273 raw_xml = plgdata->xslt_ctx_gcal->xml_str;
274 xmlformat = osync_xmlformat_parse(raw_xml,
275 strlen(raw_xml),
276 &error);
277 if (!xmlformat)
278 goto error;
280 osync_trace(TRACE_INTERNAL, "gevent: %s\nosync: %s\n",
281 gcal_event_get_xml(event), raw_xml);
283 osync_xmlformat_sort(xmlformat);
284 odata = osync_data_new(xmlformat,
285 osync_xmlformat_size(),
286 plgdata->gcal_format, &error);
287 if (!odata)
288 goto cleanup;
290 if (!(chg = osync_change_new(&error)))
291 goto cleanup;
292 osync_data_set_objtype(odata, osync_objtype_sink_get_name(plgdata->gcal_sink));
293 osync_change_set_data(chg, odata);
294 osync_data_unref(odata);
296 osync_change_set_uid(chg, gcal_event_get_url(event));
298 if (slow_sync_flag)
299 osync_change_set_changetype(chg, OSYNC_CHANGE_TYPE_ADDED);
300 else
301 if (gcal_event_is_deleted(event))
302 osync_change_set_changetype(chg, OSYNC_CHANGE_TYPE_DELETED);
303 else
304 osync_change_set_changetype(chg, OSYNC_CHANGE_TYPE_MODIFIED);
306 osync_context_report_change(ctx, chg);
307 osync_change_unref(chg);
310 no_changes:
312 /* Load XSLT style to convert osync xmlformat-event --> gdata */
313 snprintf(buffer, sizeof(buffer) - 1, "%s/osync2gcal.xslt",
314 plgdata->xslt_path);
315 if ((result = xslt_initialize(plgdata->xslt_ctx_gcal, buffer))) {
316 msg = "Cannot initialize new XSLT!\n";
317 goto error;
320 osync_trace(TRACE_INTERNAL, "\ndone calendar: %s\n", buffer);
322 exit:
323 osync_context_report_success(ctx);
324 return;
326 cleanup:
327 osync_error_unref(&error);
328 osync_xmlformat_unref(&xmlformat);
330 error:
331 osync_context_report_error(ctx, OSYNC_ERROR_GENERIC, msg);
336 static void gc_get_changes_contact(void *data, OSyncPluginInfo *info, OSyncContext *ctx)
338 osync_trace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, data, info, ctx);
339 char buffer[512];
340 static int counter = 0;
341 struct gc_plgdata *plgdata = data;
342 char slow_sync_flag = 0;
343 OSyncObjTypeSink *sink = osync_plugin_info_get_sink(info);
344 OSyncError *error = NULL;
345 OSyncXMLFormat *xmlformat;
346 OSyncData *odata = NULL;
347 OSyncChange *chg = NULL;
348 int result = 0, i;
349 char *timestamp = NULL, *msg, *raw_xml = NULL;
350 gcal_contact contact;
351 slow_sync_flag = 0;
353 if (!plgdata->gcont_sink)
354 return;
355 timestamp = osync_anchor_retrieve(plgdata->gcont_anchor_path, "gcontact");
356 if (timestamp)
357 osync_trace(TRACE_INTERNAL, "timestamp is: %s\n", timestamp);
358 else
359 osync_trace(TRACE_INTERNAL, "first sync!\n");
361 if (osync_objtype_sink_get_slowsync(plgdata->gcont_sink)) {
362 osync_trace(TRACE_INTERNAL, "\n\t\tgcont: Client asked for slow syncing...\n");
363 slow_sync_flag = 1;
364 result = gcal_get_contacts(plgdata->contacts, &(plgdata->all_contacts));
366 } else {
367 osync_trace(TRACE_INTERNAL, "\n\t\tgcont: Client asked for fast syncing...\n");
368 result = gcal_get_updated_contacts(plgdata->contacts,
369 &(plgdata->all_contacts),
370 timestamp);
373 if (result) {
374 msg = "Failed getting contacts!";
375 goto error;
378 osync_trace(TRACE_INTERNAL, "gcontact: got then all!\n");
379 if (plgdata->all_contacts.length == 0) {
380 osync_trace(TRACE_INTERNAL, "gcontact: no changes...\n");
381 goto no_changes;
382 } else
383 osync_trace(TRACE_INTERNAL, "gcontact: changes count: %d\n",
384 plgdata->all_contacts.length);
386 /* Contacts returns most recently updated entry as last element */
387 contact = gcal_contact_element(&(plgdata->all_contacts),
388 (plgdata->all_contacts.length - 1));
389 if (!contact) {
390 msg = "Cannot access last updated contact!\n";
391 goto error;
393 plgdata->cont_timestamp = strdup(gcal_contact_get_updated(contact));
394 if (!plgdata->cont_timestamp) {
395 msg = "Failed copying contact timestamp!\n";
396 goto error;
399 for (i = 0; i < plgdata->all_contacts.length; ++i) {
400 contact = gcal_contact_element(&(plgdata->all_contacts), i);
401 if (!contact)
402 goto error;
404 raw_xml = gcal_contact_get_xml(contact);
405 if ((result = xslt_transform(plgdata->xslt_ctx_gcont,
406 raw_xml)))
407 goto error;
408 raw_xml = plgdata->xslt_ctx_gcont->xml_str;
409 xmlformat = osync_xmlformat_parse(raw_xml,
410 strlen(raw_xml),
411 &error);
412 if (!xmlformat)
413 goto error;
415 osync_trace(TRACE_INTERNAL, "gcont: %s\nosync: %s\n",
416 gcal_contact_get_xml(contact), raw_xml);
418 osync_xmlformat_sort(xmlformat);
420 odata = osync_data_new(xmlformat,
421 osync_xmlformat_size(),
422 plgdata->gcont_format, &error);
424 if (!odata)
425 goto cleanup;
427 if (!(chg = osync_change_new(&error)))
428 goto cleanup;
429 osync_data_set_objtype(odata, osync_objtype_sink_get_name(plgdata->gcont_sink));
430 osync_change_set_data(chg, odata);
431 osync_data_unref(odata);
433 osync_change_set_uid(chg, gcal_contact_get_url(contact));
435 if (slow_sync_flag)
436 osync_change_set_changetype(chg, OSYNC_CHANGE_TYPE_ADDED);
437 else
438 if (gcal_contact_is_deleted(contact))
439 osync_change_set_changetype(chg, OSYNC_CHANGE_TYPE_DELETED);
440 else
441 osync_change_set_changetype(chg, OSYNC_CHANGE_TYPE_MODIFIED);
443 osync_context_report_change(ctx, chg);
444 osync_change_unref(chg);
447 no_changes:
449 /* Load XSLT style to convert osync xmlformat-contact --> gdata */
450 snprintf(buffer, sizeof(buffer) - 1, "%s/osync2gcont.xslt",
451 plgdata->xslt_path);
452 if ((result = xslt_initialize(plgdata->xslt_ctx_gcont, buffer))) {
453 msg = "Cannot initialize new XSLT!\n";
454 goto error;
457 osync_trace(TRACE_INTERNAL, "\ndone contact: %s\n", buffer);
459 exit:
460 osync_context_report_success(ctx);
461 return;
463 cleanup:
464 osync_error_unref(&error);
465 osync_xmlformat_unref(&xmlformat);
467 error:
468 osync_context_report_error(ctx, OSYNC_ERROR_GENERIC, msg);
471 static void gc_commit_change_calendar(void *data, OSyncPluginInfo *info,
472 OSyncContext *ctx, OSyncChange *change)
474 osync_trace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, data, info, ctx, change);
475 osync_trace(TRACE_INTERNAL, "hello, from calendar!\n");
476 OSyncObjTypeSink *sink = osync_plugin_info_get_sink(info);
477 struct gc_plgdata *plgdata = data;
478 gcal_event event = NULL;
480 int size, result;
481 char *osync_xml = NULL, *msg = NULL, *raw_xml = NULL, *updated_event = NULL;
482 OSyncData *odata = NULL;
484 if (!(odata = osync_change_get_data(change))) {
485 msg = "Cannot get raw data from change obj!\n";
486 goto error;
489 osync_data_get_data(odata, &osync_xml, &size);
490 if (!osync_xml) {
491 msg = "Failed getting xml from change obj!\n";
492 goto error;
495 /* Convert to gdata format */
496 if ((result = xslt_transform(plgdata->xslt_ctx_gcal, osync_xml))) {
497 msg = "Failed converting from osync xmlevent to gcalendar\n";
498 goto error;
500 raw_xml = plgdata->xslt_ctx_gcal->xml_str;
502 osync_trace(TRACE_EXIT, "osync: %s\ngcont: %s\n\n", osync_xml, raw_xml);
504 switch (osync_change_get_changetype(change)) {
505 case OSYNC_CHANGE_TYPE_ADDED:
506 result = gcal_add_xmlentry(plgdata->calendar, raw_xml, &updated_event);
507 if (result == -1) {
508 msg = "Failed adding new event!\n";
509 result = gcal_status_httpcode(plgdata->calendar);
510 goto error;
513 if (!(event = gcal_event_new(updated_event))) {
514 msg = "Failed recovering updated fields!\n";
515 goto error;
517 break;
519 case OSYNC_CHANGE_TYPE_MODIFIED:
520 result = gcal_update_xmlentry(plgdata->calendar, raw_xml, &updated_event,
521 NULL);
522 if (result == -1) {
523 msg = "Failed editing event!\n";
524 goto error;
527 if (!(event = gcal_event_new(updated_event))) {
528 msg = "Failed recovering updated fields!\n";
529 goto error;
531 break;
533 case OSYNC_CHANGE_TYPE_DELETED:
534 result = gcal_erase_xmlentry(plgdata->calendar, raw_xml);
535 if (result == -1) {
536 msg = "Failed deleting event!\n";
537 goto error;
539 break;
541 default:
542 osync_context_report_error(ctx, OSYNC_ERROR_NOT_SUPPORTED,
543 "Unknown change type");
544 goto error;
545 break;
548 if (updated_event)
549 free(updated_event);
551 if (event) {
552 /* update the timestamp */
553 if (plgdata->cal_timestamp)
554 free(plgdata->cal_timestamp);
555 plgdata->cal_timestamp = strdup(gcal_event_get_updated(event));
556 if (!plgdata->cal_timestamp) {
557 msg = "Failed copying contact timestamp!\n";
558 goto error;
561 /* FIXME: not sure if this works */
562 /* Inform the new ID */
563 osync_change_set_uid(change, gcal_event_get_url(event));
564 gcal_event_delete(event);
568 osync_context_report_success(ctx);
570 osync_trace(TRACE_EXIT, "%s", __func__);
572 return;
573 error:
574 osync_context_report_error(ctx, OSYNC_ERROR_GENERIC, msg);
575 osync_trace(TRACE_EXIT, "%s:%sHTTP code: %d", __func__, msg, result);
578 static void gc_commit_change_contact(void *data, OSyncPluginInfo *info,
579 OSyncContext *ctx, OSyncChange *change)
581 osync_trace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, data, info, ctx, change);
582 osync_trace(TRACE_INTERNAL, "hello, from contacts!\n");
584 OSyncObjTypeSink *sink = osync_plugin_info_get_sink(info);
585 struct gc_plgdata *plgdata = data;
586 gcal_contact contact = NULL;
587 int size, result;
588 char *osync_xml = NULL, *msg = NULL, *raw_xml = NULL, *updated_contact = NULL;
589 OSyncData *odata = NULL;
591 if (!(odata = osync_change_get_data(change))) {
592 msg = "Cannot get raw data from change obj!\n";
593 goto error;
596 osync_data_get_data(odata, &osync_xml, &size);
597 if (!osync_xml) {
598 msg = "Failed getting xml from change obj!\n";
599 goto error;
602 /* Convert to gdata format */
603 if ((result = xslt_transform(plgdata->xslt_ctx_gcont, osync_xml))) {
604 msg = "Failed converting from osync xmlcontact to gcontact\n";
605 goto error;
607 raw_xml = plgdata->xslt_ctx_gcont->xml_str;
609 osync_trace(TRACE_INTERNAL, "osync: %s\ngcont: %s\n\n", osync_xml, raw_xml);
611 switch (osync_change_get_changetype(change)) {
612 case OSYNC_CHANGE_TYPE_ADDED:
613 result = gcal_add_xmlentry(plgdata->contacts, raw_xml, &updated_contact);
614 if (result == -1) {
615 msg = "Failed adding new contact!\n";
616 result = gcal_status_httpcode(plgdata->contacts);
617 goto error;
620 if (!(contact = gcal_contact_new(updated_contact))) {
621 msg = "Failed recovering updated fields!\n";
622 goto error;
624 break;
626 case OSYNC_CHANGE_TYPE_MODIFIED:
627 result = gcal_update_xmlentry(plgdata->contacts, raw_xml, &updated_contact,
628 NULL);
629 if (result == -1) {
630 msg = "Failed editing contact!\n";
631 goto error;
634 if (!(contact = gcal_contact_new(updated_contact))) {
635 msg = "Failed recovering updated fields!\n";
636 goto error;
638 break;
640 case OSYNC_CHANGE_TYPE_DELETED:
641 result = gcal_erase_xmlentry(plgdata->contacts, raw_xml);
642 if (result == -1) {
643 msg = "Failed deleting contact!\n";
644 goto error;
646 break;
648 default:
649 osync_context_report_error(ctx, OSYNC_ERROR_NOT_SUPPORTED,
650 "Unknown change type");
651 goto error;
652 break;
655 if (updated_contact)
656 free(updated_contact);
658 if (contact) {
659 /* update the timestamp */
660 if (plgdata->cont_timestamp)
661 free(plgdata->cont_timestamp);
662 plgdata->cont_timestamp = strdup(gcal_contact_get_updated(contact));
663 if (!plgdata->cont_timestamp) {
664 msg = "Failed copying contact timestamp!\n";
665 goto error;
668 /* FIXME: not sure if this works */
669 /* Inform the new ID */
670 osync_change_set_uid(change, gcal_contact_get_url(contact));
671 gcal_contact_delete(contact);
674 osync_context_report_success(ctx);
675 osync_trace(TRACE_EXIT, "%s", __func__);
676 return;
678 error:
679 osync_context_report_error(ctx, OSYNC_ERROR_GENERIC, msg);
680 osync_trace(TRACE_EXIT, "%s:%sHTTP code: %d", __func__, msg, result);
683 static void gc_sync_done(void *data, OSyncPluginInfo *info, OSyncContext *ctx)
685 osync_trace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, data, info, ctx);
686 struct gc_plgdata *plgdata = data;
687 OSyncObjTypeSink *sink = osync_plugin_info_get_sink(info);
689 if (plgdata->calendar && plgdata->cal_timestamp) {
690 /* FIXME: hack to workaround the limitation of google protocol
691 * doing inclusive query: advance 1 second in timestamp.
693 plgdata->cal_timestamp[18] += 1;
694 osync_trace(TRACE_INTERNAL, "query updated timestamp: %s\n",
695 plgdata->cal_timestamp);
696 osync_anchor_update(plgdata->gcal_anchor_path, "gcalendar",
697 plgdata->cal_timestamp);
700 if (plgdata->contacts && plgdata->cont_timestamp) {
701 /* FIXME: hack to workaround the limitation of google protocol
702 * doing inclusive query: advance 1 second in timestamp.
704 plgdata->cont_timestamp[18] += 1;
705 osync_trace(TRACE_INTERNAL, "query updated timestamp: %s\n",
706 plgdata->cont_timestamp);
707 osync_anchor_update(plgdata->gcont_anchor_path, "gcontact",
708 plgdata->cont_timestamp);
711 osync_context_report_success(ctx);
714 static void gc_disconnect(void *data, OSyncPluginInfo *info, OSyncContext *ctx)
716 osync_trace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, data, info, ctx);
717 osync_context_report_success(ctx);
718 osync_trace(TRACE_EXIT, "%s", __func__);
721 static void gc_finalize(void *data)
723 osync_trace(TRACE_ENTRY, "%s(%p)", __func__, data);
724 struct gc_plgdata *plgdata = data;
726 free_plg(plgdata);
727 osync_trace(TRACE_EXIT, "%s", __func__);
730 static void *gc_initialize(OSyncPlugin *plugin,
731 OSyncPluginInfo *info,
732 OSyncError **error)
734 osync_trace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, plugin, info, error);
735 struct gc_plgdata *plgdata;
736 OSyncPluginConfig *config;
737 OSyncPluginAuthentication *auth;
738 OSyncPluginAdvancedOption *advanced;
739 OSyncList *resources;
740 OSyncList *r;
741 const char *objtype, *tmp;
742 int i, numobjs;
744 plgdata = osync_try_malloc0(sizeof(struct gc_plgdata), error);
745 config = osync_plugin_info_get_config(info);
746 if ((!plgdata) || (!config)) {
747 osync_error_set(error, OSYNC_ERROR_GENERIC,
748 "Unable to get config data.");
749 goto error_freeplg;
752 advanced = osync_plugin_config_get_advancedoption_value_by_name(config, "xslt");
753 if (!advanced) {
754 osync_trace(TRACE_INTERNAL, "Cannot locate xslt config!\n");
755 goto error_freeplg;
758 if (!(plgdata->xslt_path = strdup(osync_plugin_advancedoption_get_value(advanced))))
759 goto error_freeplg;
761 resources = osync_plugin_config_get_resources(config);
762 numobjs = osync_plugin_info_num_objtypes(info);
764 for (i = 1, r = resources; r; r = r->next, i++) {
765 osync_trace(TRACE_INTERNAL, "field: %s\n", osync_plugin_resource_get_objtype(r->data));
766 if (!(strcmp(osync_plugin_resource_get_objtype(r->data), "event")))
767 if (!(plgdata->calendar = gcal_new(GCALENDAR)))
768 goto error_freeplg;
769 else {
770 osync_trace(TRACE_INTERNAL, "\tcreated calendar obj!\n");
771 gcal_set_store_xml(plgdata->calendar, 1);
774 if (!(strcmp(osync_plugin_resource_get_objtype(r->data), "contact")))
775 if (!(plgdata->contacts = gcal_new(GCONTACT)))
776 goto error_freeplg;
777 else {
778 osync_trace(TRACE_INTERNAL, "\tcreated contact obj!\n");
779 gcal_set_store_xml(plgdata->contacts, 1);
785 /* TODO: how works resource policy? For while, copy everything... */
786 for (i = 0; i < numobjs; i++) {
788 if (!plgdata->username) {
789 auth = osync_plugin_config_get_authentication(config);
790 tmp = osync_plugin_authentication_get_username(auth);
791 if (!tmp)
792 goto error_freeplg;
793 else
794 if (!(plgdata->username = strdup(tmp)))
795 goto error_freeplg;
799 if (!plgdata->password) {
800 tmp = osync_plugin_authentication_get_password(auth);
801 if (!tmp)
802 goto error_freeplg;
803 else
804 if (!(plgdata->password = strdup(tmp)))
805 goto error_freeplg;
808 /* TODO: get proxy/calendar title/resources/etc */
812 OSyncObjTypeSinkFunctions functions_gcal;
813 memset(&functions_gcal, 0, sizeof(functions_gcal));
814 functions_gcal.connect = gc_connect;
815 functions_gcal.get_changes = gc_get_changes_calendar;
816 functions_gcal.commit = gc_commit_change_calendar;
817 functions_gcal.disconnect = gc_disconnect;
818 functions_gcal.sync_done = gc_sync_done;
821 if (plgdata->calendar) {
822 osync_trace(TRACE_INTERNAL, "\tcreating calendar sink...\n");
823 OSyncFormatEnv *formatenv1 = osync_plugin_info_get_format_env(info);
824 plgdata->gcal_format = osync_format_env_find_objformat(formatenv1, "xmlformat-event");
825 if (!plgdata->gcal_format)
826 goto error_freeplg;
827 osync_objformat_ref(plgdata->gcal_format);
829 plgdata->gcal_sink = osync_plugin_info_find_objtype(info, "event");
830 if (!plgdata->gcal_sink)
831 goto error_freeplg;
833 osync_objtype_sink_set_functions(plgdata->gcal_sink, functions_gcal, plgdata);
834 osync_plugin_info_add_objtype(info, plgdata->gcal_sink);
838 OSyncObjTypeSinkFunctions functions_gcont;
839 memset(&functions_gcont, 0, sizeof(functions_gcont));
840 functions_gcont.connect = gc_connect;
841 functions_gcont.get_changes = gc_get_changes_contact;
842 functions_gcont.commit = gc_commit_change_contact;
843 functions_gcont.disconnect = gc_disconnect;
844 functions_gcont.sync_done = gc_sync_done;
846 if (plgdata->contacts) {
847 osync_trace(TRACE_INTERNAL, "\tcreating contact sink...\n");
848 OSyncFormatEnv *formatenv2 = osync_plugin_info_get_format_env(info);
849 plgdata->gcont_format = osync_format_env_find_objformat(formatenv2, "xmlformat-contact");
850 if (!plgdata->gcont_format)
851 goto error_freeplg;
852 osync_objformat_ref(plgdata->gcont_format);
854 plgdata->gcont_sink = osync_plugin_info_find_objtype(info, "contact");
855 if (!plgdata->gcont_sink)
856 goto error_freeplg;
858 osync_objtype_sink_set_functions(plgdata->gcont_sink, functions_gcont, plgdata);
859 osync_plugin_info_add_objtype(info, plgdata->gcont_sink);
864 plgdata->gcal_anchor_path = g_strdup_printf("%s/calendar_anchor.db",
865 osync_plugin_info_get_configdir(info));
866 if (!(plgdata->gcal_anchor_path))
867 goto error_freeplg;
868 else
869 osync_trace(TRACE_INTERNAL, "\tanchor: %s\n", plgdata->gcal_anchor_path);
871 plgdata->gcont_anchor_path = g_strdup_printf("%s/contact_anchor.db",
872 osync_plugin_info_get_configdir(info));
873 if (!(plgdata->gcont_anchor_path))
874 goto error_freeplg;
875 else
876 osync_trace(TRACE_INTERNAL, "\tanchor: %s\n", plgdata->gcont_anchor_path);
878 if (plgdata->calendar)
879 if (!(plgdata->xslt_ctx_gcal = xslt_new()))
880 goto error_freeplg;
881 else
882 osync_trace(TRACE_INTERNAL, "\tsucceed creating xslt_gcal!\n");
884 if (plgdata->contacts)
885 if (!(plgdata->xslt_ctx_gcont = xslt_new()))
886 goto error_freeplg;
887 else
888 osync_trace(TRACE_INTERNAL, "\tsucceed creating xslt_gcont!\n");
890 osync_trace(TRACE_EXIT, "%s", __func__);
892 return plgdata;
894 error_freeplg:
895 if (plgdata)
896 free_plg(plgdata);
897 out:
898 osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
899 return NULL;
902 static osync_bool gc_discover(void *data, OSyncPluginInfo *info, OSyncError **error)
904 osync_trace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, data, info, error);
906 struct gc_plgdata *plgdata = data;
908 if (plgdata->calendar)
909 osync_objtype_sink_set_available(plgdata->gcal_sink, TRUE);
910 if (plgdata->contacts)
911 osync_objtype_sink_set_available(plgdata->gcont_sink, TRUE);
913 OSyncVersion *version = osync_version_new(error);
914 osync_version_set_plugin(version, "google-data");
915 osync_plugin_info_set_version(info, version);
916 osync_version_unref(version);
918 osync_trace(TRACE_EXIT, "%s", __func__);
919 return TRUE;
922 osync_bool get_sync_info(OSyncPluginEnv *env, OSyncError **error)
924 osync_trace(TRACE_ENTRY, "%s(%p, %p)", __func__, env, error);
925 OSyncPlugin *plugin = osync_plugin_new(error);
926 if (!plugin)
927 goto error;
929 osync_plugin_set_name(plugin, "google-data");
930 osync_plugin_set_longname(plugin, "Google calendar/plugin");
931 osync_plugin_set_description(plugin, "Google calendar and contacts plugin");
933 osync_plugin_set_initialize(plugin, gc_initialize);
934 osync_plugin_set_finalize(plugin, gc_finalize);
935 osync_plugin_set_discover(plugin, gc_discover);
937 osync_plugin_env_register_plugin(env, plugin);
938 osync_plugin_unref(plugin);
940 osync_trace(TRACE_EXIT, "%s", __func__);
941 return TRUE;
943 error:
944 osync_trace(TRACE_EXIT_ERROR, "Unable to register: %s", osync_error_print(error));
945 osync_error_unref(error);
946 return FALSE;
949 int get_version(void)
951 return 1;