diff options
-rw-r--r-- | calendar/ChangeLog | 17 | ||||
-rw-r--r-- | calendar/GnomeCal.idl | 20 | ||||
-rw-r--r-- | calendar/TODO | 3 | ||||
-rw-r--r-- | calendar/cal-util/calobj.c | 17 | ||||
-rw-r--r-- | calendar/calendar-pilot-sync.c | 304 | ||||
-rw-r--r-- | calendar/calendar.c | 32 | ||||
-rw-r--r-- | calendar/calendar.h | 2 | ||||
-rw-r--r-- | calendar/calobj.c | 17 | ||||
-rw-r--r-- | calendar/corba-cal-factory.c | 4 | ||||
-rw-r--r-- | calendar/corba-cal.c | 59 | ||||
-rw-r--r-- | calendar/eventedit.c | 4 | ||||
-rw-r--r-- | calendar/gui/GnomeCal.idl | 20 | ||||
-rw-r--r-- | calendar/gui/calendar-pilot-sync.c | 304 | ||||
-rw-r--r-- | calendar/gui/calendar.c | 32 | ||||
-rw-r--r-- | calendar/gui/calendar.h | 2 | ||||
-rw-r--r-- | calendar/gui/corba-cal-factory.c | 4 | ||||
-rw-r--r-- | calendar/gui/corba-cal.c | 59 | ||||
-rw-r--r-- | calendar/gui/eventedit.c | 4 | ||||
-rw-r--r-- | calendar/pcs/calobj.c | 17 |
19 files changed, 833 insertions, 88 deletions
diff --git a/calendar/ChangeLog b/calendar/ChangeLog index 8d7fed8098..c6e61d4ee0 100644 --- a/calendar/ChangeLog +++ b/calendar/ChangeLog @@ -1,10 +1,23 @@ 1999-07-28 Miguel de Icaza <miguel@gnu.org> - * calendar-pilot-sync.c: New file. Implements PalmPilot - syncronization with the Gnome Calendar. + * calobj.c (ical_gen_uid): Use the hostname, not the domain name. + (ical_gen_uid): Add a serial number. Isodates can be small. + + * corba-cal.c (cal_repo_update_pilot_id): New method to update the + pilot status. + (cal_repo_get_updated_objects): New method. Returns a list of + modified and not-sycned objects + + * calendar-pilot-sync.c (sync_cal_to_pilot): New function to sync + from the GnomeCalendar to the pilot. + (sync_object_to_pilot): Sync a single event to the pilot. + (try_alarm): Alarm syncing code. 1999-07-27 Miguel de Icaza <miguel@gnu.org> + * calendar-pilot-sync.c: New file. Implements PalmPilot + syncronization with the Gnome Calendar. + * calobj.c (ical_object_new_from_string): New function. Creates an iCalObject from a vCalendar string that is supposed to contain only one vEvent. diff --git a/calendar/GnomeCal.idl b/calendar/GnomeCal.idl index bfeb502518..5c158284a3 100644 --- a/calendar/GnomeCal.idl +++ b/calendar/GnomeCal.idl @@ -11,7 +11,7 @@ module GNOME { * @uid: Unique Identifier for the object * * Returns a vCalendar object for the object - * that matches the UID @uid + * that matches the UID @uid. */ string get_object (in string uid) raises (NotFound); @@ -44,6 +44,23 @@ module GNOME { void update_object (in string uid, in string object); /* + * update_pilot_id: + * @uid: Unique identifier for the event we want to update + * @pilot_id: new ID assigned by the pilot + * @pilot_status: Status to flag the event with + */ + void update_pilot_id (in string uid, in long pilot_id, in long pilot_status) + raises (NotFound); + + /* + * get_updated_objects: + * + * Returns a vCalendar with all the objects that have been + * modified since the last Pilot Sync + */ + string get_updated_objects (); + + /* * done: * * Informs the calendar that we are done using it, @@ -53,3 +70,4 @@ module GNOME { }; }; }; + diff --git a/calendar/TODO b/calendar/TODO index bb964e908d..822ec2eb35 100644 --- a/calendar/TODO +++ b/calendar/TODO @@ -1,8 +1,11 @@ Pilot: * Better support for untimed events (we have none now). + * Add syncing from Desktop to Pilot. +* Hash objects based on their UIDs. + BUGS: - Recurrence end date is wrong. An event that repeats daily will not diff --git a/calendar/cal-util/calobj.c b/calendar/cal-util/calobj.c index 08c8d8c63a..f1bec05c2b 100644 --- a/calendar/cal-util/calobj.c +++ b/calendar/cal-util/calobj.c @@ -18,23 +18,28 @@ static char * ical_gen_uid (void) { - static char *domain; + static char *hostname; time_t t = time (NULL); + static int serial; - if (!domain){ + if (!hostname){ char buffer [128]; - getdomainname (buffer, sizeof (buffer)-1); - domain = g_strdup (domain); + gethostname (buffer, sizeof (buffer)-1); + if (hostname) + hostname = g_strdup (hostname); + else + hostname = g_strdup ("localhost"); } return g_strdup_printf ( - "%s-%d-%d-%d@%s", + "%s-%d-%d-%d-%d@%s", isodate_from_time_t (t), getpid (), getgid (), getppid (), - domain); + serial++, + hostname); } iCalObject * diff --git a/calendar/calendar-pilot-sync.c b/calendar/calendar-pilot-sync.c index 6ed92d540a..bbacd312eb 100644 --- a/calendar/calendar-pilot-sync.c +++ b/calendar/calendar-pilot-sync.c @@ -31,11 +31,28 @@ char *pilot_port = "/dev/pilot"; CORBA_Environment ev; +/* Our pi-socket address where we connect to */ struct pi_sockaddr addr; +/* The Pilot DB identifier for DateBook */ +int db; + +/* True if you want to dump the flags bits from the records */ +int debug_attrs = 0; + +int only_desktop_to_pilot = 0; + +int only_pilot_to_desktop = 0; + const struct poptOption calendar_sync_options [] = { { "pilot", 0, POPT_ARG_STRING, &pilot_port, 0, N_("Specifies the port on which the Pilot is"), N_("PORT") }, + { "debug-attrs", 0, POPT_ARG_INT, &debug_attrs, 0, + N_("If you want to debug the attributes on records"), NULL }, + { "only-desktop", 0, POPT_ARG_INT, &only_desktop_to_pilot, 0, + N_("Only syncs from desktop to pilot"), NULL }, + { "only-pilot", 0, POPT_ARG_INT, &only_pilot_to_desktop, 0, + N_("Only syncs from pilot to desktop"), NULL }, { NULL, '\0', 0, NULL, 0 } }; @@ -68,7 +85,6 @@ static GNOME_Calendar_Repository locate_calendar_server (void) { GNOME_Calendar_Repository repo; - GNOME_stringlist list; repo = goad_server_activate_with_id ( NULL, "IDL:GNOME:Calendar:Repository:1.0", @@ -112,6 +128,7 @@ update_record (GNOME_Calendar_Repository repo, int id, struct Appointment *a, in g_get_user_name (), a->description ? a->description : ""); + printf ("requesting %d [%s]\n", id, a->description); vcal_string = GNOME_Calendar_Repository_get_object_by_pilot_id (repo, id, &ev); if (ev._major == CORBA_USER_EXCEPTION){ @@ -124,12 +141,14 @@ update_record (GNOME_Calendar_Repository repo, int id, struct Appointment *a, in obj->related = NULL; obj->pilot_id = id; obj->pilot_status = ICAL_PILOT_SYNC_NONE; - printf (_("Object did not exist, creating a new one")); - } else + printf (_("\tObject did not exist, creating a new one\n")); + } else { + printf ("\tFound\n"); obj = ical_object_new_from_string (vcal_string); + } if (obj->pilot_status == ICAL_PILOT_SYNC_MOD){ - printf (_("Object has been modified on desktop and on the pilot, desktop takes precedence")); + printf (_("\tObject has been modified on desktop and on the pilot, desktop takes precedence\n")); ical_object_destroy (obj); return; } @@ -261,12 +280,220 @@ update_record (GNOME_Calendar_Repository repo, int id, struct Appointment *a, in ical_object_destroy (obj); } +/* + * Sets the alarm for Appointment based on @alarm + */ +static int +try_alarm (CalendarAlarm *alarm, struct Appointment *a) +{ + if (!alarm->enabled) + return 0; + + a->advance = alarm->count; + switch (alarm->type){ + case ALARM_DAYS: + a->advanceUnits = advDays; + break; + + case ALARM_HOURS: + a->advanceUnits = advHours; + break; + + case ALARM_MINUTES: + a->advanceUnits = advMinutes; + break; + + default: + return 0; + } + a->alarm = 1; + return 1; +} + +static void +sync_object_to_pilot (GNOME_Calendar_Repository repo, iCalObject *obj, int pilot_fd) +{ + char buffer [65536]; + struct Appointment *a; + int wd, i, idx, attr, cat, rec_len; + recordid_t new_id; + GList *l; + + a = g_new0 (struct Appointment, 1); + + attr = 0; + cat = 0; + idx = 0; + + if (obj->pilot_id){ + rec_len = dlp_ReadRecordById (pilot_fd, db, obj->pilot_id, + buffer, &idx, &rec_len, &attr, &cat); + + if (rec_len > 0) + unpack_Appointment (a, buffer, rec_len); + } + /* a contains the appointment either cleared or with the data from the Pilot */ + a->begin = *localtime (&obj->dtstart); + a->end = *localtime (&obj->dtend); + + /* FIXME: add support for timeless */ + a->event = 0; + + /* Alarms, try the various ones. Probably we should only do Audio? + * Otherwise going gnomecal->pilot->gnomecal would get the gnomecal + * with *possibly* an alarm that was not originally defined. + */ + a->alarm = 0; + if (try_alarm (&obj->aalarm, a) == 0) + if (try_alarm (&obj->dalarm, a) == 0) + try_alarm (&obj->palarm, a); + + /* Recurrence */ + if (obj->recur){ + a->repeatFrequency = obj->recur->interval; + + switch (obj->recur->type){ + case RECUR_MONTHLY_BY_POS: + a->repeatType = repeatMonthlyByDay; + a->repeatFrequency = obj->recur->u.month_pos; + a->repeatDay = obj->recur->weekday * 7; + break; + + case RECUR_MONTHLY_BY_DAY: + a->repeatType = repeatMonthlyByDate; + a->repeatFrequency = obj->recur->u.month_day; + break; + + case RECUR_YEARLY_BY_DAY: + a->repeatType = repeatYearly; + break; + + case RECUR_WEEKLY: + for (wd = 0; wd < 7; wd++) + if (obj->recur->weekday & (1 << wd)) + a->repeatDays [wd] = 1; + a->repeatType = repeatWeekly; + break; + case RECUR_DAILY: + + default: + a->repeatType = repeatNone; + break; + } + a->repeatEnd = *localtime (&obj->recur->_enddate); + } + + /* + * Pilot uses a repeat-daily for a multi-day event, adjust for that case + */ + if ((a->end.tm_mday != a->begin.tm_mday) || + (a->end.tm_mon != a->begin.tm_mon) || + (a->end.tm_year != a->begin.tm_year)){ + + a->repeatEnd = a->end; + a->repeatForever = 0; + a->repeatFrequency = 0; + a->repeatType = repeatDaily; + a->end.tm_mday = a->begin.tm_mday; + a->end.tm_mon = a->begin.tm_mon; + a->end.tm_year = a->begin.tm_year; + } + + /* + * Exceptions + */ + a->exceptions = g_list_length (obj->exdate); + a->exception = (struct tm *) malloc (sizeof (struct tm) * a->exceptions); + for (i = 0, l = obj->exdate; l; l = l->next, i++){ + time_t *exdate = l->data; + + a->exception [i] = *localtime (exdate); + } + + /* + * Description and note. + * + * We use strdup to be correct. free_Appointment assumes we used + * malloc. + */ + if (obj->comment) + a->note = strdup (obj->comment); + else + a->note = 0; + + if (obj->summary) + a->description = strdup (obj->summary); + else + a->description = strdup (_("No description")); + + if (strcmp (obj->class, "PUBLIC") != 0) + attr |= dlpRecAttrSecret; + else + attr &= ~dlpRecAttrSecret; + + /* + * Mark as archived. FIXME: is this the case? + */ + attr |= dlpRecAttrArchived; + + /* + * Send the appointment to the pilot + */ + rec_len = pack_Appointment (a, buffer, sizeof (buffer)); + attr &= ~dlpRecAttrDirty; + + printf ("Status=%d\n", + dlp_WriteRecord ( + pilot_fd, db, attr, + obj->pilot_id, cat, buffer, rec_len, &new_id)); + GNOME_Calendar_Repository_update_pilot_id (repo, obj->uid, new_id, ICAL_PILOT_SYNC_NONE, &ev); + + free_Appointment (a); + g_free (a); +} + +static void +sync_cal_to_pilot (GNOME_Calendar_Repository repo, Calendar *cal, int pilot_fd) +{ + GList *l; + + for (l = cal->events; l; l = l->next){ + iCalObject *obj = l->data; + + if (obj->pilot_status != ICAL_PILOT_SYNC_MOD){ + g_warning ("Strange, we were supposed to get only a dirty object"); + continue; + } + + sync_object_to_pilot (repo, obj, pilot_fd); + } +} + +static void +dump_attr (int flags) +{ + if (flags & dlpRecAttrDeleted) + fprintf(stderr, " Deleted"); + if (flags & dlpRecAttrDirty) + fprintf(stderr, " Dirty"); + if (flags & dlpRecAttrBusy) + fprintf(stderr, " Busy"); + if (flags & dlpRecAttrSecret) + fprintf(stderr, " Secret"); + if (flags & dlpRecAttrArchived) + fprintf(stderr, " Archive"); + fprintf (stderr, "\n"); +} + static void sync_pilot (GNOME_Calendar_Repository repo, int pilot_fd) { struct PilotUser user_info; - int db,record; + int record; unsigned char buffer [65536]; + Calendar *dirty_cal; + char *vcalendar_string; + char *error; printf (_("Syncing with the pilot...")); dlp_ReadUserInfo (pilot_fd, &user_info); @@ -285,36 +512,59 @@ sync_pilot (GNOME_Calendar_Repository repo, int pilot_fd) * 1. Pull all the records from the Pilot, and make any updates * required on the desktop side */ - for (record = 0;; record++){ - struct Appointment a; - int rec_len, attr, size; - recordid_t id; - - rec_len = dlp_ReadRecordByIndex (pilot_fd, db, record, buffer, &id, &size, &attr, 0); - - if (rec_len < 0) - break; + if (!only_desktop_to_pilot){ + for (record = 0;; record++){ + struct Appointment a; + int rec_len, attr, size; + recordid_t id; + + rec_len = dlp_ReadRecordByIndex ( + pilot_fd, db, + record, buffer, &id, &size, &attr, 0); - printf ("processing record %d\n", record); - unpack_Appointment (&a, buffer, rec_len); - - /* If the object was deleted, remove it from the database */ - if (attr & dlpRecAttrDeleted){ - delete_record (repo, id); - continue; - } + if (rec_len < 0) + break; + + printf ("processing record %d\n", record); + unpack_Appointment (&a, buffer, rec_len); + + if (debug_attrs) + dump_attr (attr); + + /* If the object was deleted, remove it from the database */ + if (attr & dlpRecAttrDeleted){ + printf ("Deleteing\n"); + delete_record (repo, id); + free_Appointment (&a); + continue; + } - if (attr & dlpRecAttrDirty){ - printf ("updating record\n"); - update_record (repo, id, &a, attr); + if (attr & dlpRecAttrArchived) + continue; + + if (attr & dlpRecAttrDirty){ + printf ("updating record\n"); + update_record (repo, id, &a, attr); + } + + free_Appointment (&a); } - - free_Appointment (&a); } + /* * 2. Pull all the records from the Calendar, and move any new items * to the pilot */ + if (!only_pilot_to_desktop){ + vcalendar_string = GNOME_Calendar_Repository_get_updated_objects (repo, &ev); + dirty_cal = calendar_new ("Temporal"); + error = calendar_load_from_memory (dirty_cal, vcalendar_string); + if (!error) + sync_cal_to_pilot (repo, dirty_cal, pilot_fd); + calendar_destroy (dirty_cal); + } + + dlp_CloseDB (pilot_fd, db); dlp_AddSyncLogEntry (pilot_fd, _("Synced DateBook from Pilot to GnomeCal")); pi_close (pilot_fd); diff --git a/calendar/calendar.c b/calendar/calendar.c index b67f875fdc..30e4e0168c 100644 --- a/calendar/calendar.c +++ b/calendar/calendar.c @@ -72,7 +72,7 @@ add_object_alarms (iCalObject *obj, time_t start, time_t end, void *closure) #define max(a,b) ((a > b) ? a : b) -void +static void ical_object_try_alarms (iCalObject *obj) { int ao, po, od, mo; @@ -169,7 +169,7 @@ calendar_destroy (Calendar *cal) g_free (cal); } -char * +static char * ice (time_t t) { static char buffer [100]; @@ -323,6 +323,34 @@ calendar_load (Calendar *cal, char *fname) return NULL; } +/* + * calendar_load_from_memory: + * @cal: calendar on which we load the information + * @buffer: A buffer that contains a vCalendar file + * + * Loads the information from the vCalendar information in @buffer + * into the Calendar + */ +char * +calendar_load_from_memory (Calendar *cal, const char *buffer) +{ + VObject *vcal; + + g_return_val_if_fail (buffer != NULL, NULL); + + cal->filename = g_strdup ("memory-based-calendar"); + vcal = Parse_MIME (buffer, strlen (buffer)); + if (!vcal) + return "Could not load the calendar"; + + cal->file_time = time (NULL); + calendar_load_from_vobject (cal, vcal); + cleanVObject (vcal); + cleanStrTbl (); + + return NULL; +} + static VObject * vcalendar_create_from_calendar (Calendar *cal) { diff --git a/calendar/calendar.h b/calendar/calendar.h index 2ea2753057..aa25fba67c 100644 --- a/calendar/calendar.h +++ b/calendar/calendar.h @@ -44,6 +44,8 @@ char *calendar_get_as_vcal_string (Calendar *cal); char *calendar_string_from_object (iCalObject *object); char *calendar_load (Calendar *cal, char *fname); +char *calendar_load_from_memory (Calendar *cal, const char *buffer); +void calendar_load_from_vobject (Calendar *cal, VObject *vcal); void calendar_save (Calendar *cal, char *fname); void calendar_add_object (Calendar *cal, iCalObject *obj); void calendar_remove_object (Calendar *cal, iCalObject *obj); diff --git a/calendar/calobj.c b/calendar/calobj.c index 08c8d8c63a..f1bec05c2b 100644 --- a/calendar/calobj.c +++ b/calendar/calobj.c @@ -18,23 +18,28 @@ static char * ical_gen_uid (void) { - static char *domain; + static char *hostname; time_t t = time (NULL); + static int serial; - if (!domain){ + if (!hostname){ char buffer [128]; - getdomainname (buffer, sizeof (buffer)-1); - domain = g_strdup (domain); + gethostname (buffer, sizeof (buffer)-1); + if (hostname) + hostname = g_strdup (hostname); + else + hostname = g_strdup ("localhost"); } return g_strdup_printf ( - "%s-%d-%d-%d@%s", + "%s-%d-%d-%d-%d@%s", isodate_from_time_t (t), getpid (), getgid (), getppid (), - domain); + serial++, + hostname); } iCalObject * diff --git a/calendar/corba-cal-factory.c b/calendar/corba-cal-factory.c index 49a2c5ac76..c10929376b 100644 --- a/calendar/corba-cal-factory.c +++ b/calendar/corba-cal-factory.c @@ -35,7 +35,7 @@ static GNOME_GenericFactory calendar_factory; static CORBA_boolean calendar_supports (PortableServer_Servant servant, - const CORBA_char * obj_goad_id, + CORBA_char * obj_goad_id, CORBA_Environment * ev) { if (strcmp (obj_goad_id, "IDL:GNOME:Calendar:Repository:1.0") == 0) @@ -46,7 +46,7 @@ calendar_supports (PortableServer_Servant servant, static CORBA_Object calendar_create_object (PortableServer_Servant servant, - const CORBA_char *goad_id, + CORBA_char *goad_id, const GNOME_stringlist *params, CORBA_Environment *ev) { diff --git a/calendar/corba-cal.c b/calendar/corba-cal.c index d78685bf90..8f92057d42 100644 --- a/calendar/corba-cal.c +++ b/calendar/corba-cal.c @@ -81,6 +81,7 @@ cal_repo_get_object_by_pilot_id (PortableServer_Servant servant, CORBA_char *ret; obj = calendar_object_find_by_pilot (gcal->cal, pilot_id); + printf ("Looking for [%d]\n", pilot_id); if (obj == NULL){ CORBA_exception_set (ev, CORBA_USER_EXCEPTION, @@ -148,6 +149,7 @@ cal_repo_update_object (PortableServer_Servant servant, obj = calendar_object_find_event (gcal->cal, uid); if (obj != NULL){ + printf ("ELIMINATING: %s -> %s\n", obj->uid, new_object->uid); calendar_remove_object (gcal->cal, obj); } @@ -155,6 +157,60 @@ cal_repo_update_object (PortableServer_Servant servant, } static void +cal_repo_update_pilot_id (PortableServer_Servant servant, + CORBA_char *uid, + CORBA_long pilot_id, + CORBA_long pilot_status, + CORBA_Environment *ev) +{ + GnomeCalendar *gcal = gnomecal_from_servant (servant); + iCalObject *obj; + + obj = calendar_object_find_event (gcal->cal, uid); + if (obj == NULL){ + CORBA_exception_set ( + ev, + CORBA_USER_EXCEPTION, + ex_GNOME_Calendar_Repository_NotFound, + ""); + return; + } + + obj->pilot_id = pilot_id; + obj->pilot_status = pilot_status; +} + +static CORBA_char * +cal_repo_get_updated_objects (PortableServer_Servant servant, + CORBA_Environment *ev) +{ + GnomeCalendar *gcal = gnomecal_from_servant (servant); + Calendar *dirty_cal; + GList *l; + CORBA_char *res; + char *str; + + dirty_cal = calendar_new ("Temporal"); + + for (l = gcal->cal->events; l; l = l->next){ + iCalObject *obj = l->data; + + if (obj->pilot_status != ICAL_PILOT_SYNC_MOD) + continue; + + obj = ical_object_duplicate (l->data); + + calendar_add_object (dirty_cal, obj); + } + str = calendar_get_as_vcal_string (dirty_cal); + res = CORBA_string_dup (str); + g_free (str); + calendar_destroy (dirty_cal); + + return res; +} + +static void cal_repo_done (PortableServer_Servant servant, CORBA_Environment *ev) { @@ -171,6 +227,9 @@ init_calendar_repo_class (void) calendar_repository_epv.get_id_from_pilot_id = cal_repo_get_id_from_pilot_id; calendar_repository_epv.delete_object = cal_repo_delete_object; calendar_repository_epv.update_object = cal_repo_update_object; + calendar_repository_epv.get_updated_objects = cal_repo_get_updated_objects; + calendar_repository_epv.update_pilot_id = cal_repo_update_pilot_id; + calendar_repository_epv.done = cal_repo_done; calendar_repository_vepv.GNOME_Calendar_Repository_epv = diff --git a/calendar/eventedit.c b/calendar/eventedit.c index a73775b375..8a36b94638 100644 --- a/calendar/eventedit.c +++ b/calendar/eventedit.c @@ -59,7 +59,7 @@ event_editor_class_init (EventEditorClass *class) object_class->destroy = event_editor_destroy; } -GtkWidget * +static GtkWidget * adjust (GtkWidget *w, gfloat x, gfloat y, gfloat xs, gfloat ys) { GtkWidget *a = gtk_alignment_new (x, y, xs, ys); @@ -432,7 +432,7 @@ ee_classification_widgets (EventEditor *ee) * Retrieves the information from the CalendarAlarm widgets and stores them * on the CalendarAlarm generic values */ -void +static void ee_store_alarm (CalendarAlarm *alarm, enum AlarmType type) { GtkWidget *item; diff --git a/calendar/gui/GnomeCal.idl b/calendar/gui/GnomeCal.idl index bfeb502518..5c158284a3 100644 --- a/calendar/gui/GnomeCal.idl +++ b/calendar/gui/GnomeCal.idl @@ -11,7 +11,7 @@ module GNOME { * @uid: Unique Identifier for the object * * Returns a vCalendar object for the object - * that matches the UID @uid + * that matches the UID @uid. */ string get_object (in string uid) raises (NotFound); @@ -44,6 +44,23 @@ module GNOME { void update_object (in string uid, in string object); /* + * update_pilot_id: + * @uid: Unique identifier for the event we want to update + * @pilot_id: new ID assigned by the pilot + * @pilot_status: Status to flag the event with + */ + void update_pilot_id (in string uid, in long pilot_id, in long pilot_status) + raises (NotFound); + + /* + * get_updated_objects: + * + * Returns a vCalendar with all the objects that have been + * modified since the last Pilot Sync + */ + string get_updated_objects (); + + /* * done: * * Informs the calendar that we are done using it, @@ -53,3 +70,4 @@ module GNOME { }; }; }; + diff --git a/calendar/gui/calendar-pilot-sync.c b/calendar/gui/calendar-pilot-sync.c index 6ed92d540a..bbacd312eb 100644 --- a/calendar/gui/calendar-pilot-sync.c +++ b/calendar/gui/calendar-pilot-sync.c @@ -31,11 +31,28 @@ char *pilot_port = "/dev/pilot"; CORBA_Environment ev; +/* Our pi-socket address where we connect to */ struct pi_sockaddr addr; +/* The Pilot DB identifier for DateBook */ +int db; + +/* True if you want to dump the flags bits from the records */ +int debug_attrs = 0; + +int only_desktop_to_pilot = 0; + +int only_pilot_to_desktop = 0; + const struct poptOption calendar_sync_options [] = { { "pilot", 0, POPT_ARG_STRING, &pilot_port, 0, N_("Specifies the port on which the Pilot is"), N_("PORT") }, + { "debug-attrs", 0, POPT_ARG_INT, &debug_attrs, 0, + N_("If you want to debug the attributes on records"), NULL }, + { "only-desktop", 0, POPT_ARG_INT, &only_desktop_to_pilot, 0, + N_("Only syncs from desktop to pilot"), NULL }, + { "only-pilot", 0, POPT_ARG_INT, &only_pilot_to_desktop, 0, + N_("Only syncs from pilot to desktop"), NULL }, { NULL, '\0', 0, NULL, 0 } }; @@ -68,7 +85,6 @@ static GNOME_Calendar_Repository locate_calendar_server (void) { GNOME_Calendar_Repository repo; - GNOME_stringlist list; repo = goad_server_activate_with_id ( NULL, "IDL:GNOME:Calendar:Repository:1.0", @@ -112,6 +128,7 @@ update_record (GNOME_Calendar_Repository repo, int id, struct Appointment *a, in g_get_user_name (), a->description ? a->description : ""); + printf ("requesting %d [%s]\n", id, a->description); vcal_string = GNOME_Calendar_Repository_get_object_by_pilot_id (repo, id, &ev); if (ev._major == CORBA_USER_EXCEPTION){ @@ -124,12 +141,14 @@ update_record (GNOME_Calendar_Repository repo, int id, struct Appointment *a, in obj->related = NULL; obj->pilot_id = id; obj->pilot_status = ICAL_PILOT_SYNC_NONE; - printf (_("Object did not exist, creating a new one")); - } else + printf (_("\tObject did not exist, creating a new one\n")); + } else { + printf ("\tFound\n"); obj = ical_object_new_from_string (vcal_string); + } if (obj->pilot_status == ICAL_PILOT_SYNC_MOD){ - printf (_("Object has been modified on desktop and on the pilot, desktop takes precedence")); + printf (_("\tObject has been modified on desktop and on the pilot, desktop takes precedence\n")); ical_object_destroy (obj); return; } @@ -261,12 +280,220 @@ update_record (GNOME_Calendar_Repository repo, int id, struct Appointment *a, in ical_object_destroy (obj); } +/* + * Sets the alarm for Appointment based on @alarm + */ +static int +try_alarm (CalendarAlarm *alarm, struct Appointment *a) +{ + if (!alarm->enabled) + return 0; + + a->advance = alarm->count; + switch (alarm->type){ + case ALARM_DAYS: + a->advanceUnits = advDays; + break; + + case ALARM_HOURS: + a->advanceUnits = advHours; + break; + + case ALARM_MINUTES: + a->advanceUnits = advMinutes; + break; + + default: + return 0; + } + a->alarm = 1; + return 1; +} + +static void +sync_object_to_pilot (GNOME_Calendar_Repository repo, iCalObject *obj, int pilot_fd) +{ + char buffer [65536]; + struct Appointment *a; + int wd, i, idx, attr, cat, rec_len; + recordid_t new_id; + GList *l; + + a = g_new0 (struct Appointment, 1); + + attr = 0; + cat = 0; + idx = 0; + + if (obj->pilot_id){ + rec_len = dlp_ReadRecordById (pilot_fd, db, obj->pilot_id, + buffer, &idx, &rec_len, &attr, &cat); + + if (rec_len > 0) + unpack_Appointment (a, buffer, rec_len); + } + /* a contains the appointment either cleared or with the data from the Pilot */ + a->begin = *localtime (&obj->dtstart); + a->end = *localtime (&obj->dtend); + + /* FIXME: add support for timeless */ + a->event = 0; + + /* Alarms, try the various ones. Probably we should only do Audio? + * Otherwise going gnomecal->pilot->gnomecal would get the gnomecal + * with *possibly* an alarm that was not originally defined. + */ + a->alarm = 0; + if (try_alarm (&obj->aalarm, a) == 0) + if (try_alarm (&obj->dalarm, a) == 0) + try_alarm (&obj->palarm, a); + + /* Recurrence */ + if (obj->recur){ + a->repeatFrequency = obj->recur->interval; + + switch (obj->recur->type){ + case RECUR_MONTHLY_BY_POS: + a->repeatType = repeatMonthlyByDay; + a->repeatFrequency = obj->recur->u.month_pos; + a->repeatDay = obj->recur->weekday * 7; + break; + + case RECUR_MONTHLY_BY_DAY: + a->repeatType = repeatMonthlyByDate; + a->repeatFrequency = obj->recur->u.month_day; + break; + + case RECUR_YEARLY_BY_DAY: + a->repeatType = repeatYearly; + break; + + case RECUR_WEEKLY: + for (wd = 0; wd < 7; wd++) + if (obj->recur->weekday & (1 << wd)) + a->repeatDays [wd] = 1; + a->repeatType = repeatWeekly; + break; + case RECUR_DAILY: + + default: + a->repeatType = repeatNone; + break; + } + a->repeatEnd = *localtime (&obj->recur->_enddate); + } + + /* + * Pilot uses a repeat-daily for a multi-day event, adjust for that case + */ + if ((a->end.tm_mday != a->begin.tm_mday) || + (a->end.tm_mon != a->begin.tm_mon) || + (a->end.tm_year != a->begin.tm_year)){ + + a->repeatEnd = a->end; + a->repeatForever = 0; + a->repeatFrequency = 0; + a->repeatType = repeatDaily; + a->end.tm_mday = a->begin.tm_mday; + a->end.tm_mon = a->begin.tm_mon; + a->end.tm_year = a->begin.tm_year; + } + + /* + * Exceptions + */ + a->exceptions = g_list_length (obj->exdate); + a->exception = (struct tm *) malloc (sizeof (struct tm) * a->exceptions); + for (i = 0, l = obj->exdate; l; l = l->next, i++){ + time_t *exdate = l->data; + + a->exception [i] = *localtime (exdate); + } + + /* + * Description and note. + * + * We use strdup to be correct. free_Appointment assumes we used + * malloc. + */ + if (obj->comment) + a->note = strdup (obj->comment); + else + a->note = 0; + + if (obj->summary) + a->description = strdup (obj->summary); + else + a->description = strdup (_("No description")); + + if (strcmp (obj->class, "PUBLIC") != 0) + attr |= dlpRecAttrSecret; + else + attr &= ~dlpRecAttrSecret; + + /* + * Mark as archived. FIXME: is this the case? + */ + attr |= dlpRecAttrArchived; + + /* + * Send the appointment to the pilot + */ + rec_len = pack_Appointment (a, buffer, sizeof (buffer)); + attr &= ~dlpRecAttrDirty; + + printf ("Status=%d\n", + dlp_WriteRecord ( + pilot_fd, db, attr, + obj->pilot_id, cat, buffer, rec_len, &new_id)); + GNOME_Calendar_Repository_update_pilot_id (repo, obj->uid, new_id, ICAL_PILOT_SYNC_NONE, &ev); + + free_Appointment (a); + g_free (a); +} + +static void +sync_cal_to_pilot (GNOME_Calendar_Repository repo, Calendar *cal, int pilot_fd) +{ + GList *l; + + for (l = cal->events; l; l = l->next){ + iCalObject *obj = l->data; + + if (obj->pilot_status != ICAL_PILOT_SYNC_MOD){ + g_warning ("Strange, we were supposed to get only a dirty object"); + continue; + } + + sync_object_to_pilot (repo, obj, pilot_fd); + } +} + +static void +dump_attr (int flags) +{ + if (flags & dlpRecAttrDeleted) + fprintf(stderr, " Deleted"); + if (flags & dlpRecAttrDirty) + fprintf(stderr, " Dirty"); + if (flags & dlpRecAttrBusy) + fprintf(stderr, " Busy"); + if (flags & dlpRecAttrSecret) + fprintf(stderr, " Secret"); + if (flags & dlpRecAttrArchived) + fprintf(stderr, " Archive"); + fprintf (stderr, "\n"); +} + static void sync_pilot (GNOME_Calendar_Repository repo, int pilot_fd) { struct PilotUser user_info; - int db,record; + int record; unsigned char buffer [65536]; + Calendar *dirty_cal; + char *vcalendar_string; + char *error; printf (_("Syncing with the pilot...")); dlp_ReadUserInfo (pilot_fd, &user_info); @@ -285,36 +512,59 @@ sync_pilot (GNOME_Calendar_Repository repo, int pilot_fd) * 1. Pull all the records from the Pilot, and make any updates * required on the desktop side */ - for (record = 0;; record++){ - struct Appointment a; - int rec_len, attr, size; - recordid_t id; - - rec_len = dlp_ReadRecordByIndex (pilot_fd, db, record, buffer, &id, &size, &attr, 0); - - if (rec_len < 0) - break; + if (!only_desktop_to_pilot){ + for (record = 0;; record++){ + struct Appointment a; + int rec_len, attr, size; + recordid_t id; + + rec_len = dlp_ReadRecordByIndex ( + pilot_fd, db, + record, buffer, &id, &size, &attr, 0); - printf ("processing record %d\n", record); - unpack_Appointment (&a, buffer, rec_len); - - /* If the object was deleted, remove it from the database */ - if (attr & dlpRecAttrDeleted){ - delete_record (repo, id); - continue; - } + if (rec_len < 0) + break; + + printf ("processing record %d\n", record); + unpack_Appointment (&a, buffer, rec_len); + + if (debug_attrs) + dump_attr (attr); + + /* If the object was deleted, remove it from the database */ + if (attr & dlpRecAttrDeleted){ + printf ("Deleteing\n"); + delete_record (repo, id); + free_Appointment (&a); + continue; + } - if (attr & dlpRecAttrDirty){ - printf ("updating record\n"); - update_record (repo, id, &a, attr); + if (attr & dlpRecAttrArchived) + continue; + + if (attr & dlpRecAttrDirty){ + printf ("updating record\n"); + update_record (repo, id, &a, attr); + } + + free_Appointment (&a); } - - free_Appointment (&a); } + /* * 2. Pull all the records from the Calendar, and move any new items * to the pilot */ + if (!only_pilot_to_desktop){ + vcalendar_string = GNOME_Calendar_Repository_get_updated_objects (repo, &ev); + dirty_cal = calendar_new ("Temporal"); + error = calendar_load_from_memory (dirty_cal, vcalendar_string); + if (!error) + sync_cal_to_pilot (repo, dirty_cal, pilot_fd); + calendar_destroy (dirty_cal); + } + + dlp_CloseDB (pilot_fd, db); dlp_AddSyncLogEntry (pilot_fd, _("Synced DateBook from Pilot to GnomeCal")); pi_close (pilot_fd); diff --git a/calendar/gui/calendar.c b/calendar/gui/calendar.c index b67f875fdc..30e4e0168c 100644 --- a/calendar/gui/calendar.c +++ b/calendar/gui/calendar.c @@ -72,7 +72,7 @@ add_object_alarms (iCalObject *obj, time_t start, time_t end, void *closure) #define max(a,b) ((a > b) ? a : b) -void +static void ical_object_try_alarms (iCalObject *obj) { int ao, po, od, mo; @@ -169,7 +169,7 @@ calendar_destroy (Calendar *cal) g_free (cal); } -char * +static char * ice (time_t t) { static char buffer [100]; @@ -323,6 +323,34 @@ calendar_load (Calendar *cal, char *fname) return NULL; } +/* + * calendar_load_from_memory: + * @cal: calendar on which we load the information + * @buffer: A buffer that contains a vCalendar file + * + * Loads the information from the vCalendar information in @buffer + * into the Calendar + */ +char * +calendar_load_from_memory (Calendar *cal, const char *buffer) +{ + VObject *vcal; + + g_return_val_if_fail (buffer != NULL, NULL); + + cal->filename = g_strdup ("memory-based-calendar"); + vcal = Parse_MIME (buffer, strlen (buffer)); + if (!vcal) + return "Could not load the calendar"; + + cal->file_time = time (NULL); + calendar_load_from_vobject (cal, vcal); + cleanVObject (vcal); + cleanStrTbl (); + + return NULL; +} + static VObject * vcalendar_create_from_calendar (Calendar *cal) { diff --git a/calendar/gui/calendar.h b/calendar/gui/calendar.h index 2ea2753057..aa25fba67c 100644 --- a/calendar/gui/calendar.h +++ b/calendar/gui/calendar.h @@ -44,6 +44,8 @@ char *calendar_get_as_vcal_string (Calendar *cal); char *calendar_string_from_object (iCalObject *object); char *calendar_load (Calendar *cal, char *fname); +char *calendar_load_from_memory (Calendar *cal, const char *buffer); +void calendar_load_from_vobject (Calendar *cal, VObject *vcal); void calendar_save (Calendar *cal, char *fname); void calendar_add_object (Calendar *cal, iCalObject *obj); void calendar_remove_object (Calendar *cal, iCalObject *obj); diff --git a/calendar/gui/corba-cal-factory.c b/calendar/gui/corba-cal-factory.c index 49a2c5ac76..c10929376b 100644 --- a/calendar/gui/corba-cal-factory.c +++ b/calendar/gui/corba-cal-factory.c @@ -35,7 +35,7 @@ static GNOME_GenericFactory calendar_factory; static CORBA_boolean calendar_supports (PortableServer_Servant servant, - const CORBA_char * obj_goad_id, + CORBA_char * obj_goad_id, CORBA_Environment * ev) { if (strcmp (obj_goad_id, "IDL:GNOME:Calendar:Repository:1.0") == 0) @@ -46,7 +46,7 @@ calendar_supports (PortableServer_Servant servant, static CORBA_Object calendar_create_object (PortableServer_Servant servant, - const CORBA_char *goad_id, + CORBA_char *goad_id, const GNOME_stringlist *params, CORBA_Environment *ev) { diff --git a/calendar/gui/corba-cal.c b/calendar/gui/corba-cal.c index d78685bf90..8f92057d42 100644 --- a/calendar/gui/corba-cal.c +++ b/calendar/gui/corba-cal.c @@ -81,6 +81,7 @@ cal_repo_get_object_by_pilot_id (PortableServer_Servant servant, CORBA_char *ret; obj = calendar_object_find_by_pilot (gcal->cal, pilot_id); + printf ("Looking for [%d]\n", pilot_id); if (obj == NULL){ CORBA_exception_set (ev, CORBA_USER_EXCEPTION, @@ -148,6 +149,7 @@ cal_repo_update_object (PortableServer_Servant servant, obj = calendar_object_find_event (gcal->cal, uid); if (obj != NULL){ + printf ("ELIMINATING: %s -> %s\n", obj->uid, new_object->uid); calendar_remove_object (gcal->cal, obj); } @@ -155,6 +157,60 @@ cal_repo_update_object (PortableServer_Servant servant, } static void +cal_repo_update_pilot_id (PortableServer_Servant servant, + CORBA_char *uid, + CORBA_long pilot_id, + CORBA_long pilot_status, + CORBA_Environment *ev) +{ + GnomeCalendar *gcal = gnomecal_from_servant (servant); + iCalObject *obj; + + obj = calendar_object_find_event (gcal->cal, uid); + if (obj == NULL){ + CORBA_exception_set ( + ev, + CORBA_USER_EXCEPTION, + ex_GNOME_Calendar_Repository_NotFound, + ""); + return; + } + + obj->pilot_id = pilot_id; + obj->pilot_status = pilot_status; +} + +static CORBA_char * +cal_repo_get_updated_objects (PortableServer_Servant servant, + CORBA_Environment *ev) +{ + GnomeCalendar *gcal = gnomecal_from_servant (servant); + Calendar *dirty_cal; + GList *l; + CORBA_char *res; + char *str; + + dirty_cal = calendar_new ("Temporal"); + + for (l = gcal->cal->events; l; l = l->next){ + iCalObject *obj = l->data; + + if (obj->pilot_status != ICAL_PILOT_SYNC_MOD) + continue; + + obj = ical_object_duplicate (l->data); + + calendar_add_object (dirty_cal, obj); + } + str = calendar_get_as_vcal_string (dirty_cal); + res = CORBA_string_dup (str); + g_free (str); + calendar_destroy (dirty_cal); + + return res; +} + +static void cal_repo_done (PortableServer_Servant servant, CORBA_Environment *ev) { @@ -171,6 +227,9 @@ init_calendar_repo_class (void) calendar_repository_epv.get_id_from_pilot_id = cal_repo_get_id_from_pilot_id; calendar_repository_epv.delete_object = cal_repo_delete_object; calendar_repository_epv.update_object = cal_repo_update_object; + calendar_repository_epv.get_updated_objects = cal_repo_get_updated_objects; + calendar_repository_epv.update_pilot_id = cal_repo_update_pilot_id; + calendar_repository_epv.done = cal_repo_done; calendar_repository_vepv.GNOME_Calendar_Repository_epv = diff --git a/calendar/gui/eventedit.c b/calendar/gui/eventedit.c index a73775b375..8a36b94638 100644 --- a/calendar/gui/eventedit.c +++ b/calendar/gui/eventedit.c @@ -59,7 +59,7 @@ event_editor_class_init (EventEditorClass *class) object_class->destroy = event_editor_destroy; } -GtkWidget * +static GtkWidget * adjust (GtkWidget *w, gfloat x, gfloat y, gfloat xs, gfloat ys) { GtkWidget *a = gtk_alignment_new (x, y, xs, ys); @@ -432,7 +432,7 @@ ee_classification_widgets (EventEditor *ee) * Retrieves the information from the CalendarAlarm widgets and stores them * on the CalendarAlarm generic values */ -void +static void ee_store_alarm (CalendarAlarm *alarm, enum AlarmType type) { GtkWidget *item; diff --git a/calendar/pcs/calobj.c b/calendar/pcs/calobj.c index 08c8d8c63a..f1bec05c2b 100644 --- a/calendar/pcs/calobj.c +++ b/calendar/pcs/calobj.c @@ -18,23 +18,28 @@ static char * ical_gen_uid (void) { - static char *domain; + static char *hostname; time_t t = time (NULL); + static int serial; - if (!domain){ + if (!hostname){ char buffer [128]; - getdomainname (buffer, sizeof (buffer)-1); - domain = g_strdup (domain); + gethostname (buffer, sizeof (buffer)-1); + if (hostname) + hostname = g_strdup (hostname); + else + hostname = g_strdup ("localhost"); } return g_strdup_printf ( - "%s-%d-%d-%d@%s", + "%s-%d-%d-%d-%d@%s", isodate_from_time_t (t), getpid (), getgid (), getppid (), - domain); + serial++, + hostname); } iCalObject * |