From: Markus M. <ms...@us...> - 2005-03-06 01:31:02
|
Update of /cvsroot/multisync/multisync/plugins/sunbird_plugin/src In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv32055 Modified Files: Tag: branch_08X Makefile sunbird_plugin.c sunbird_plugin.h tools.c tools.h Log Message: Initial support for two-way-sync Index: tools.h =================================================================== RCS file: /cvsroot/multisync/multisync/plugins/sunbird_plugin/src/Attic/tools.h,v retrieving revision 1.1.2.1 retrieving revision 1.1.2.2 diff -u -d -r1.1.2.1 -r1.1.2.2 --- tools.h 4 Feb 2005 09:50:55 -0000 1.1.2.1 +++ tools.h 6 Mar 2005 01:30:49 -0000 1.1.2.2 @@ -10,6 +10,8 @@ GString* data; /* The actual entry data in iCalendar format */ GString* remove_priority; int deleted; /* Notification that entry has been deleted */ + int remote_change_type; /* Remote change type, one of SYNC_OBJ_MODIFIED/ADDED/HARDDELETED, + or 0, when this is a notification of a local change */ } calendar_entry; /* @@ -33,6 +35,16 @@ /* Free a list of strings (list of char* pointers, not GStrings) */ void free_string_list(GList *lst); +/* Patch a calendar file (held in memory as a string), + adding/deleting/modifying the given entry */ +void patch_calendar(GString* calendar, int change_type, char* id, char* data); + +/* Return a new UID as a GString */ +GString* create_new_uid(); + +/* Extract the first VEVENT from this VCARD (and remove BEGIN:VCARD/END:VCARD) */ +GString* extract_first_vevent(char* data); + /* Note that this function, despite its name, will at the moment not read every icalendar file, because it doesn't really parse the file, but Index: sunbird_plugin.c =================================================================== RCS file: /cvsroot/multisync/multisync/plugins/sunbird_plugin/src/Attic/sunbird_plugin.c,v retrieving revision 1.1.2.1 retrieving revision 1.1.2.2 diff -u -d -r1.1.2.1 -r1.1.2.2 --- sunbird_plugin.c 4 Feb 2005 09:50:55 -0000 1.1.2.1 +++ sunbird_plugin.c 6 Mar 2005 01:30:49 -0000 1.1.2.2 @@ -56,22 +56,13 @@ sync_set_requestdone(sync_pair); } -int get_calendar_changes(GList** changes_ptr, sync_object_type* retnewdbs_ptr, ical_connection* conn) +GList* get_calendar_files_list() { - char keyfile[256]; - GString* calendars_env = g_string_new(g_getenv("MULTISYNC_SUNBIRD_CALENDARS")); - GList *entries = NULL, *cached_entries = NULL, *files = NULL, *cur, *cur2; - - /* Free previous pending changes, if any */ - if (conn->pending_changes) - { - printf("Warning: Resetting pending changes\n"); - free_events_list(conn->pending_changes); - conn->pending_changes = NULL; - } - /* FIXME: We need an option dialog for that */ /* FIXME: We also should not use strtok (not multithread-safe) */ + GList* files = NULL; + GString* calendars_env = g_string_new(g_getenv("MULTISYNC_SUNBIRD_CALENDARS")); + if (calendars_env) { char* pch; @@ -86,9 +77,193 @@ { printf("ERROR: List of calendars not set. Set MULTISYNC_SUNBIRD_CALENDARS\n"); printf(" to a list of ics files or URLs, separated with colons (':')"); - return FALSE; } + + return files; +} + +void write_changes_to_calendars(GList* entries, ical_connection* conn) +{ + char keyfile[256]; + GList* files = get_calendar_files_list(), *calendars = NULL, *cur, *cur2, *curfile, *curcal, *cached_entries = NULL; + GString *default_calendar = g_string_new(g_getenv("MULTISYNC_SUNBIRD_DEFAULT_CALENDAR")); + + if (!files) + return; + if (!default_calendar) + { + char *basename_ptr = (char*)strdup((char*)g_list_first(files)->data); + char *basename = basename_ptr + strlen(basename_ptr) - 1; + while (basename > basename_ptr && *(basename-1) != '/') + basename--; + default_calendar = g_string_new(basename); + free(basename_ptr); + + printf("WARNING: MULTISYNC_SUNBIRD_DEFAULT_CALENDAR not set, using first calendar: %s", default_calendar->str); + } + + strcpy(keyfile, sync_get_datapath(conn->sync_pair)); + strcat(keyfile, "/mozilla_keyfile.ics"); + + printf("Reading keyfile '%s'...\n", keyfile); + + if (!read_icalendar_file(keyfile, &cached_entries)) + { + printf("WARNING: Keyfile not found!\n"); + } + + printf("Reading all calendars into memory...\n"); + for (cur = g_list_first(files); cur; cur = cur->next) + { + int filesize; + char *filename = (char*)cur->data, *buffer; + FILE* f = fopen(filename, "r"); + if (!f) + { + printf("ERROR: Could not read file: %s\n", filename); + return; + } + + fseek(f, 0, SEEK_END); + filesize = ftell(f); + rewind(f); + buffer = (char*)g_malloc0(filesize+1); + if (!buffer) + { + printf("ERROR: Out of memory\n"); + return; + } + fread(buffer,1,filesize,f); + fclose(f); + buffer[filesize] = 0; /* end of string delimiter */ + + calendars = g_list_append(calendars, g_string_new(buffer)); + } + + for (cur = g_list_first(entries); cur; cur = cur->next) + { + calendar_entry* e = (calendar_entry*)cur->data; + + /* Find name of source file for this object */ + if (e->remote_change_type == SYNC_OBJ_ADDED) + { + /* This is a new object, source file is always the default calendar */ + printf("Scheduling new object %s for adding to default calendar %s\n", e->id->str, default_calendar->str); + e->sourcefile = g_string_new(default_calendar->str); + } else if (e->remote_change_type == SYNC_OBJ_HARDDELETED || e->remote_change_type == SYNC_OBJ_MODIFIED) + { + /* This is an old object, look it up in the key file */ + for (cur2 = g_list_first(cached_entries); cur2; cur2 = cur2->next) + { + calendar_entry* e2 = (calendar_entry*)cur2->data; + + if (strcmp(e2->id->str, e->id->str) == 0) + { + e->sourcefile = g_string_new(e2->sourcefile->str); + printf("Modified/Deleted object %s (%s) has been looked up in keyfile\n", + e->id->str, e->sourcefile->str); + break; + } + } + + if (!e->sourcefile) + { + printf("Warning: Object %s could not be found in keyfile, although change mode is SYNC_OBJ_MODIFIED.\n", + e->id->str); + printf(" Adding the object to the default calendar\n"); + e->sourcefile = g_string_new(default_calendar->str); + } + } + + /* Find correct calendar for this object */ + curfile = g_list_first(files); + curcal = g_list_first(calendars); + while (curfile) + { + char* filepath = (char*)curfile->data; + char* calendarname; + + if (e->sourcefile) + { + calendarname = e->sourcefile->str; + + if (strlen(filepath) >= strlen(calendarname) && + strcmp(calendarname, filepath + strlen(filepath) - strlen(calendarname)) == 0) + { + /* This is the correct calendar */ + break; + } + } + + curfile = curfile->next; + curcal = curcal->next; + } + + if (!curcal) + { + printf("ERROR: Calendar not found for object %s, changes to this object are not synced!\n", e->id->str); + } else if (e->remote_change_type == SYNC_OBJ_ADDED || e->remote_change_type == SYNC_OBJ_MODIFIED || + e->remote_change_type == SYNC_OBJ_HARDDELETED) + { + printf("Adding/Modifying/Deleting object %s (%s) \n", e->id->str, e->sourcefile->str); + + GString* calcontent = (GString*)curcal->data; + patch_calendar(calcontent, e->remote_change_type, e->id->str, e->data ? e->data->str : NULL); + + printf("Done.\n"); + } + } + + printf("Writing all calendars to disk...\n"); + curcal = g_list_first(calendars); + for (cur = g_list_first(files); cur; cur = cur->next) + { + char *textdata = (char*)(((GString*)curcal->data)->str); + char *filename = (char*)cur->data; + FILE* f = fopen(filename, "w"); + + if (!f) + { + printf("ERROR: Could not open file for writing: %s\n", filename); + return; + } + + fwrite(textdata, 1, strlen(textdata), f); + fclose(f); + curcal = curcal->next; + } + + if (calendars) + { + for (cur = g_list_first(calendars); cur; cur = cur->next) + { + GString* s = (GString*)cur->data; + g_string_free(s, TRUE); + } + g_list_free(calendars); + } + + free_string_list(files); + free_events_list(cached_entries); +} + +int get_calendar_changes(GList** changes_ptr, sync_object_type* retnewdbs_ptr, ical_connection* conn) +{ + char keyfile[256]; + GList *entries = NULL, *cached_entries = NULL, *files = NULL, *cur, *cur2; + /* Free previous pending changes, if any */ + if (conn->pending_changes) + { + printf("Warning: Resetting pending changes\n"); + free_events_list(conn->pending_changes); + conn->pending_changes = NULL; + } + + files = get_calendar_files_list(); + if (!files) + return FALSE; + strcpy(keyfile, sync_get_datapath(conn->sync_pair)); strcat(keyfile, "/mozilla_keyfile.ics"); @@ -275,50 +450,96 @@ GList *node; syncobj_modify_result *result; GList *results = NULL; - GString *default_calendar = g_string_new(g_getenv("MULTISYNC_SUNBIRD_DEFAULT_CALENDAR")); - - if (!default_calendar || strlen(default_calendar->str) == 0) - { - printf("WARNING! Default calendar not set. Writing changes to the first calendar found\n"); - printf(" To set the default calendar file, set MULTISYNC_SUNBIRD_DEFAULT_CALENDAR\n"); - } + char* last_modified; for (node = g_list_first(changes); node; node = node->next) { + char* returnuid = NULL; changed_object *obj = (changed_object*)node->data; if (obj->object_type == SYNC_OBJECT_TYPE_CALENDAR) { - printf("syncobj_modify_list got new calendar entry\n"); + calendar_entry* entry = (calendar_entry*)g_malloc0(sizeof(calendar_entry)); - if (obj->change_type == SYNC_OBJ_ADDED) - { - printf("sync_object_modify_list adding entry\n"); - } else if (obj->change_type == SYNC_OBJ_MODIFIED) - { - printf("sync_object_modify_list modifying entry\n"); - } else if (obj->change_type == SYNC_OBJ_HARDDELETED) + if (obj->comp) + entry->data = g_string_new(obj->comp); + else + entry->data = NULL; // no data provided + + if (obj->uid && strlen(obj->uid) > 0) + entry->id = g_string_new(obj->uid); + else { - printf("sync_object_modify_list (hard-)deleting entry\n"); - } else if (obj->change_type == SYNC_OBJ_SOFTDELETED) + char *s, buf[256]; + + /* Create ID */ + entry->id = create_new_uid(); + returnuid = (char*)g_malloc0(strlen(entry->id->str)+1); + if (returnuid) + strcpy(returnuid, entry->id->str); + else + printf("ERROR: Out of memory!\n"); + + printf("Created new UID=%s for entry\n", entry->id->str); + + /* Add UID to VCARD */ + sprintf(buf, "BEGIN:VEVENT\r\nUID:%s", entry->id->str); + s = strstr(entry->data->str, "BEGIN:VEVENT"); + g_string_erase(entry->data, 0, s - entry->data->str + 12); + g_string_insert(entry->data, 0, buf); + } + + entry->last_modified = NULL; // will eventually be set later + entry->sourcefile = NULL; // unknown at this stage + entry->remote_change_type = obj->change_type; + + if (obj->change_type == SYNC_OBJ_HARDDELETED) + entry->deleted = 1; + else + entry->deleted = 0; + + if (obj->removepriority) + entry->remove_priority = g_string_new(obj->removepriority); + else + entry->remove_priority = g_string_new("(none)"); + + if (obj->comp) { - /* FIXME: We should not deleted the object here, but we could */ - /* remember that it has been soft deleted so we don't */ - /* propagate future changes to it. */ + last_modified = sync_get_key_data(obj->comp, "LAST-MODIFIED"); + if (last_modified) + { + entry->last_modified = g_string_new(last_modified); + g_free(last_modified); + } } - } else + + if (!entry->last_modified) + entry->last_modified = g_string_new("(new)"); /* we need a last-modified entry in the key file */ + + conn->pending_changes = g_list_append(conn->pending_changes, entry); + + printf("*** syncobj_modify_list recorded new change ***\n"); + printf("entry->remote_change_type = %i\n", entry->remote_change_type); + if (entry->id) + printf("entry->id = %s\n", entry->id->str); + else + printf("entry has no id\n"); + if (entry->data->str) + printf("entry->data = %s\n", entry->data->str); + else + printf("entry has no data\n"); + } else { printf("Warning: syncobj_modify_list got other object than calendar entry\n"); } - /* We create just a dummy result because we do not really return useful results */ + /* Create result */ result = (syncobj_modify_result*)g_malloc0(sizeof(syncobj_modify_result)); memset(result, 0, sizeof(syncobj_modify_result)); + result->returnuid = returnuid; results = g_list_append(results, result); } - g_string_free(default_calendar, TRUE); - printf("syncobj_modify_list END\n"); sync_set_requestdata(results, conn->sync_pair); @@ -336,7 +557,22 @@ if (conn->pending_changes) { char keyfile[256]; - GList *cached_entries = NULL, *cur; + GList *cached_entries = NULL, *cur, *remote_changes = NULL; + + for (cur = g_list_first(conn->pending_changes); cur; cur = cur->next) + { + calendar_entry *e = (calendar_entry*)cur->data; + if (e->remote_change_type != 0) + remote_changes = g_list_append(remote_changes, e); + } + + if (remote_changes) + { + printf("Writing remote changes to calendars...\n"); + write_changes_to_calendars(remote_changes, conn); + g_list_free(remote_changes); // don't delete contents + printf("Done writing remote changes to calendars.\n"); + } printf("Sync done, remembering changes\n"); Index: sunbird_plugin.h =================================================================== RCS file: /cvsroot/multisync/multisync/plugins/sunbird_plugin/src/Attic/sunbird_plugin.h,v retrieving revision 1.1.2.1 retrieving revision 1.1.2.2 diff -u -d -r1.1.2.1 -r1.1.2.2 --- sunbird_plugin.h 4 Feb 2005 09:50:55 -0000 1.1.2.1 +++ sunbird_plugin.h 6 Mar 2005 01:30:49 -0000 1.1.2.2 @@ -24,6 +24,7 @@ void plugin_init(void); sync_object_type object_types(); int plugin_API_version(void); +GList* get_calendar_files_list(); /* User functions */ int get_calendar_changes(GList** changes_ptr, sync_object_type* retnewdbs_ptr, ical_connection* conn); Index: tools.c =================================================================== RCS file: /cvsroot/multisync/multisync/plugins/sunbird_plugin/src/Attic/tools.c,v retrieving revision 1.1.2.1 retrieving revision 1.1.2.2 diff -u -d -r1.1.2.1 -r1.1.2.2 --- tools.c 4 Feb 2005 09:50:55 -0000 1.1.2.1 +++ tools.c 6 Mar 2005 01:30:49 -0000 1.1.2.2 @@ -25,6 +25,8 @@ #include "tools.h" +static unsigned int uidcounter = 1; + void free_calendar_entry(calendar_entry* e) { g_string_free(e->id, TRUE); @@ -142,6 +144,7 @@ { calendar_entry* new_entry = (calendar_entry*)g_malloc0(sizeof(calendar_entry)); + new_entry->remote_change_type = e->remote_change_type; new_entry->id = g_string_new(e->id->str); new_entry->sourcefile = g_string_new(e->sourcefile->str); new_entry->last_modified = g_string_new(e->last_modified->str); @@ -162,8 +165,6 @@ int read_icalendar_file(char* filename, GList **entries_ptr) { - int next_is_id = 0, next_is_last_modified = 0, next_is_remove_priority = 0; - int next_is_deleted = 0, next_is_sourcefile = 0; int buf_size = 4096, len; char buf[buf_size]; FILE* f; @@ -178,7 +179,7 @@ basename = basename_ptr + strlen(basename_ptr) - 1; while (basename > basename_ptr && *(basename-1) != '/') basename--; - + while (!feof(f)) { if (!fgets(buf, buf_size, f)) @@ -191,37 +192,6 @@ buf[len] = 0; } - if (next_is_id) - { - next_is_id = 0; - cur_entry->id = g_string_new(buf+2); // skip " :" - } - if (next_is_last_modified) - { - next_is_last_modified = 0; - cur_entry->last_modified = g_string_new(buf+2); // skip " :" - } - if (next_is_remove_priority) - { - next_is_remove_priority = 0; - cur_entry->remove_priority = g_string_new(buf+2); // skip " :" - } - if (next_is_sourcefile) - { - /* Only present in key files, not in real calendars */ - next_is_sourcefile = 0; - cur_entry->sourcefile = g_string_new(buf+2); // skip " :" - } - if (next_is_deleted) - { - /* Only present in key files, not in real calendars */ - next_is_deleted = 0; - if (buf[2] == '0') - cur_entry->deleted = 0; - else - cur_entry->deleted = 1; - } - if (strcmp(buf, "BEGIN:VEVENT") == 0) { cur_entry = (calendar_entry*)g_malloc0(sizeof(calendar_entry)); @@ -231,15 +201,55 @@ if (strcmp(buf, "END:VEVENT") == 0) { - /* Last-modified info can be missing, if the item */ - /* was never modified. */ - if (!cur_entry->last_modified) + char *uid, *last_modified, *dtend, *x_sourcefile, *x_deleted, *vcal; + + + g_string_append(cur_entry->data, "\nEND:VEVENT\nEND:VCALENDAR\n"); + vcal = cur_entry->data->str; + + uid = sync_get_key_data(vcal, "UID"); + last_modified = sync_get_key_data(vcal, "LAST-MODIFIED"); + dtend = sync_get_key_data(vcal, "DTEND"); + x_sourcefile = sync_get_key_data(vcal, "X-SOURCEFILE"); + x_deleted = sync_get_key_data(vcal, "X-DELETED"); + + if (uid) + { + cur_entry->id = g_string_new(uid); + g_free(uid); + } + + if (last_modified) + { + cur_entry->last_modified = g_string_new(last_modified); + g_free(last_modified); + } else { + /* default last-modified tag */ cur_entry->last_modified = g_string_new("(new)"); } - g_string_append(cur_entry->data, "\nEND:VEVENT\nEND:VCALENDAR\n"); + if (dtend) + { + cur_entry->remove_priority = g_string_new(dtend); + g_free(dtend); + } + if (x_sourcefile) + { + cur_entry->sourcefile = g_string_new(x_sourcefile); + g_free(x_sourcefile); + } + + if (x_deleted) + { + if (x_deleted[0] == '0') + cur_entry->deleted = 0; + else + cur_entry->deleted = 1; + g_free(x_deleted); + } + *entries_ptr = g_list_append(*entries_ptr, cur_entry); cur_entry = NULL; } @@ -265,17 +275,6 @@ g_string_append(cur_entry->data, buf); } - - if (strcmp(buf, "UID") == 0) - next_is_id = 1; - if (strcmp(buf, "LAST-MODIFIED") == 0) - next_is_last_modified = 1; - if (strcmp(buf, "DTEND") == 0) - next_is_remove_priority = 1; - if (strcmp(buf, "X-SOURCEFILE") == 0) - next_is_sourcefile = 1; - if (strcmp(buf, "X-DELETED") == 0) - next_is_deleted = 1; } } @@ -299,4 +298,94 @@ return p; } +GString* extract_first_vevent(char* data) +{ + GString* g = g_string_new(data); + char *s; + s = strstr(g->str, "BEGIN:VEVENT"); + if (s) + g_string_erase(g, 0, s-g->str); + s = strstr(g->str, "END:VEVENT"); + if (s) + g_string_truncate(g, s-g->str+10); + return g; +} +void patch_calendar(GString* calendar, int change_type, char* id, char* data) +{ + char *line, *begin_vevent = NULL; + char *curpos = calendar->str; + + while (*curpos) + { + char *pos2 = curpos; + while (*pos2 != 0 && *pos2 != '\r' && *pos2 != '\n') + pos2++; + + line = (char*)g_malloc0((pos2-curpos+1)*sizeof(char)); + line[pos2-curpos] = 0; + memcpy(line, curpos, pos2-curpos); + + while (*pos2 == '\r' || *pos2 == '\n') + pos2++; + + if (strcmp(line, "END:VCALENDAR") == 0) + { + /* We must insert new stuff right before this last line */ + if (change_type == SYNC_OBJ_MODIFIED || change_type == SYNC_OBJ_ADDED) + { + int insertpos = curpos - calendar->str; + GString* stripped_data = extract_first_vevent(data); + printf("Adding changed/new event with ID %s to calendar at position %i (len=%i)\n", + id, insertpos, strlen(calendar->str)); + g_string_insert(calendar, insertpos, "\r\n"); + g_string_insert(calendar, insertpos, stripped_data->str); + g_string_free(stripped_data, TRUE); + return; // We are finished + } + } + + if (strcmp(line, "BEGIN:VEVENT") == 0) + begin_vevent = curpos; + + if (strcmp(line, "END:VEVENT") == 0) + { + char* event_id; + int len = curpos+strlen(curpos)-begin_vevent; + char* vcard = (char*)g_malloc0((len+1)*sizeof(char)); + vcard[len] = 0; + memcpy(vcard, begin_vevent, len); + + event_id = sync_get_key_data(vcard, "UID"); + if (event_id) + { + if (strcmp(event_id,id) == 0) + { + int begin_pos = begin_vevent - calendar->str; + int end_pos = (curpos - calendar->str) + strlen(line) + 2; /* Skip additional \r\n */ + printf("Found event with ID %s, removing old instance\n", id); + g_string_erase(calendar, begin_pos, end_pos-begin_pos); + curpos = calendar->str + begin_pos; + } + + g_free(event_id); + } else + { + printf("ERROR: VEVENT has no ID!?\n"); + } + + g_free(vcard); + begin_vevent = NULL; + } + + g_free(line); + curpos = pos2; + } +} + +GString* create_new_uid() +{ + char s[256]; + sprintf(s, "t%ic%i", (int)time(NULL), uidcounter++); + return g_string_new(s); +} Index: Makefile =================================================================== RCS file: /cvsroot/multisync/multisync/plugins/sunbird_plugin/src/Attic/Makefile,v retrieving revision 1.1.2.1 retrieving revision 1.1.2.2 diff -u -d -r1.1.2.1 -r1.1.2.2 --- Makefile 4 Feb 2005 09:50:55 -0000 1.1.2.1 +++ Makefile 6 Mar 2005 01:30:49 -0000 1.1.2.2 @@ -77,7 +77,7 @@ INSTALL_STRIP_PROGRAM = ${SHELL} $(install_sh) -c -s LIBTOOL = $(SHELL) $(top_builddir)/libtool LN_S = ln -s -MULTISYNC_VERSION = 0.82 +MULTISYNC_VERSION = OBJDUMP = @OBJDUMP@ PACKAGE = sunbird_plugin PACKAGE_CFLAGS = -DORBIT2=1 -pthread -I/usr/include/libgnomeui-2.0 -I/usr/include/libgnome-2.0 -I/usr/include/libgnomecanvas-2.0 -I/usr/include/gtk-2.0 -I/usr/include/libart-2.0 -I/usr/include/gconf/2 -I/usr/include/libbonoboui-2.0 -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/orbit-2.0 -I/usr/include/libbonobo-2.0 -I/usr/include/gnome-vfs-2.0 -I/usr/lib/gnome-vfs-2.0/include -I/usr/include/bonobo-activation-2.0 -I/usr/include/pango-1.0 -I/usr/include/freetype2 -I/usr/lib/gtk-2.0/include -I/usr/include/atk-1.0 -I/usr/X11R6/include -I/usr/include/libxml2 |