Adding logic to allow contact resource creation (XSLT loading and getting
[gdataplugin.git] / src / gcalendar.c
blob57d7a83493ae193583ecff4f7ba1562cf01f9ee2
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
19 * 02110-1301 USA
23 /* TODO:
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'
29 * helper tool)
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>
43 #include <glib.h>
45 #include <libxml/tree.h>
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <sys/types.h>
51 #include <signal.h>
52 #include <sys/wait.h>
53 #include <gcal_status.h>
54 #include <gcalendar.h>
55 #include <gcontact.h>
56 #include "xslt_aux.h"
58 struct gc_plgdata
60 char *url;
61 char *username;
62 char *password;
63 char *anchor_path;
64 char *timestamp;
65 char *timezone;
66 char *xslt_path;
67 /* libgcal resources */
68 gcal_t calendar;
69 gcal_t contacts;
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);
104 if (plgdata->url)
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);
118 g_free(plgdata);
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,
126 OSyncError **error)
129 osync_bool result = FALSE;
130 /* TODO: add calls to libgcal */
131 exit:
132 return result;
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;
139 int result;
140 struct gc_plgdata *plgdata = data;
141 OSyncObjTypeSink *sink = osync_plugin_info_get_sink(info);
142 OSyncError *error = NULL;
143 char buffer[512];
145 if ((plgdata->calendar) && (counter == 0)) {
146 result = gcal_get_authentication(plgdata->calendar, plgdata->username,
147 plgdata->password);
148 ++counter;
149 if (result == -1)
150 goto error;
152 snprintf(buffer, sizeof(buffer) - 1, "%s/gcal2osync.xslt",
153 plgdata->xslt_path);
154 if ((result = xslt_initialize(plgdata->xslt_ctx_gcal, buffer)))
155 goto error;
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,
162 plgdata->password);
163 counter++;
164 if (result == -1)
165 goto error;
167 snprintf(buffer, sizeof(buffer) - 1, "%s/gcont2osync.xslt",
168 plgdata->xslt_path);
169 if ((result = xslt_initialize(plgdata->xslt_ctx_gcont, buffer)))
170 goto error;
171 fprintf(stderr, "\ndone contact: %s\n", buffer);
174 osync_context_report_success(ctx);
175 osync_trace(TRACE_EXIT, "%s", __func__);
176 return;
178 error:
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;
190 int result = 0;
191 char *timestamp = NULL, *msg;
193 timestamp = osync_anchor_retrieve(plgdata->anchor_path, "gdata");
194 if (timestamp)
195 fprintf(stderr, "timestamp is: %s\n", timestamp);
196 else
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));
203 if (result) {
204 msg = "Failed getting events!";
205 goto error;
207 /* TODO: report back events to opensync */
208 fprintf(stderr, "\tgot then all!\n");
210 } else {
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));
222 if (result) {
223 msg = "Failed getting contacts!";
224 goto error;
227 fprintf(stderr, "\tgot then all!\n");
229 /* TODO: report back contacts to opensync */
231 } else {
232 /* TODO: write getchanges */
233 fprintf(stderr, "\n\t\tgcont: Its a fast sync!\n");
236 exit:
237 ++counter;
238 osync_context_report_success(ctx);
239 return;
240 error:
241 ++counter;
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:
253 cmd = "add";
254 arg = NULL;
255 break;
256 case OSYNC_CHANGE_TYPE_MODIFIED:
257 cmd = "edit";
258 arg = hash;
259 break;
260 case OSYNC_CHANGE_TYPE_DELETED:
261 cmd = "delete";
262 arg = hash;
263 break;
264 default:
265 osync_context_report_error(ctx, OSYNC_ERROR_NOT_SUPPORTED, "Unknown change type");
266 goto error;
267 break;
271 osync_context_report_success(ctx);
273 osync_trace(TRACE_EXIT, "%s", __func__);
274 return;
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;
281 int result;
283 plgdata = data;
284 result = get_mili_timestamp(plgdata->timestamp, TIMESTAMP_MAX_SIZE,
285 plgdata->timezone);
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;
303 free_plg(plgdata);
304 osync_trace(TRACE_EXIT, "%s", __func__);
307 static void *gc_initialize(OSyncPlugin *plugin,
308 OSyncPluginInfo *info,
309 OSyncError **error)
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;
317 OSyncList *r;
318 const char *objtype, *tmp;
319 int i, numobjs;
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.");
326 goto error_freeplg;
329 advanced = osync_plugin_config_get_advancedoption_value_by_name(config, "xslt");
330 if (!advanced) {
331 fprintf(stderr, "Cannot locate xslt config!\n");
332 goto error_freeplg;
335 if (!(plgdata->xslt_path = strdup(osync_plugin_advancedoption_get_value(advanced))))
336 goto error_freeplg;
338 /* TODO: add timezone in configuration */
339 if (!(plgdata->timestamp = malloc(TIMESTAMP_MAX_SIZE)))
340 goto error_freeplg;
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)))
349 goto error_freeplg;
350 else
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)))
355 goto error_freeplg;
356 else
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);
368 if (!tmp)
369 goto error_freeplg;
370 else
371 if (!(plgdata->username = strdup(tmp)))
372 goto error_freeplg;
376 if (!plgdata->password) {
377 tmp = osync_plugin_authentication_get_password(auth);
378 if (!tmp)
379 goto error_freeplg;
380 else
381 if (!(plgdata->password = strdup(tmp)))
382 goto error_freeplg;
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)
403 goto error_freeplg;
404 osync_objformat_ref(plgdata->gcal_format);
406 plgdata->gcal_sink = osync_objtype_sink_new("event", error);
407 if (!plgdata->gcal_sink)
408 goto error_freeplg;
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)
420 goto error_freeplg;
421 osync_objformat_ref(plgdata->gcont_format);
423 plgdata->gcont_sink = osync_objtype_sink_new("contact", error);
424 if (!plgdata->gcont_sink)
425 goto error_freeplg;
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))
436 goto error_freeplg;
437 else
438 fprintf(stderr, "\tanchor: %s\n", plgdata->anchor_path);
440 if (plgdata->calendar)
441 if (!(plgdata->xslt_ctx_gcal = xslt_new()))
442 goto error_freeplg;
443 else
444 fprintf(stderr, "\tsucceed creating xslt_gcal!\n");
446 if (plgdata->contacts)
447 if (!(plgdata->xslt_ctx_gcont = xslt_new()))
448 goto error_freeplg;
449 else
450 fprintf(stderr, "\tsucceed creating xslt_gcont!\n");
452 osync_trace(TRACE_EXIT, "%s", __func__);
454 return plgdata;
456 error_freeplg:
457 if (plgdata)
458 free_plg(plgdata);
459 out:
460 osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
461 return NULL;
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__);
481 return TRUE;
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);
488 if (!plugin)
489 goto 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__);
503 return TRUE;
505 error:
506 osync_trace(TRACE_EXIT_ERROR, "Unable to register: %s", osync_error_print(error));
507 osync_error_unref(error);
508 return FALSE;
511 int get_version(void)
513 return 1;