Update of /cvsroot/multisync/multisync/plugins/gpe_plugin/src In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv30033/src Added Files: Tag: branch_08X Makefile.am calendar.c config.c connection.c contacts.c gpe_sync.c gui.c todo.c Log Message: Initial revision of gpe_plugin --- NEW FILE: contacts.c --- /* * MultiSync GPE Plugin * Copyright (C) 2004 Phil Blundell <pb...@ne...> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation; */ #include <stdlib.h> #include <errno.h> #include <glib.h> #include <libintl.h> #include <stdio.h> #include <string.h> #include "gpe_sync.h" #include <gpe/vcard.h> #include <gpe/tag-db.h> GList * contacts_get_changes (struct db *db, int newdb) { GList *data = NULL; GSList *list, *i; if (newdb) list = fetch_uid_list (db->db, "select distinct urn from contacts_urn"); else list = fetch_uid_list (db->db, "select urn from contacts where (tag='modified' or tag='MODIFIED') and value>%d", db->last_timestamp); for (i = list; i; i = i->next) { GSList *tags; MIMEDirVCard *vcard; gchar *string; changed_object *obj; int urn = (int)i->data; tags = fetch_tag_data (db->db, "select tag,value from contacts where urn=%d", urn); vcard = vcard_from_tags (tags); gpe_tag_list_free (tags); string = mimedir_vcard_write_to_string (vcard); g_object_unref (vcard); obj = g_malloc0 (sizeof (*obj)); obj->comp = string; obj->uid = g_strdup_printf ("%d", urn); obj->object_type = SYNC_OBJECT_TYPE_PHONEBOOK; obj->change_type = SYNC_OBJ_MODIFIED; data = g_list_append (data, obj); } g_slist_free (list); return data; } gboolean contacts_push_object (struct db *db, const char *obj, const char *uid, char *returnuid, int *returnuidlen, GError **err) { GSList *tags; MIMEDirVCard *vcard; int id; vcard = mimedir_vcard_new_from_string (obj, err); if (vcard == NULL) return FALSE; tags = vcard_to_tags (vcard); if (uid) id = atoi (uid); else { char *errmsg; if (nsqlc_exec (db->db, "insert into contacts_urn values (NULL)", NULL, NULL, &errmsg)) return FALSE; id = nsqlc_last_insert_rowid (db->db); } store_tag_data (db->db, "contacts", id, tags, TRUE); sprintf (returnuid, "%d", id); *returnuidlen = strlen (returnuid); return TRUE; } gboolean contacts_delete_object (struct db *db, const char *uid, gboolean soft) { nsqlc_exec_printf (db->db, "delete from contacts where urn='%q'", NULL, NULL, NULL, uid); nsqlc_exec_printf (db->db, "delete from contacts_urn where urn='%q'", NULL, NULL, NULL, uid); return TRUE; } struct db contacts_db = { .type = SYNC_OBJECT_TYPE_PHONEBOOK, .name = "contacts", .get_changes = contacts_get_changes, .push_object = contacts_push_object, .delete_object = contacts_delete_object, }; void contacts_init (void) { db_list = g_slist_append (db_list, &contacts_db); } --- NEW FILE: calendar.c --- /* * MultiSync GPE Plugin * Copyright (C) 2004 Phil Blundell <pb...@ne...> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation; */ #include <stdlib.h> #include <errno.h> #include <glib.h> #include <libintl.h> #include <stdio.h> #include <string.h> #include "gpe_sync.h" #include <gpe/vevent.h> #include <gpe/tag-db.h> #include <mimedir/mimedir-vcal.h> GList * calendar_get_changes (struct db *db, int newdb) { GList *data = NULL; GSList *list, *i; if (newdb) list = fetch_uid_list (db->db, "select distinct uid from calendar_urn"); else list = fetch_uid_list (db->db, "select uid from calendar where (tag='modified' or tag='MODIFIED') and value>%d", db->last_timestamp); for (i = list; i; i = i->next) { GSList *tags; MIMEDirVCal *vcal; MIMEDirVEvent *vevent; gchar *string; changed_object *obj; int urn = (int)i->data; tags = fetch_tag_data (db->db, "select tag,value from calendar where uid=%d", urn); vevent = vevent_from_tags (tags); gpe_tag_list_free (tags); vcal = mimedir_vcal_new (); mimedir_vcal_add_component (vcal, MIMEDIR_VCOMPONENT (vevent)); string = mimedir_vcal_write_to_string (vcal); g_object_unref (vcal); obj = g_malloc0 (sizeof (*obj)); obj->comp = string; obj->uid = g_strdup_printf ("%d", urn); obj->object_type = SYNC_OBJECT_TYPE_CALENDAR; obj->change_type = SYNC_OBJ_MODIFIED; data = g_list_append (data, obj); } g_slist_free (list); return data; } gboolean calendar_push_object (struct db *db, const char *obj, const char *uid, char *returnuid, int *returnuidlen, GError **err) { GSList *list, *tags; MIMEDirVEvent *vevent; MIMEDirVCal *vcal; int id; vcal = mimedir_vcal_new_from_string (obj, err); if (vcal == NULL) return FALSE; list = mimedir_vcal_get_event_list (vcal); if (list == NULL) { g_object_unref (vcal); return FALSE; } vevent = MIMEDIR_VEVENT (list->data); tags = vevent_to_tags (vevent); if (uid) id = atoi (uid); else { char *errmsg; if (nsqlc_exec (db->db, "insert into calendar_urn values (NULL)", NULL, NULL, &errmsg)) return FALSE; id = nsqlc_last_insert_rowid (db->db); } mimedir_vcal_free_component_list (list); g_object_unref (vcal); store_tag_data (db->db, "calendar", id, tags, TRUE); sprintf (returnuid, "%d", id); *returnuidlen = strlen (returnuid); return TRUE; } gboolean calendar_delete_object (struct db *db, const char *uid, gboolean soft) { nsqlc_exec_printf (db->db, "delete from calendar where uid='%q'", NULL, NULL, NULL, uid); nsqlc_exec_printf (db->db, "delete from calendar_urn where uid='%q'", NULL, NULL, NULL, uid); return TRUE; } struct db calendar_db = { .type = SYNC_OBJECT_TYPE_CALENDAR, .name = "calendar", .get_changes = calendar_get_changes, .push_object = calendar_push_object, .delete_object = calendar_delete_object, }; void calendar_init (void) { db_list = g_slist_append (db_list, &calendar_db); } --- NEW FILE: todo.c --- /* * MultiSync GPE Plugin * Copyright (C) 2004 Phil Blundell <pb...@ne...> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation; */ #include <stdlib.h> #include <errno.h> #include <glib.h> #include <libintl.h> #include <stdio.h> #include <string.h> #include "gpe_sync.h" #include <gpe/vtodo.h> #include <gpe/tag-db.h> #include <mimedir/mimedir-vcal.h> GList * todo_get_changes (struct db *db, int newdb) { GList *data = NULL; GSList *list, *i; if (newdb) list = fetch_uid_list (db->db, "select distinct uid from todo_urn"); else list = fetch_uid_list (db->db, "select uid from todo where (tag='modified' or tag='MODIFIED') and value>%d", db->last_timestamp); for (i = list; i; i = i->next) { GSList *tags; MIMEDirVCal *vcal; MIMEDirVTodo *vtodo; gchar *string; changed_object *obj; int urn = (int)i->data; tags = fetch_tag_data (db->db, "select tag,value from todo where uid=%d", urn); vtodo = vtodo_from_tags (tags); gpe_tag_list_free (tags); vcal = mimedir_vcal_new (); mimedir_vcal_add_component (vcal, MIMEDIR_VCOMPONENT (vtodo)); string = mimedir_vcal_write_to_string (vcal); g_object_unref (vcal); obj = g_malloc0 (sizeof (*obj)); obj->comp = string; obj->uid = g_strdup_printf ("todo-%d", urn); obj->object_type = SYNC_OBJECT_TYPE_TODO; obj->change_type = SYNC_OBJ_MODIFIED; data = g_list_append (data, obj); } g_slist_free (list); return data; } gboolean todo_push_object (struct db *db, const char *obj, const char *uid, char *returnuid, int *returnuidlen, GError **err) { GSList *list, *tags; MIMEDirVTodo *vtodo; MIMEDirVCal *vcal; int id; vcal = mimedir_vcal_new_from_string (obj, err); if (vcal == NULL) return FALSE; list = mimedir_vcal_get_todo_list (vcal); if (list == NULL) { g_object_unref (vcal); return FALSE; } vtodo = MIMEDIR_VTODO (list->data); tags = vtodo_to_tags (vtodo); if (uid) sscanf (uid, "todo-%d", &id); else { char *errmsg; if (nsqlc_exec (db->db, "insert into todo_urn values (NULL)", NULL, NULL, &errmsg)) return FALSE; id = nsqlc_last_insert_rowid (db->db); } mimedir_vcal_free_component_list (list); g_object_unref (vcal); nsqlc_exec_printf (db->db, "delete from todo where uid='%q'", NULL, NULL, NULL, uid); store_tag_data (db->db, "todo", id, tags, FALSE); sprintf (returnuid, "%d", id); *returnuidlen = strlen (returnuid); return TRUE; } gboolean todo_delete_object (struct db *db, const char *uid, gboolean soft) { nsqlc_exec_printf (db->db, "delete from todo where uid='%q'", NULL, NULL, NULL, uid); nsqlc_exec_printf (db->db, "delete from todo_urn where uid='%q'", NULL, NULL, NULL, uid); return TRUE; } struct db todo_db = { .type = SYNC_OBJECT_TYPE_TODO, .name = "todo", .get_changes = todo_get_changes, .push_object = todo_push_object, .delete_object = todo_delete_object, }; void todo_init (void) { db_list = g_slist_append (db_list, &todo_db); } --- NEW FILE: Makefile.am --- ## Process this file with automake to produce Makefile.in libdir=$(prefix)/lib/multisync PLUGINDIR = $(libdir) if GPE_DBG_FLAGS GPE_CFLAGS = -g -D_GPE_PRINT_DEBUG -D_GPE_LOG_DEBUG else GPE_CFLAGS = -O2 endif MULTISYNC_HOME = "$(prefix)/include/multisync" AM_CFLAGS = $(GPE_CFLAGS) -DPLUGINDIR=\"$(PLUGINDIR)\" -DPREFIX=\"$(prefix)\" INCLUDES = \ -DPACKAGE_DATA_DIR=\""$(datadir)"\" \ -DPACKAGE_LOCALE_DIR=\""$(prefix)/$(DATADIRNAME)/locale"\" \ -I../../../src/libversit -I$(top_srcdir) -I$(top_srcdir)/intl -I$(top_srcdir)/../../include \ -I$(MULTISYNC_HOME) \ @PACKAGE_CFLAGS@ lib_LTLIBRARIES = libgpe_sync.la libgpe_sync_la_SOURCES = \ gpe_sync.c calendar.c connection.c contacts.c todo.c gui.c libgpe_sync_la_LIBADD = -lnsqlc @PACKAGE_LIBS@ --- NEW FILE: gpe_sync.c --- /* * MultiSync GPE Plugin * Copyright (C) 2004 Phil Blundell <pb...@ne...> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation; */ #include <stdlib.h> #include <errno.h> #include <glib.h> #include <libintl.h> #include <stdio.h> #include <string.h> #include "multisync.h" #include "gpe_sync.h" /* this should match MULTISYNC_API_VER in * multisync.h if everything is up to date */ #define GPE_MULTISYNC_API_VER (3) #define _(x) gettext(x) GSList *db_list; /****************************************************************** The following functions are called by the syncengine thread, and syncengine expects an asynchronous answer using on of // Success sync_set_requestdone(sync_pair*); // General failure (equal to sync_set_requestmsg(SYNC_MSG_REQFAILED,...)) sync_set_requestfailed(sync_pair*); // General failure with specific log string sync_set_requestfailederror(char*, sync_pair*); // Success with data sync_set_requestdata(gpointer data, sync_pair*); // General return (with either failure or other request) sync_set_requestmsg(sync_msg_type, sync_pair*); // General return with log string sync_set_requestmsgerror(sync_msg_type, char*, sync_pair*); // General return with data pointere sync_set_requestdatamsg(gpointer data, sync_msg_type, sync_pair*); (Yes, there are lots of them for convenience.) These functions do not have to be called from this thread. If your client uses the gtk main loop, use gtk_idle_add() to call your real function and let that function call sync_set_requestsomething() when done. ******************************************************************/ /* sync_connect() This is called once every time the sync engine tries to get changes from the two plugins, or only once if always_connected() returns true. Typically, this is where you should try to connect to the device to be synchronized, as well as load any options and so on. The returned struct must contain a client_connection commondata; first for common MultiSync data. NOTE: Oddly enough (for historical reasons) this callback MUST return the connection handle from this function call (and NOT by using sync_set_requestdata()). The sync engine still waits for a sync_set_requestdone() call (or _requestfailed) before continuing. */ gpe_conn* sync_connect (sync_pair* handle, connection_type type, sync_object_type object_types) { gpe_conn *conn = NULL; conn = g_malloc0 (sizeof (gpe_conn)); g_assert (conn); conn->sync_pair = handle; conn->commondata.object_types = object_types; pthread_create (&conn->thread, NULL, gpe_do_connect, conn); return conn; } /* sync_disconnect() Called by the sync engine to free the connection handle and disconnect from the database client. */ void sync_disconnect (gpe_conn *conn) { GSList *i; sync_pair *sync_pair = conn->sync_pair; GPE_DEBUG(conn, "sync_disconnect"); for (i = db_list; i; i = i->next) { struct db *db = i->data; gpe_disconnect (db); } /* cleanup memory from the connection */ if (conn->device_addr) g_free (conn->device_addr); if (conn->username) g_free (conn->username); g_free (conn); sync_set_requestdone (sync_pair); } /* get_changes() The most important function in the plugin. This function is called periodically by the sync engine to poll for changes in the database to be synchronized. The function should return a pointer to a gmalloc'ed change_info struct (which will be freed by the sync engine after usage). using sync_set_requestdata(change_info*, sync_pair*). For all data types set in the argument "newdbs", ALL entries should be returned. This is used when the other end reports that a database has been reset (by e.g. selecting "Reset all data" in a mobile phone.) Testing for a data type is simply done by if (newdbs & SYNC_OBJECT_TYPE_SOMETHING) ... The "commondata" field of the connection handle contains the field commondata.object_types which specifies which data types should be synchronized. Only return changes from these data types. The changes reported by this function should be the remembered and rereported every time until sync_done() (see below) has been called with a success value. This ensures that no changes get lost if some connection fails. */ void get_changes (gpe_conn *conn, sync_object_type newdbs) { conn->newdbs = newdbs; pthread_create (&conn->thread, NULL, gpe_do_get_changes, conn); } /* syncobj_modify() Modify or add an object in the database. This is called by the sync engine when a change has been reported in the other end. Arguments: object A string containing the actual data of the object. E.g. for an objtype of SYNC_OBJECT_TYPE_CALENDAR, this is a vCALENDAR 2.0 string (see RFC 2445). uid The unique ID of this entry. If it is new (i.e. the sync engine has not seen it before), this is NULL. objtype The data type of this object. returnuid If uid is NULL, then the ID of the newly created object should be returned in this buffer (if non-NULL). The length of the ID should be returned in returnuidlen. */ void syncobj_modify (gpe_conn *conn, char* object, char *uid, sync_object_type objtype, char *returnuid, int *returnuidlen) { GError *err = NULL; GSList *i; GPE_DEBUG (conn, "syncobj_modify"); for (i = db_list; i; i = i->next) { struct db *db = i->data; if (objtype & db->type) db->push_object (db, object, uid, returnuid, returnuidlen, &err); } sync_set_requestdone (conn->sync_pair); } /* syncobj_delete() Delete an object from the database. If the argument softdelete is true, then this object is deleted by the sync engine for storage reasons. */ void syncobj_delete (gpe_conn *conn, char *uid, sync_object_type objtype, int softdelete) { gboolean soft = softdelete ? TRUE : FALSE; GSList *i; GPE_DEBUG (conn, "syncobj_delete"); if (!uid) { GPE_DEBUG (conn, "item to delete not specified by syncengine"); sync_set_requestfailed (conn->sync_pair); return; } for (i = db_list; i; i = i->next) { struct db *db = i->data; if (objtype & db->type) db->delete_object (db, uid, soft); } sync_set_requestdone (conn->sync_pair); } /* syncobj_get_recurring() This is a very optional function which may very well be removed in the future. It should return a list of all recurrence instance of an object (such as all instances of a recurring calendar event). The recurring events should be returned as a GList of changed_objects with change type SYNC_OBJ_RECUR. */ void syncobj_get_recurring (gpe_conn *conn, changed_object *obj) { GPE_DEBUG(conn, "syncobj_get_recurring"); /* * not implemented */ sync_set_requestdata (NULL, conn->sync_pair); } /* sync_done() This function is called by the sync engine after a synchronization has been completed. If success is true, the sync was successful, and all changes reported by get_changes can be forgot. If your database is based on a change counter, this can be done by simply saving the new change counter. */ void sync_done (gpe_conn *conn, gboolean success) { GSList *i; for (i = db_list; i; i = i->next) { struct db *db = i->data; if (db->changed) { gchar *filename; FILE *fp; filename = g_strdup_printf ("%s/%s", sync_get_datapath (conn->sync_pair), db->name); fp = fopen (filename, "w"); if (fp) { fprintf (fp, "%d\n", (int)db->current_timestamp); fclose (fp); } g_free (filename); } } sync_set_requestdone (conn->sync_pair); } /*********************************************************************** The following functions are synchronous, i.e. the syncengine expects an immedieate answer without using sync_set_requestsomething() ************************************************************************/ /* always_connected() Return TRUE if this client does not have to be polled (i.e. can be constantly connected). */ gboolean always_connected (void) { return FALSE; } /* short_name() Return a short plugin name for internal use. */ char * short_name (void) { return "gpe"; } /* long_name() Return a long name which can be shown to the user. */ char * long_name (void) { return _("GPE"); } /* plugin_info() Return an even longer description of what this plugin does. This will be shown next to the drop-down menu in the sync pair options. */ char * plugin_info (void) { return _("This plugin allows you to synchronize with the GPE Palmtop Environment"); } /* plugin_init() Initialize the plugin. Called once upon loading of the plugin (NOT once per sync pair). */ void plugin_init (void) { calendar_init (); todo_init (); contacts_init (); } /* object_types() Return the data types this plugin can handle. */ sync_object_type object_types (void) { return SYNC_OBJECT_TYPE_CALENDAR | SYNC_OBJECT_TYPE_TODO | SYNC_OBJECT_TYPE_PHONEBOOK; } /* plugin_API_version() Return the MultiSync API version for which the plugin was compiled. It is defined in multisync.h as MULTISYNC_API_VER. Do not use return(MULTISYNC_API_VER), though, as the plugin will then get valid after a simple recompilation. This may not be all that is needed. */ int plugin_API_version (void) { return GPE_MULTISYNC_API_VER; } --- NEW FILE: gui.c --- /* * MultiSync GPE Plugin * Copyright (C) 2004 Phil Blundell <pb...@ne...> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation; */ #include "config.h" #include <gtk/gtk.h> #include <glade/glade.h> #include "gpe_sync.h" void cancel_clicked (GtkWidget *w, GtkWidget *data) { gtk_widget_destroy (data); } void ok_clicked (GtkWidget *w, GtkWidget *data) { gpe_conn *conn; conn = g_object_get_data (G_OBJECT (data), "conn"); g_free (conn->username); g_free (conn->device_addr); w = g_object_get_data (G_OBJECT (data), "username"); conn->username = gtk_editable_get_chars (GTK_EDITABLE (w), 0, -1); w = g_object_get_data (G_OBJECT (data), "addr"); conn->device_addr = gtk_editable_get_chars (GTK_EDITABLE (GTK_COMBO (w)->entry), 0, -1); gpe_save_config (conn); gtk_widget_destroy (data); } void delete_window (GtkWidget *w) { gpe_conn *conn; conn = g_object_get_data (G_OBJECT (w), "conn"); g_free (conn->username); g_free (conn->device_addr); g_free (conn); sync_plugin_window_closed (); } GtkWidget* open_option_window (sync_pair *pair, connection_type type) { GladeXML *xml; gchar *filename; GtkWidget *config_window; GtkWidget *w; gpe_conn *conn; filename = g_build_filename (PREFIX, "share", PACKAGE_NAME, "gpe_sync.glade", NULL); xml = glade_xml_new (filename, NULL, NULL); g_free (filename); if (xml == NULL) return FALSE; conn = g_malloc0 (sizeof (*conn)); conn->sync_pair = pair; config_window = glade_xml_get_widget (xml, "gpe_config"); gpe_load_config (conn); g_object_set_data (G_OBJECT (config_window), "conn", conn); g_signal_connect (G_OBJECT (config_window), "destroy", G_CALLBACK (delete_window), NULL); w = glade_xml_get_widget (xml, "entry1"); gtk_entry_set_text (GTK_ENTRY (w), conn->username); g_object_set_data (G_OBJECT (config_window), "username", w); w = glade_xml_get_widget (xml, "combo1"); gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (w)->entry), conn->device_addr); g_object_set_data (G_OBJECT (config_window), "addr", w); w = glade_xml_get_widget (xml, "cancelbutton1"); g_signal_connect (G_OBJECT (w), "clicked", G_CALLBACK (cancel_clicked), config_window); w = glade_xml_get_widget (xml, "okbutton1"); g_signal_connect (G_OBJECT (w), "clicked", G_CALLBACK (ok_clicked), config_window); g_object_unref (G_OBJECT (xml)); return config_window; } --- NEW FILE: config.c --- /* * MultiSync GPE Plugin * Copyright (C) 2004 Phil Blundell <pb...@ne...> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation; */ #include <stdlib.h> #include <errno.h> #include <glib.h> #include <libintl.h> #include <stdio.h> #include <string.h> #include "multisync.h" #include "gpe_sync.h" gchar * gpe_config_path (gpe_conn *conn) { gchar *filename; filename = g_strdup_printf ("%s/%s", sync_get_datapath (conn->sync_pair), "gpe_config.dat"); return filename; } gboolean gpe_load_config (gpe_conn *conn) { gchar *path; FILE *fp; path = gpe_config_path (conn); fp = fopen (path, "r"); if (fp) { char buf[256]; if (fgets (buf, sizeof (buf), fp)) { buf [strlen (buf) - 1] = 0; conn->device_addr = g_strdup (buf); } if (fgets (buf, sizeof (buf), fp)) { buf [strlen (buf) - 1] = 0; conn->username = g_strdup (buf); } fclose (fp); } else { conn->username = g_strdup (g_get_user_name ()); conn->device_addr = g_strdup ("localhost"); } g_free (path); return TRUE; } gboolean gpe_save_config (gpe_conn *conn) { gchar *path; FILE *fp; path = gpe_config_path (conn); fprintf (stderr, "Saving config to %s\n", path); fp = fopen (path, "w"); if (fp) { fprintf (fp, "%s\n", conn->device_addr); fprintf (fp, "%s\n", conn->username); fclose (fp); } g_free (path); return TRUE; } --- NEW FILE: connection.c --- /* * MultiSync GPE Plugin * Copyright (C) 2004 Phil Blundell <pb...@ne...> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation; */ #include <stdlib.h> #include <errno.h> #include <glib.h> #include <libintl.h> #include <stdio.h> #include <string.h> #include <fcntl.h> #include "gpe_sync.h" #include <gpe/tag-db.h> #define _(x) gettext(x) nsqlc * gpe_connect_one (gpe_conn *conn, const gchar *db, char **err) { gchar *path; nsqlc *r; path = g_strdup_printf ("%s@%s:.gpe/%s", conn->username, conn->device_addr, db); fprintf (stderr, "connecting to %s\n", path); r = nsqlc_open_ssh (path, O_RDWR, err); g_free (path); return r; } void * gpe_do_connect (void *_conn) { GSList *i; char* errmsg = NULL; gboolean failed = FALSE; gpe_conn *conn; conn = (gpe_conn *)_conn; GPE_DEBUG(conn, "sync_connect"); /* load the connection attributes */ if (! gpe_load_config (conn)) { /* failure */ errmsg = g_strdup (_("Failed to load configuration")); sync_set_requestfailederror (errmsg, conn->sync_pair); pthread_exit (0); } for (i = db_list; i; i = i->next) { struct db *db = i->data; db->db = gpe_connect_one (conn, db->name, &errmsg); if (!db->db) { failed = TRUE; break; } } if (failed) { for (i = db_list; i; i = i->next) { struct db *db = i->data; gpe_disconnect (db); } sync_set_requestfailederror (g_strdup (errmsg), conn->sync_pair); pthread_exit (0); } sync_set_requestdone (conn->sync_pair); pthread_exit (0); } void gpe_disconnect (struct db *db) { if (db->db) nsqlc_close (db->db); db->db = NULL; } void * gpe_do_get_changes (void *_conn) { GSList *i; GList *changes = NULL; sync_object_type retnewdbs = 0; change_info *chinfo; gpe_conn *conn; sync_object_type newdbs; conn = (gpe_conn *)_conn; newdbs = conn->newdbs; GPE_DEBUG(conn, "get_changes"); for (i = db_list; i; i = i->next) { struct db *db = i->data; gchar *filename; FILE *fp; db->last_timestamp = 0; filename = g_strdup_printf ("%s/%s", sync_get_datapath (conn->sync_pair), db->name); fp = fopen (filename, "r"); if (fp) { int i; if (fscanf (fp, "%d", &i)) db->last_timestamp = i; fclose (fp); } g_free (filename); nsqlc_get_time (db->db, &db->current_timestamp, NULL); if (conn->commondata.object_types & db->type) { GList *local_changes = db->get_changes (db, newdbs & db->type); if (local_changes) { db->changed = TRUE; changes = g_list_concat (changes, local_changes); } } } /* Allocate the change_info struct */ chinfo = g_malloc0 (sizeof (change_info)); chinfo->changes = changes; /* Did we detect any reset databases */ chinfo->newdbs = retnewdbs; sync_set_requestdata (chinfo, conn->sync_pair); pthread_exit (0); } static int fetch_callback (void *arg, int argc, char **argv, char **names) { if (argc == 2) { GSList **data = (GSList **)arg; gpe_tag_pair *p = g_malloc (sizeof (*p)); p->tag = g_strdup (argv[0]); p->value = g_strdup (argv[1]); *data = g_slist_prepend (*data, p); } return 0; } GSList * fetch_tag_data (nsqlc *db, const gchar *query_str, guint id) { GSList *data = NULL; nsqlc_exec_printf (db, query_str, fetch_callback, &data, NULL, id); return data; } gboolean store_tag_data (nsqlc *db, const gchar *table, guint id, GSList *tags, gboolean delete) { if (delete) nsqlc_exec_printf (db, "delete from '%q' where urn=%d", NULL, NULL, NULL, table, id); while (tags) { gpe_tag_pair *p = tags->data; nsqlc_exec_printf (db, "insert into '%q' values (%d, '%q', '%q')", NULL, NULL, NULL, table, id, p->tag, p->value); tags = tags->next; } return TRUE; } static int fetch_uid_callback (void *arg, int argc, char **argv, char **names) { if (argc == 1) { GSList **data = (GSList **)arg; *data = g_slist_prepend (*data, (void *)atoi (argv[0])); } return 0; } GSList * fetch_uid_list (nsqlc *db, const gchar *query, ...) { GSList *data = NULL; va_list ap; va_start (ap, query); nsqlc_exec_vprintf (db, query, fetch_uid_callback, &data, NULL, ap); va_end (ap); return data; } |