Fixing symbol name clash (I got to be more careful about my 'namespaces').
[gdataplugin.git] / src / gcalendar.c
blob1eda2c19dc0c2281d4134252bb35c3c38d4f621c
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 if (!timestamp1 || !timestamp2)
66 return 1;
68 /* From timestamp string to time structure */
69 strptime(timestamp1, format, &first);
70 strptime(timestamp2, format, &second);
72 /* From time structure to calendar time (since
73 * Epoch (00:00:00 UTC, January 1, 1970)
75 t_first = mktime(&first);
76 t_second = mktime(&second);
78 if (t_first == t_second)
79 result = 0;
80 else if (t_first > t_second)
81 result = 1;
82 else if (t_first < t_second)
83 result = -1;
85 return result;
89 struct gc_plgdata
91 char *url;
92 char *username;
93 char *password;
94 char *gcal_anchor_path;
95 char *gcont_anchor_path;
96 char *timezone;
97 char *xslt_path;
98 /* libgcal resources */
99 char *cal_timestamp;
100 char *cont_timestamp;
101 gcal_t calendar;
102 gcal_t contacts;
103 struct gcal_event_array all_events;
104 struct gcal_contact_array all_contacts;
105 /* calendar sink/format */
106 OSyncObjTypeSink *gcal_sink;
107 OSyncObjFormat *gcal_format;
108 /* contact sink/format */
109 OSyncObjTypeSink *gcont_sink;
110 OSyncObjFormat *gcont_format;
111 /* XSLT context resource struct */
112 struct xslt_resources *xslt_ctx_gcal;
113 struct xslt_resources *xslt_ctx_gcont;
116 static void free_plg(struct gc_plgdata *plgdata)
118 if (plgdata->calendar) {
119 gcal_delete(plgdata->calendar);
120 gcal_cleanup_events(&(plgdata->all_events));
122 if (plgdata->contacts) {
123 gcal_delete(plgdata->contacts);
124 gcal_cleanup_contacts(&(plgdata->all_contacts));
127 if (plgdata->gcal_anchor_path)
128 g_free(plgdata->gcal_anchor_path);
129 if (plgdata->gcont_anchor_path)
130 g_free(plgdata->gcont_anchor_path);
131 if (plgdata->xslt_path)
132 free(plgdata->xslt_path);
133 if (plgdata->xslt_ctx_gcal)
134 xslt_delete(plgdata->xslt_ctx_gcal);
135 if (plgdata->xslt_ctx_gcont)
136 xslt_delete(plgdata->xslt_ctx_gcont);
137 if (plgdata->cal_timestamp)
138 free(plgdata->cal_timestamp);
139 if (plgdata->cont_timestamp)
140 free(plgdata->cont_timestamp);
141 if (plgdata->timezone)
142 free(plgdata->timezone);
143 if (plgdata->url)
144 xmlFree(plgdata->url);
145 if (plgdata->username)
146 xmlFree(plgdata->username);
147 if (plgdata->password)
148 xmlFree(plgdata->password);
149 if (plgdata->gcal_sink)
150 osync_objtype_sink_unref(plgdata->gcal_sink);
151 if (plgdata->gcal_format)
152 osync_objformat_unref(plgdata->gcal_format);
153 g_free(plgdata);
156 static void gc_connect(void *data, OSyncPluginInfo *info, OSyncContext *ctx)
158 osync_trace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, data, info, ctx);
159 static int counter = 0;
160 int result;
161 struct gc_plgdata *plgdata = data;
162 OSyncObjTypeSink *sink = osync_plugin_info_get_sink(info);
163 OSyncError *error = NULL;
164 char buffer[512];
166 if ((plgdata->calendar) && (counter == 0)) {
167 result = gcal_get_authentication(plgdata->calendar, plgdata->username,
168 plgdata->password);
169 ++counter;
170 if (result == -1)
171 goto error;
173 snprintf(buffer, sizeof(buffer) - 1, "%s/gcal2osync.xslt",
174 plgdata->xslt_path);
175 if ((result = xslt_initialize(plgdata->xslt_ctx_gcal, buffer)))
176 goto error;
177 osync_trace(TRACE_INTERNAL, "\ndone calendar: %s\n", buffer);
180 if (((plgdata->contacts) && (counter == 1)) ||
181 ((plgdata->gcont_sink) && (!plgdata->gcal_sink))) {
182 result = gcal_get_authentication(plgdata->contacts, plgdata->username,
183 plgdata->password);
184 counter++;
185 if (result == -1)
186 goto error;
188 snprintf(buffer, sizeof(buffer) - 1, "%s/gcont2osync.xslt",
189 plgdata->xslt_path);
190 if ((result = xslt_initialize(plgdata->xslt_ctx_gcont, buffer)))
191 goto error;
192 osync_trace(TRACE_INTERNAL, "\ndone contact: %s\n", buffer);
195 osync_context_report_success(ctx);
196 osync_trace(TRACE_EXIT, "%s", __func__);
197 return;
199 error:
200 osync_trace(TRACE_INTERNAL, "\nGood bye, cruel world...\n");
201 osync_context_report_osyncerror(ctx, &error);
204 static void gc_get_changes_calendar(void *data, OSyncPluginInfo *info, OSyncContext *ctx)
206 osync_trace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, data, info, ctx);
207 char buffer[512];
208 static int counter = 0;
209 struct gc_plgdata *plgdata = data;
210 char slow_sync_flag = 0;
211 OSyncObjTypeSink *sink = osync_plugin_info_get_sink(info);
212 OSyncError *error = NULL;
213 OSyncXMLFormat *xmlformat;
214 OSyncData *odata = NULL;
215 OSyncChange *chg = NULL;
216 int result = 0, i;
217 char *timestamp = NULL, *msg, *raw_xml = NULL;
218 gcal_event event;
220 if (!plgdata->gcal_sink)
221 return;
222 timestamp = osync_anchor_retrieve(plgdata->gcal_anchor_path, "gcalendar");
223 if (timestamp)
224 osync_trace(TRACE_INTERNAL, "timestamp is: %s\n", timestamp);
225 else
226 osync_trace(TRACE_INTERNAL, "first sync!\n");
228 if (osync_objtype_sink_get_slowsync(plgdata->gcal_sink)) {
229 osync_trace(TRACE_INTERNAL, "\n\t\tgcal: Client asked for slow syncing...\n");
230 slow_sync_flag = 1;
231 result = gcal_get_events(plgdata->calendar, &(plgdata->all_events));
233 } else {
234 osync_trace(TRACE_INTERNAL, "\n\t\tgcal: Client asked for fast syncing...\n");
235 result = gcal_get_updated_events(plgdata->calendar,
236 &(plgdata->all_events),
237 timestamp);
240 if (result) {
241 msg = "Failed getting events!";
242 goto error;
245 osync_trace(TRACE_INTERNAL, "gcalendar: got then all!\n");
246 if (plgdata->all_events.length == 0) {
247 osync_trace(TRACE_INTERNAL, "gcalendar: no changes...\n");
248 goto no_changes;
249 } else
250 osync_trace(TRACE_INTERNAL, "gcalendar: changes count: %d\n",
251 plgdata->all_events.length);
254 /* Calendar returns most recently updated event as first element */
255 event = gcal_event_element(&(plgdata->all_events), 0);
256 if (!event) {
257 msg = "Cannot access last updated event!\n";
258 goto error;
260 plgdata->cont_timestamp = strdup(gcal_event_get_updated(event));
261 if (!plgdata->cont_timestamp) {
262 msg = "Failed copying event timestamp!\n";
263 goto error;
266 for (i = 0; i < plgdata->all_events.length; ++i) {
267 event = gcal_event_element(&(plgdata->all_events), i);
268 if (!event)
269 goto error;
271 osync_trace(TRACE_INTERNAL, "gevent: timestamp:%s\tevent:%s\n",
272 timestamp, gcal_event_get_updated(event));
273 /* Workaround for inclusive returned results */
274 if ((timestamp_cmp(timestamp, gcal_event_get_updated(event)) == 0)
275 && !slow_sync_flag
276 && !gcal_event_is_deleted(event)) {
277 osync_trace(TRACE_INTERNAL, "gevent: old event.");
278 continue;
279 } else
280 osync_trace(TRACE_INTERNAL, "gevent: new or deleted event!");
282 raw_xml = gcal_event_get_xml(event);
283 if ((result = xslt_transform(plgdata->xslt_ctx_gcal,
284 raw_xml)))
285 goto error;
287 raw_xml = plgdata->xslt_ctx_gcal->xml_str;
288 xmlformat = osync_xmlformat_parse(raw_xml,
289 strlen(raw_xml),
290 &error);
291 if (!xmlformat)
292 goto error;
294 osync_trace(TRACE_INTERNAL, "gevent: %s\nosync: %s\n",
295 gcal_event_get_xml(event), raw_xml);
297 osync_xmlformat_sort(xmlformat);
298 odata = osync_data_new(xmlformat,
299 osync_xmlformat_size(),
300 plgdata->gcal_format, &error);
301 if (!odata)
302 goto cleanup;
304 if (!(chg = osync_change_new(&error)))
305 goto cleanup;
306 osync_data_set_objtype(odata, osync_objtype_sink_get_name(plgdata->gcal_sink));
307 osync_change_set_data(chg, odata);
308 osync_data_unref(odata);
310 osync_change_set_uid(chg, gcal_event_get_url(event));
312 if (slow_sync_flag)
313 osync_change_set_changetype(chg, OSYNC_CHANGE_TYPE_ADDED);
314 else
315 if (gcal_event_is_deleted(event)) {
316 osync_change_set_changetype(chg, OSYNC_CHANGE_TYPE_DELETED);
317 osync_trace(TRACE_INTERNAL, "deleted entry!");
319 else
320 osync_change_set_changetype(chg, OSYNC_CHANGE_TYPE_MODIFIED);
322 osync_context_report_change(ctx, chg);
323 osync_change_unref(chg);
326 no_changes:
328 /* Load XSLT style to convert osync xmlformat-event --> gdata */
329 snprintf(buffer, sizeof(buffer) - 1, "%s/osync2gcal.xslt",
330 plgdata->xslt_path);
331 if ((result = xslt_initialize(plgdata->xslt_ctx_gcal, buffer))) {
332 msg = "Cannot initialize new XSLT!\n";
333 goto error;
336 osync_trace(TRACE_INTERNAL, "\ndone calendar: %s\n", buffer);
338 exit:
339 osync_context_report_success(ctx);
340 return;
342 cleanup:
343 osync_error_unref(&error);
344 osync_xmlformat_unref(&xmlformat);
346 error:
347 osync_context_report_error(ctx, OSYNC_ERROR_GENERIC, msg);
352 static void gc_get_changes_contact(void *data, OSyncPluginInfo *info, OSyncContext *ctx)
354 osync_trace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, data, info, ctx);
355 char buffer[512];
356 static int counter = 0;
357 struct gc_plgdata *plgdata = data;
358 char slow_sync_flag = 0;
359 OSyncObjTypeSink *sink = osync_plugin_info_get_sink(info);
360 OSyncError *error = NULL;
361 OSyncXMLFormat *xmlformat;
362 OSyncData *odata = NULL;
363 OSyncChange *chg = NULL;
364 int result = 0, i;
365 char *timestamp = NULL, *msg, *raw_xml = NULL;
366 gcal_contact contact;
367 slow_sync_flag = 0;
369 if (!plgdata->gcont_sink)
370 return;
371 timestamp = osync_anchor_retrieve(plgdata->gcont_anchor_path, "gcontact");
372 if (timestamp)
373 osync_trace(TRACE_INTERNAL, "timestamp is: %s\n", timestamp);
374 else
375 osync_trace(TRACE_INTERNAL, "first sync!\n");
377 if (osync_objtype_sink_get_slowsync(plgdata->gcont_sink)) {
378 osync_trace(TRACE_INTERNAL, "\n\t\tgcont: Client asked for slow syncing...\n");
379 slow_sync_flag = 1;
380 result = gcal_get_contacts(plgdata->contacts, &(plgdata->all_contacts));
382 } else {
383 osync_trace(TRACE_INTERNAL, "\n\t\tgcont: Client asked for fast syncing...\n");
384 gcal_deleted(plgdata->contacts, SHOW);
385 result = gcal_get_updated_contacts(plgdata->contacts,
386 &(plgdata->all_contacts),
387 timestamp);
390 if (result) {
391 msg = "Failed getting contacts!";
392 goto error;
395 osync_trace(TRACE_INTERNAL, "gcontact: got then all!\n");
396 if (plgdata->all_contacts.length == 0) {
397 osync_trace(TRACE_INTERNAL, "gcontact: no changes...\n");
398 goto no_changes;
399 } else
400 osync_trace(TRACE_INTERNAL, "gcontact: changes count: %d\n",
401 plgdata->all_contacts.length);
403 /* Contacts returns most recently updated entry as last element */
404 contact = gcal_contact_element(&(plgdata->all_contacts),
405 (plgdata->all_contacts.length - 1));
406 if (!contact) {
407 msg = "Cannot access last updated contact!\n";
408 goto error;
410 plgdata->cont_timestamp = strdup(gcal_contact_get_updated(contact));
411 if (!plgdata->cont_timestamp) {
412 msg = "Failed copying contact timestamp!\n";
413 goto error;
416 for (i = 0; i < plgdata->all_contacts.length; ++i) {
417 contact = gcal_contact_element(&(plgdata->all_contacts), i);
418 if (!contact)
419 goto error;
421 osync_trace(TRACE_INTERNAL, "gcontact: timestamp:%s\tcontact:%s\n",
422 timestamp, gcal_contact_get_updated(contact));
423 /* Workaround for inclusive returned results */
424 if ((timestamp_cmp(timestamp, gcal_contact_get_updated(contact)) == 0)
425 && !slow_sync_flag
426 && !gcal_contact_is_deleted(contact)) {
427 osync_trace(TRACE_INTERNAL, "gcontact: old contact.");
428 continue;
429 } else
430 osync_trace(TRACE_INTERNAL, "gcontact: new or deleted contact!");
432 raw_xml = gcal_contact_get_xml(contact);
433 if ((result = xslt_transform(plgdata->xslt_ctx_gcont,
434 raw_xml)))
435 goto error;
436 raw_xml = plgdata->xslt_ctx_gcont->xml_str;
437 xmlformat = osync_xmlformat_parse(raw_xml,
438 strlen(raw_xml),
439 &error);
440 if (!xmlformat)
441 goto error;
443 osync_trace(TRACE_INTERNAL, "gcont: %s\nosync: %s\n",
444 gcal_contact_get_xml(contact), raw_xml);
446 osync_xmlformat_sort(xmlformat);
448 odata = osync_data_new(xmlformat,
449 osync_xmlformat_size(),
450 plgdata->gcont_format, &error);
452 if (!odata)
453 goto cleanup;
455 if (!(chg = osync_change_new(&error)))
456 goto cleanup;
457 osync_data_set_objtype(odata, osync_objtype_sink_get_name(plgdata->gcont_sink));
458 osync_change_set_data(chg, odata);
459 osync_data_unref(odata);
461 osync_change_set_uid(chg, gcal_contact_get_url(contact));
463 if (slow_sync_flag)
464 osync_change_set_changetype(chg, OSYNC_CHANGE_TYPE_ADDED);
465 else
466 if (gcal_contact_is_deleted(contact)) {
467 osync_change_set_changetype(chg, OSYNC_CHANGE_TYPE_DELETED);
468 osync_trace(TRACE_INTERNAL, "deleted entry!");
470 else
471 osync_change_set_changetype(chg, OSYNC_CHANGE_TYPE_MODIFIED);
473 osync_context_report_change(ctx, chg);
474 osync_change_unref(chg);
477 no_changes:
479 /* Load XSLT style to convert osync xmlformat-contact --> gdata */
480 snprintf(buffer, sizeof(buffer) - 1, "%s/osync2gcont.xslt",
481 plgdata->xslt_path);
482 if ((result = xslt_initialize(plgdata->xslt_ctx_gcont, buffer))) {
483 msg = "Cannot initialize new XSLT!\n";
484 goto error;
487 osync_trace(TRACE_INTERNAL, "\ndone contact: %s\n", buffer);
489 exit:
490 osync_context_report_success(ctx);
491 return;
493 cleanup:
494 osync_error_unref(&error);
495 osync_xmlformat_unref(&xmlformat);
497 error:
498 osync_context_report_error(ctx, OSYNC_ERROR_GENERIC, msg);
501 static void gc_commit_change_calendar(void *data, OSyncPluginInfo *info,
502 OSyncContext *ctx, OSyncChange *change)
504 osync_trace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, data, info, ctx, change);
505 osync_trace(TRACE_INTERNAL, "hello, from calendar!\n");
506 OSyncObjTypeSink *sink = osync_plugin_info_get_sink(info);
507 struct gc_plgdata *plgdata = data;
508 gcal_event event = NULL;
510 int size, result;
511 char *osync_xml = NULL, *msg = NULL, *raw_xml = NULL, *updated_event = NULL;
512 OSyncData *odata = NULL;
514 if (!(odata = osync_change_get_data(change))) {
515 msg = "Cannot get raw data from change obj!\n";
516 goto error;
519 osync_data_get_data(odata, &osync_xml, &size);
520 if (!osync_xml) {
521 msg = "Failed getting xml from change obj!\n";
522 goto error;
525 /* Convert to gdata format */
526 if ((result = xslt_transform(plgdata->xslt_ctx_gcal, osync_xml))) {
527 msg = "Failed converting from osync xmlevent to gcalendar\n";
528 goto error;
530 raw_xml = plgdata->xslt_ctx_gcal->xml_str;
532 osync_trace(TRACE_EXIT, "osync: %s\ngcont: %s\n\n", osync_xml, raw_xml);
534 switch (osync_change_get_changetype(change)) {
535 case OSYNC_CHANGE_TYPE_ADDED:
536 result = gcal_add_xmlentry(plgdata->calendar, raw_xml, &updated_event);
537 if (result == -1) {
538 msg = "Failed adding new event!\n";
539 result = gcal_status_httpcode(plgdata->calendar);
540 goto error;
543 if (!(event = gcal_event_new(updated_event))) {
544 msg = "Failed recovering updated fields!\n";
545 goto error;
547 break;
549 case OSYNC_CHANGE_TYPE_MODIFIED:
550 result = gcal_update_xmlentry(plgdata->calendar, raw_xml, &updated_event,
551 NULL);
552 if (result == -1) {
553 msg = "Failed editing event!\n";
554 goto error;
557 if (!(event = gcal_event_new(updated_event))) {
558 msg = "Failed recovering updated fields!\n";
559 goto error;
561 break;
563 case OSYNC_CHANGE_TYPE_DELETED:
564 result = gcal_erase_xmlentry(plgdata->calendar, raw_xml);
565 if (result == -1) {
566 msg = "Failed deleting event!\n";
567 goto error;
569 break;
571 default:
572 osync_context_report_error(ctx, OSYNC_ERROR_NOT_SUPPORTED,
573 "Unknown change type");
574 goto error;
575 break;
578 if (updated_event)
579 free(updated_event);
581 if (event) {
582 /* update the timestamp */
583 if (plgdata->cal_timestamp)
584 free(plgdata->cal_timestamp);
585 plgdata->cal_timestamp = strdup(gcal_event_get_updated(event));
586 if (!plgdata->cal_timestamp) {
587 msg = "Failed copying contact timestamp!\n";
588 goto error;
591 /* FIXME: not sure if this works */
592 /* Inform the new ID */
593 osync_change_set_uid(change, gcal_event_get_url(event));
594 gcal_event_delete(event);
598 osync_context_report_success(ctx);
600 osync_trace(TRACE_EXIT, "%s", __func__);
602 return;
603 error:
604 osync_context_report_error(ctx, OSYNC_ERROR_GENERIC, msg);
605 osync_trace(TRACE_EXIT, "%s:%sHTTP code: %d", __func__, msg, result);
608 static void gc_commit_change_contact(void *data, OSyncPluginInfo *info,
609 OSyncContext *ctx, OSyncChange *change)
611 osync_trace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, data, info, ctx, change);
612 osync_trace(TRACE_INTERNAL, "hello, from contacts!\n");
614 OSyncObjTypeSink *sink = osync_plugin_info_get_sink(info);
615 struct gc_plgdata *plgdata = data;
616 gcal_contact contact = NULL;
617 int size, result;
618 char *osync_xml = NULL, *msg = NULL, *raw_xml = NULL, *updated_contact = NULL;
619 OSyncData *odata = NULL;
621 if (!(odata = osync_change_get_data(change))) {
622 msg = "Cannot get raw data from change obj!\n";
623 goto error;
626 osync_data_get_data(odata, &osync_xml, &size);
627 if (!osync_xml) {
628 msg = "Failed getting xml from change obj!\n";
629 goto error;
632 /* Convert to gdata format */
633 if ((result = xslt_transform(plgdata->xslt_ctx_gcont, osync_xml))) {
634 msg = "Failed converting from osync xmlcontact to gcontact\n";
635 goto error;
637 raw_xml = plgdata->xslt_ctx_gcont->xml_str;
639 osync_trace(TRACE_INTERNAL, "osync: %s\ngcont: %s\n\n", osync_xml, raw_xml);
641 switch (osync_change_get_changetype(change)) {
642 case OSYNC_CHANGE_TYPE_ADDED:
643 result = gcal_add_xmlentry(plgdata->contacts, raw_xml, &updated_contact);
644 if (result == -1) {
645 msg = "Failed adding new contact!\n";
646 result = gcal_status_httpcode(plgdata->contacts);
647 goto error;
650 if (!(contact = gcal_contact_new(updated_contact))) {
651 msg = "Failed recovering updated fields!\n";
652 goto error;
654 break;
656 case OSYNC_CHANGE_TYPE_MODIFIED:
657 result = gcal_update_xmlentry(plgdata->contacts, raw_xml, &updated_contact,
658 NULL);
659 if (result == -1) {
660 msg = "Failed editing contact!\n";
661 goto error;
664 if (!(contact = gcal_contact_new(updated_contact))) {
665 msg = "Failed recovering updated fields!\n";
666 goto error;
668 break;
670 case OSYNC_CHANGE_TYPE_DELETED:
671 result = gcal_erase_xmlentry(plgdata->contacts, raw_xml);
672 if (result == -1) {
673 msg = "Failed deleting contact!\n";
674 goto error;
676 break;
678 default:
679 osync_context_report_error(ctx, OSYNC_ERROR_NOT_SUPPORTED,
680 "Unknown change type");
681 goto error;
682 break;
685 if (updated_contact)
686 free(updated_contact);
688 if (contact) {
689 /* update the timestamp */
690 if (plgdata->cont_timestamp)
691 free(plgdata->cont_timestamp);
692 plgdata->cont_timestamp = strdup(gcal_contact_get_updated(contact));
693 if (!plgdata->cont_timestamp) {
694 msg = "Failed copying contact timestamp!\n";
695 goto error;
698 /* FIXME: not sure if this works */
699 /* Inform the new ID */
700 osync_change_set_uid(change, gcal_contact_get_url(contact));
701 gcal_contact_delete(contact);
704 osync_context_report_success(ctx);
705 osync_trace(TRACE_EXIT, "%s", __func__);
706 return;
708 error:
709 osync_context_report_error(ctx, OSYNC_ERROR_GENERIC, msg);
710 osync_trace(TRACE_EXIT, "%s:%sHTTP code: %d", __func__, msg, result);
713 static void gc_sync_done(void *data, OSyncPluginInfo *info, OSyncContext *ctx)
715 osync_trace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, data, info, ctx);
716 struct gc_plgdata *plgdata = data;
717 OSyncObjTypeSink *sink = osync_plugin_info_get_sink(info);
719 if (plgdata->calendar && plgdata->cal_timestamp) {
720 osync_trace(TRACE_INTERNAL, "query updated timestamp: %s\n",
721 plgdata->cal_timestamp);
722 osync_anchor_update(plgdata->gcal_anchor_path, "gcalendar",
723 plgdata->cal_timestamp);
726 if (plgdata->contacts && plgdata->cont_timestamp) {
727 osync_trace(TRACE_INTERNAL, "query updated timestamp: %s\n",
728 plgdata->cont_timestamp);
729 osync_anchor_update(plgdata->gcont_anchor_path, "gcontact",
730 plgdata->cont_timestamp);
733 osync_context_report_success(ctx);
736 static void gc_disconnect(void *data, OSyncPluginInfo *info, OSyncContext *ctx)
738 osync_trace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, data, info, ctx);
739 osync_context_report_success(ctx);
740 osync_trace(TRACE_EXIT, "%s", __func__);
743 static void gc_finalize(void *data)
745 osync_trace(TRACE_ENTRY, "%s(%p)", __func__, data);
746 struct gc_plgdata *plgdata = data;
748 free_plg(plgdata);
749 osync_trace(TRACE_EXIT, "%s", __func__);
752 static void *gc_initialize(OSyncPlugin *plugin,
753 OSyncPluginInfo *info,
754 OSyncError **error)
756 osync_trace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, plugin, info, error);
757 struct gc_plgdata *plgdata;
758 OSyncPluginConfig *config;
759 OSyncPluginAuthentication *auth;
760 OSyncPluginAdvancedOption *advanced;
761 OSyncList *resources;
762 OSyncList *r;
763 const char *objtype, *tmp;
764 int i, numobjs;
766 plgdata = osync_try_malloc0(sizeof(struct gc_plgdata), error);
767 config = osync_plugin_info_get_config(info);
768 if ((!plgdata) || (!config)) {
769 osync_error_set(error, OSYNC_ERROR_GENERIC,
770 "Unable to get config data.");
771 goto error_freeplg;
774 advanced = osync_plugin_config_get_advancedoption_value_by_name(config, "xslt");
775 if (!advanced) {
776 osync_trace(TRACE_INTERNAL, "Cannot locate xslt config!\n");
777 goto error_freeplg;
780 if (!(plgdata->xslt_path = strdup(osync_plugin_advancedoption_get_value(advanced))))
781 goto error_freeplg;
783 resources = osync_plugin_config_get_resources(config);
784 numobjs = osync_plugin_info_num_objtypes(info);
786 for (i = 1, r = resources; r; r = r->next, i++) {
787 osync_trace(TRACE_INTERNAL, "field: %s\n", osync_plugin_resource_get_objtype(r->data));
788 if (!(strcmp(osync_plugin_resource_get_objtype(r->data), "event")))
789 if (!(plgdata->calendar = gcal_new(GCALENDAR)))
790 goto error_freeplg;
791 else {
792 osync_trace(TRACE_INTERNAL, "\tcreated calendar obj!\n");
793 gcal_set_store_xml(plgdata->calendar, 1);
796 if (!(strcmp(osync_plugin_resource_get_objtype(r->data), "contact")))
797 if (!(plgdata->contacts = gcal_new(GCONTACT)))
798 goto error_freeplg;
799 else {
800 osync_trace(TRACE_INTERNAL, "\tcreated contact obj!\n");
801 gcal_set_store_xml(plgdata->contacts, 1);
807 /* TODO: how works resource policy? For while, copy everything... */
808 for (i = 0; i < numobjs; i++) {
810 if (!plgdata->username) {
811 auth = osync_plugin_config_get_authentication(config);
812 tmp = osync_plugin_authentication_get_username(auth);
813 if (!tmp)
814 goto error_freeplg;
815 else
816 if (!(plgdata->username = strdup(tmp)))
817 goto error_freeplg;
821 if (!plgdata->password) {
822 tmp = osync_plugin_authentication_get_password(auth);
823 if (!tmp)
824 goto error_freeplg;
825 else
826 if (!(plgdata->password = strdup(tmp)))
827 goto error_freeplg;
830 /* TODO: get proxy/calendar title/resources/etc */
834 OSyncObjTypeSinkFunctions functions_gcal;
835 memset(&functions_gcal, 0, sizeof(functions_gcal));
836 functions_gcal.connect = gc_connect;
837 functions_gcal.get_changes = gc_get_changes_calendar;
838 functions_gcal.commit = gc_commit_change_calendar;
839 functions_gcal.disconnect = gc_disconnect;
840 functions_gcal.sync_done = gc_sync_done;
843 if (plgdata->calendar) {
844 osync_trace(TRACE_INTERNAL, "\tcreating calendar sink...\n");
845 OSyncFormatEnv *formatenv1 = osync_plugin_info_get_format_env(info);
846 plgdata->gcal_format = osync_format_env_find_objformat(formatenv1, "xmlformat-event");
847 if (!plgdata->gcal_format)
848 goto error_freeplg;
849 osync_objformat_ref(plgdata->gcal_format);
851 plgdata->gcal_sink = osync_plugin_info_find_objtype(info, "event");
852 if (!plgdata->gcal_sink)
853 goto error_freeplg;
855 osync_objtype_sink_set_functions(plgdata->gcal_sink, functions_gcal, plgdata);
856 osync_plugin_info_add_objtype(info, plgdata->gcal_sink);
860 OSyncObjTypeSinkFunctions functions_gcont;
861 memset(&functions_gcont, 0, sizeof(functions_gcont));
862 functions_gcont.connect = gc_connect;
863 functions_gcont.get_changes = gc_get_changes_contact;
864 functions_gcont.commit = gc_commit_change_contact;
865 functions_gcont.disconnect = gc_disconnect;
866 functions_gcont.sync_done = gc_sync_done;
868 if (plgdata->contacts) {
869 osync_trace(TRACE_INTERNAL, "\tcreating contact sink...\n");
870 OSyncFormatEnv *formatenv2 = osync_plugin_info_get_format_env(info);
871 plgdata->gcont_format = osync_format_env_find_objformat(formatenv2, "xmlformat-contact");
872 if (!plgdata->gcont_format)
873 goto error_freeplg;
874 osync_objformat_ref(plgdata->gcont_format);
876 plgdata->gcont_sink = osync_plugin_info_find_objtype(info, "contact");
877 if (!plgdata->gcont_sink)
878 goto error_freeplg;
880 osync_objtype_sink_set_functions(plgdata->gcont_sink, functions_gcont, plgdata);
881 osync_plugin_info_add_objtype(info, plgdata->gcont_sink);
886 plgdata->gcal_anchor_path = g_strdup_printf("%s/calendar_anchor.db",
887 osync_plugin_info_get_configdir(info));
888 if (!(plgdata->gcal_anchor_path))
889 goto error_freeplg;
890 else
891 osync_trace(TRACE_INTERNAL, "\tanchor: %s\n", plgdata->gcal_anchor_path);
893 plgdata->gcont_anchor_path = g_strdup_printf("%s/contact_anchor.db",
894 osync_plugin_info_get_configdir(info));
895 if (!(plgdata->gcont_anchor_path))
896 goto error_freeplg;
897 else
898 osync_trace(TRACE_INTERNAL, "\tanchor: %s\n", plgdata->gcont_anchor_path);
900 if (plgdata->calendar)
901 if (!(plgdata->xslt_ctx_gcal = xslt_new()))
902 goto error_freeplg;
903 else
904 osync_trace(TRACE_INTERNAL, "\tsucceed creating xslt_gcal!\n");
906 if (plgdata->contacts)
907 if (!(plgdata->xslt_ctx_gcont = xslt_new()))
908 goto error_freeplg;
909 else
910 osync_trace(TRACE_INTERNAL, "\tsucceed creating xslt_gcont!\n");
912 osync_trace(TRACE_EXIT, "%s", __func__);
914 return plgdata;
916 error_freeplg:
917 if (plgdata)
918 free_plg(plgdata);
919 out:
920 osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
921 return NULL;
924 static osync_bool gc_discover(void *data, OSyncPluginInfo *info, OSyncError **error)
926 osync_trace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, data, info, error);
928 struct gc_plgdata *plgdata = data;
930 if (plgdata->calendar)
931 osync_objtype_sink_set_available(plgdata->gcal_sink, TRUE);
932 if (plgdata->contacts)
933 osync_objtype_sink_set_available(plgdata->gcont_sink, TRUE);
935 OSyncVersion *version = osync_version_new(error);
936 osync_version_set_plugin(version, "google-data");
937 osync_plugin_info_set_version(info, version);
938 osync_version_unref(version);
940 osync_trace(TRACE_EXIT, "%s", __func__);
941 return TRUE;
944 osync_bool get_sync_info(OSyncPluginEnv *env, OSyncError **error)
946 osync_trace(TRACE_ENTRY, "%s(%p, %p)", __func__, env, error);
947 OSyncPlugin *plugin = osync_plugin_new(error);
948 if (!plugin)
949 goto error;
951 osync_plugin_set_name(plugin, "google-data");
952 osync_plugin_set_longname(plugin, "Google calendar/plugin");
953 osync_plugin_set_description(plugin, "Google calendar and contacts plugin");
955 osync_plugin_set_initialize(plugin, gc_initialize);
956 osync_plugin_set_finalize(plugin, gc_finalize);
957 osync_plugin_set_discover(plugin, gc_discover);
959 osync_plugin_env_register_plugin(env, plugin);
960 osync_plugin_unref(plugin);
962 osync_trace(TRACE_EXIT, "%s", __func__);
963 return TRUE;
965 error:
966 osync_trace(TRACE_EXIT_ERROR, "Unable to register: %s", osync_error_print(error));
967 osync_error_unref(error);
968 return FALSE;
971 int get_version(void)
973 return 1;