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 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
24 * - remove all fprintf's and use osync_trace(TRACE_INTERNAL, ...) instead
25 * - getchanges: convert gdata XML to osync using 'xslt_transform'
26 * - getchanges: report all entries to opensync
27 * - getchanges: implement getupdated for fast sync
28 * - test if it works inside opensync (all tests for while are running with 'osyncplugin'
30 * - commitchanges: well... write the code
31 * - review code for leaks (I'm not sure if I'm using opensync API correctly...)
35 #include <opensync/opensync.h>
36 #include <opensync/opensync-plugin.h>
37 #include <opensync/opensync-helper.h>
38 #include <opensync/opensync-merger.h>
39 #include <opensync/opensync-format.h>
40 #include <opensync/opensync-data.h>
41 #include <opensync/opensync-version.h>
45 #include <libxml/tree.h>
50 #include <sys/types.h>
53 #include <gcal_status.h>
54 #include <gcalendar.h>
67 /* libgcal resources */
70 struct gcal_event_array all_events
;
71 struct gcal_contact_array all_contacts
;
72 /* calendar sink/format */
73 OSyncObjTypeSink
*gcal_sink
;
74 OSyncObjFormat
*gcal_format
;
75 /* contact sink/format */
76 OSyncObjTypeSink
*gcont_sink
;
77 OSyncObjFormat
*gcont_format
;
78 /* XSLT context resource struct */
79 struct xslt_resources
*xslt_ctx_gcal
;
80 struct xslt_resources
*xslt_ctx_gcont
;
83 static void free_plg(struct gc_plgdata
*plgdata
)
85 if (plgdata
->calendar
) {
86 gcal_delete(plgdata
->calendar
);
87 gcal_cleanup_events(&(plgdata
->all_events
));
89 if (plgdata
->contacts
) {
90 gcal_delete(plgdata
->contacts
);
91 gcal_cleanup_contacts(&(plgdata
->all_contacts
));
94 if (plgdata
->xslt_path
)
95 free(plgdata
->xslt_path
);
96 if (plgdata
->xslt_ctx_gcal
)
97 xslt_delete(plgdata
->xslt_ctx_gcal
);
98 if (plgdata
->xslt_ctx_gcont
)
99 xslt_delete(plgdata
->xslt_ctx_gcont
);
100 if (plgdata
->timestamp
)
101 free(plgdata
->timestamp
);
102 if (plgdata
->timezone
)
103 free(plgdata
->timezone
);
105 xmlFree(plgdata
->url
);
106 if (plgdata
->username
)
107 xmlFree(plgdata
->username
);
108 if (plgdata
->password
)
109 xmlFree(plgdata
->password
);
110 if (plgdata
->gcal_sink
)
111 osync_objtype_sink_unref(plgdata
->gcal_sink
);
112 if (plgdata
->gcal_format
)
113 osync_objformat_unref(plgdata
->gcal_format
);
114 if (plgdata
->gcont_sink
)
115 osync_objtype_sink_unref(plgdata
->gcont_sink
);
116 if (plgdata
->gcont_format
)
117 osync_objformat_unref(plgdata
->gcont_format
);
121 /** Run gchelper and return the file descriptors for its stdin/stdout
124 osync_bool
run_helper(struct gc_plgdata
*plgdata
, const char *operation
,
125 const char *arg
, int *in
, int *out
, pid_t
*ppid
,
129 osync_bool result
= FALSE
;
130 /* TODO: add calls to libgcal */
135 static void gc_connect(void *data
, OSyncPluginInfo
*info
, OSyncContext
*ctx
)
137 osync_trace(TRACE_ENTRY
, "%s(%p, %p, %p)", __func__
, data
, info
, ctx
);
138 static int counter
= 0;
140 struct gc_plgdata
*plgdata
= data
;
141 OSyncObjTypeSink
*sink
= osync_plugin_info_get_sink(info
);
142 OSyncError
*error
= NULL
;
145 if ((plgdata
->calendar
) && (counter
== 0)) {
146 result
= gcal_get_authentication(plgdata
->calendar
, plgdata
->username
,
152 snprintf(buffer
, sizeof(buffer
) - 1, "%s/gcal2osync.xslt",
154 if ((result
= xslt_initialize(plgdata
->xslt_ctx_gcal
, buffer
)))
156 fprintf(stderr
, "\ndone calendar: %s\n", buffer
);
159 if (((plgdata
->contacts
) && (counter
== 1)) ||
160 ((plgdata
->gcont_sink
) && (!plgdata
->gcal_sink
))) {
161 result
= gcal_get_authentication(plgdata
->contacts
, plgdata
->username
,
167 snprintf(buffer
, sizeof(buffer
) - 1, "%s/gcont2osync.xslt",
169 if ((result
= xslt_initialize(plgdata
->xslt_ctx_gcont
, buffer
)))
171 fprintf(stderr
, "\ndone contact: %s\n", buffer
);
174 osync_context_report_success(ctx
);
175 osync_trace(TRACE_EXIT
, "%s", __func__
);
179 fprintf(stderr
, "\nGood bye, cruel world...\n");
180 osync_context_report_osyncerror(ctx
, &error
);
183 static void gc_get_changes(void *data
, OSyncPluginInfo
*info
, OSyncContext
*ctx
)
185 osync_trace(TRACE_ENTRY
, "%s(%p, %p, %p)", __func__
, data
, info
, ctx
);
186 static int counter
= 0;
187 struct gc_plgdata
*plgdata
= data
;
188 OSyncObjTypeSink
*sink
= osync_plugin_info_get_sink(info
);
189 OSyncError
*error
= NULL
;
191 char *timestamp
= NULL
, *msg
;
193 timestamp
= osync_anchor_retrieve(plgdata
->anchor_path
, "gdata");
195 fprintf(stderr
, "timestamp is: %s\n", timestamp
);
197 fprintf(stderr
, "first sync!\n");
199 if ((plgdata
->gcal_sink
) && (counter
== 0)) {
200 if (osync_objtype_sink_get_slowsync(plgdata
->gcal_sink
)) {
201 fprintf(stderr
, "\n\t\tgcal: Client asked for slow syncing...\n");
202 result
= gcal_get_events(plgdata
->calendar
, &(plgdata
->all_events
));
204 msg
= "Failed getting events!";
207 /* TODO: report back events to opensync */
208 fprintf(stderr
, "\tgot then all!\n");
211 /* TODO: write getchanges */
212 fprintf(stderr
, "\n\t\tgcal: Its a fast sync!\n");
217 if (((plgdata
->gcont_sink
) && (counter
== 1)) ||
218 ((plgdata
->gcont_sink
) && (!plgdata
->gcal_sink
)))
219 if (osync_objtype_sink_get_slowsync(plgdata
->gcont_sink
)) {
220 fprintf(stderr
, "\n\t\tgcont: Client asked for slow syncing...\n");
221 result
= gcal_get_contacts(plgdata
->contacts
, &(plgdata
->all_contacts
));
223 msg
= "Failed getting contacts!";
227 fprintf(stderr
, "\tgot then all!\n");
229 /* TODO: report back contacts to opensync */
232 /* TODO: write getchanges */
233 fprintf(stderr
, "\n\t\tgcont: Its a fast sync!\n");
238 osync_context_report_success(ctx
);
242 osync_context_report_error(ctx
, OSYNC_ERROR_GENERIC
, msg
);
245 static void gc_commit_change(void *data
, OSyncPluginInfo
*info
,
246 OSyncContext
*ctx
, OSyncChange
*change
)
248 osync_trace(TRACE_ENTRY
, "%s(%p, %p, %p)", __func__
, data
, info
, ctx
, change
);
251 switch (osync_change_get_changetype(change)) {
252 case OSYNC_CHANGE_TYPE_ADDED:
256 case OSYNC_CHANGE_TYPE_MODIFIED:
260 case OSYNC_CHANGE_TYPE_DELETED:
265 osync_context_report_error(ctx, OSYNC_ERROR_NOT_SUPPORTED, "Unknown change type");
271 osync_context_report_success(ctx
);
273 osync_trace(TRACE_EXIT
, "%s", __func__
);
277 static void gc_sync_done(void *data
, OSyncPluginInfo
*info
, OSyncContext
*ctx
)
279 osync_trace(TRACE_ENTRY
, "%s(%p, %p, %p)", __func__
, data
, info
, ctx
);
280 struct gc_plgdata
*plgdata
= NULL
;
284 result
= get_mili_timestamp(plgdata
->timestamp
, TIMESTAMP_MAX_SIZE
,
286 osync_anchor_update(plgdata
->anchor_path
, "gdata", plgdata
->timestamp
);
289 static void gc_disconnect(void *data
, OSyncPluginInfo
*info
, OSyncContext
*ctx
)
291 osync_trace(TRACE_ENTRY
, "%s(%p, %p, %p)", __func__
, data
, info
, ctx
);
292 struct gc_plgdata
*plgdata
= data
;
294 osync_context_report_success(ctx
);
295 osync_trace(TRACE_EXIT
, "%s", __func__
);
298 static void gc_finalize(void *data
)
300 osync_trace(TRACE_ENTRY
, "%s(%p)", __func__
, data
);
301 struct gc_plgdata
*plgdata
= data
;
304 osync_trace(TRACE_EXIT
, "%s", __func__
);
307 static void *gc_initialize(OSyncPlugin
*plugin
,
308 OSyncPluginInfo
*info
,
311 osync_trace(TRACE_ENTRY
, "%s(%p, %p, %p)", __func__
, plugin
, info
, error
);
312 struct gc_plgdata
*plgdata
;
313 OSyncPluginConfig
*config
;
314 OSyncPluginAuthentication
*auth
;
315 OSyncPluginAdvancedOption
*advanced
;
316 OSyncList
*resources
;
318 const char *objtype
, *tmp
;
321 plgdata
= osync_try_malloc0(sizeof(struct gc_plgdata
), error
);
322 config
= osync_plugin_info_get_config(info
);
323 if ((!plgdata
) || (!config
)) {
324 osync_error_set(error
, OSYNC_ERROR_GENERIC
,
325 "Unable to get config data.");
329 advanced
= osync_plugin_config_get_advancedoption_value_by_name(config
, "xslt");
331 fprintf(stderr
, "Cannot locate xslt config!\n");
335 if (!(plgdata
->xslt_path
= strdup(osync_plugin_advancedoption_get_value(advanced
))))
338 /* TODO: add timezone in configuration */
339 if (!(plgdata
->timestamp
= malloc(TIMESTAMP_MAX_SIZE
)))
341 plgdata
->timezone
= NULL
;
343 resources
= osync_plugin_config_get_resources(config
);
344 numobjs
= osync_plugin_info_num_objtypes(info
);
346 for (i
= 1, r
= resources
; r
; r
= r
->next
, i
++) {
347 if (!(strcmp(osync_plugin_resource_get_objtype(r
->data
), "calendar")))
348 if (!(plgdata
->calendar
= gcal_new(GCALENDAR
)))
351 gcal_set_store_xml(plgdata
->calendar
, 1);
353 if (!(strcmp(osync_plugin_resource_get_objtype(r
->data
), "contact")))
354 if (!(plgdata
->contacts
= gcal_new(GCONTACT
)))
357 gcal_set_store_xml(plgdata
->contacts
, 1);
362 /* TODO: how works resource policy? For while, copy everything... */
363 for (i
= 0; i
< numobjs
; i
++) {
365 if (!plgdata
->username
) {
366 auth
= osync_plugin_config_get_authentication(config
);
367 tmp
= osync_plugin_authentication_get_username(auth
);
371 if (!(plgdata
->username
= strdup(tmp
)))
376 if (!plgdata
->password
) {
377 tmp
= osync_plugin_authentication_get_password(auth
);
381 if (!(plgdata
->password
= strdup(tmp
)))
385 /* TODO: get proxy/calendar title/resources/etc */
389 OSyncObjTypeSinkFunctions functions
;
390 memset(&functions
, 0, sizeof(functions
));
391 functions
.connect
= gc_connect
;
392 functions
.get_changes
= gc_get_changes
;
393 functions
.commit
= gc_commit_change
;
394 functions
.disconnect
= gc_disconnect
;
395 functions
.sync_done
= gc_sync_done
;
398 if (plgdata
->calendar
) {
399 fprintf(stderr
, "\n\n\tcreating calendar sink...\n");
400 OSyncFormatEnv
*formatenv1
= osync_plugin_info_get_format_env(info
);
401 plgdata
->gcal_format
= osync_format_env_find_objformat(formatenv1
, "xmlformat-event");
402 if (!plgdata
->gcal_format
)
404 osync_objformat_ref(plgdata
->gcal_format
);
406 plgdata
->gcal_sink
= osync_objtype_sink_new("event", error
);
407 if (!plgdata
->gcal_sink
)
410 osync_objtype_sink_set_functions(plgdata
->gcal_sink
, functions
, plgdata
);
411 osync_plugin_info_add_objtype(info
, plgdata
->gcal_sink
);
415 if (plgdata
->contacts
) {
416 fprintf(stderr
, "\n\n\tcreating contact sink...\n");
417 OSyncFormatEnv
*formatenv2
= osync_plugin_info_get_format_env(info
);
418 plgdata
->gcont_format
= osync_format_env_find_objformat(formatenv2
, "xmlformat-contact");
419 if (!plgdata
->gcont_format
)
421 osync_objformat_ref(plgdata
->gcont_format
);
423 plgdata
->gcont_sink
= osync_objtype_sink_new("contact", error
);
424 if (!plgdata
->gcont_sink
)
427 osync_objtype_sink_set_functions(plgdata
->gcont_sink
, functions
, plgdata
);
428 osync_plugin_info_add_objtype(info
, plgdata
->gcont_sink
);
433 plgdata
->anchor_path
= g_strdup_printf("%sanchor.db",
434 osync_plugin_info_get_configdir(info
));
435 if (!(plgdata
->anchor_path
))
438 fprintf(stderr
, "\tanchor: %s\n", plgdata
->anchor_path
);
440 if (plgdata
->calendar
)
441 if (!(plgdata
->xslt_ctx_gcal
= xslt_new()))
444 fprintf(stderr
, "\tsucceed creating xslt_gcal!\n");
446 if (plgdata
->contacts
)
447 if (!(plgdata
->xslt_ctx_gcont
= xslt_new()))
450 fprintf(stderr
, "\tsucceed creating xslt_gcont!\n");
452 osync_trace(TRACE_EXIT
, "%s", __func__
);
460 osync_trace(TRACE_EXIT_ERROR
, "%s: %s", __func__
, osync_error_print(error
));
464 static osync_bool
gc_discover(void *data
, OSyncPluginInfo
*info
, OSyncError
**error
)
466 osync_trace(TRACE_ENTRY
, "%s(%p, %p, %p)", __func__
, data
, info
, error
);
468 struct gc_plgdata
*plgdata
= data
;
470 if (plgdata
->calendar
)
471 osync_objtype_sink_set_available(plgdata
->gcal_sink
, TRUE
);
472 if (plgdata
->contacts
)
473 osync_objtype_sink_set_available(plgdata
->gcont_sink
, TRUE
);
475 OSyncVersion
*version
= osync_version_new(error
);
476 osync_version_set_plugin(version
, "google-data");
477 osync_plugin_info_set_version(info
, version
);
478 osync_version_unref(version
);
480 osync_trace(TRACE_EXIT
, "%s", __func__
);
484 osync_bool
get_sync_info(OSyncPluginEnv
*env
, OSyncError
**error
)
486 osync_trace(TRACE_ENTRY
, "%s(%p, %p)", __func__
, env
, error
);
487 OSyncPlugin
*plugin
= osync_plugin_new(error
);
491 osync_plugin_set_name(plugin
, "google-data");
492 osync_plugin_set_longname(plugin
, "Google calendar/plugin");
493 osync_plugin_set_description(plugin
, "Google calendar and contacts plugin");
495 osync_plugin_set_initialize(plugin
, gc_initialize
);
496 osync_plugin_set_finalize(plugin
, gc_finalize
);
497 osync_plugin_set_discover(plugin
, gc_discover
);
499 osync_plugin_env_register_plugin(env
, plugin
);
500 osync_plugin_unref(plugin
);
502 osync_trace(TRACE_EXIT
, "%s", __func__
);
506 osync_trace(TRACE_EXIT_ERROR
, "Unable to register: %s", osync_error_print(error
));
507 osync_error_unref(error
);
511 int get_version(void)