aboutsummaryrefslogtreecommitdiffstats
path: root/calendar/cal-util/icalendar.c
diff options
context:
space:
mode:
Diffstat (limited to 'calendar/cal-util/icalendar.c')
-rw-r--r--calendar/cal-util/icalendar.c657
1 files changed, 657 insertions, 0 deletions
diff --git a/calendar/cal-util/icalendar.c b/calendar/cal-util/icalendar.c
new file mode 100644
index 0000000000..0a0f39c636
--- /dev/null
+++ b/calendar/cal-util/icalendar.c
@@ -0,0 +1,657 @@
+/*
+ * icalendar server for gnomecal
+ *
+ * This module interfaces between libical and the gnomecal internal
+ * representation
+ *
+ * Copyright (C) 1999 The Free Software Foundation
+ * Authors:
+ * Russell Steinthal (rms39@columbia.edu)
+ *
+ */
+
+#include <config.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include "icalendar.h"
+
+static time_t icaltime_to_timet (struct icaltimetype* i);
+static CalendarAlarm* parse_alarm (icalproperty *prop);
+static iCalPerson* parse_person (icalproperty *prop, gchar *value);
+static iCalRelation* parse_related (icalproperty *prop);
+
+/* Duplicate a string without memory leaks */
+static gchar* copy_str (gchar** store, gchar* src)
+{
+ if (*store)
+ g_free (*store);
+ return (*store = g_strdup (src));
+}
+
+static GList*
+copy_to_list (GList** store, gchar* src)
+{
+ *store = g_list_prepend (*store, g_strdup (src));
+ return *store;
+}
+
+
+iCalObject *
+ical_object_create_from_icalcomponent (icalcomponent* comp)
+{
+ iCalObject *ical = NULL;
+ iCalPerson *person;
+ icalcomponent *subcomp;
+ icalproperty *prop;
+ icalparameter *param;
+ struct icaltimetype ictime;
+ time_t *pt;
+ CalendarAlarm *alarm = NULL;
+ icalcomponent_kind compType;
+ struct icalgeotype geo;
+ struct icalperiodtype period;
+
+ gboolean root = FALSE;
+ gboolean attachment = FALSE;
+
+ char *tmpStr; /* this is a library-owned string */
+
+ ical = g_new0 (iCalObject, 1);
+
+ compType = icalcomponent_isa (comp);
+
+ switch (compType) {
+ case ICAL_XROOT_COMPONENT:
+ root = TRUE;
+ break;
+ case ICAL_XATTACH_COMPONENT:
+ attachment = TRUE;
+ break;
+ case ICAL_VEVENT_COMPONENT:
+ ical->type = ICAL_EVENT;
+ break;
+ case ICAL_VTODO_COMPONENT:
+ ical->type = ICAL_TODO;
+ break;
+ case ICAL_VJOURNAL_COMPONENT:
+ ical->type = ICAL_JOURNAL;
+ break;
+ case ICAL_VCALENDAR_COMPONENT:
+ /* FIXME: what does this mean? */
+ break;
+ case ICAL_VFREEBUSY_COMPONENT:
+ ical->type = ICAL_FBREQUEST;
+ /* NOTE: This is not conclusive- you need to analyze
+ properties to determine whether this is an
+ FBREQUEST or an FBREPLY */
+ break;
+ case ICAL_VTIMEZONE_COMPONENT:
+ ical->type = ICAL_TIMEZONE;
+ break;
+ case ICAL_VALARM_COMPONENT:
+ case ICAL_XAUDIOALARM_COMPONENT:
+ case ICAL_XDISPLAYALARM_COMPONENT:
+ case ICAL_XEMAILALARM_COMPONENT:
+ case ICAL_XPROCEDUREALARM_COMPONENT:
+ /* this should not be reached, since this loop should
+ only be processing first level components */
+ break;
+ case ICAL_XSTANDARD_COMPONENT:
+ /* FIXME: what does this mean? */
+ break;
+ case ICAL_XDAYLIGHT_COMPONENT:
+ /* FIXME: what does this mean? */
+ break;
+ case ICAL_X_COMPONENT:
+ /* FIXME: what does this mean? */
+ break;
+ case ICAL_VSCHEDULE_COMPONENT:
+ /* FIXME: what does this mean? */
+ break;
+ case ICAL_XLICINVALID_COMPONENT:
+ /* FIXME: what does this mean? */
+ break;
+ case ICAL_NO_COMPONENT:
+ case ICAL_ANY_COMPONENT:
+ /* should not occur */
+ break;
+ case ICAL_VQUERY_COMPONENT:
+ case ICAL_VCAR_COMPONENT:
+ case ICAL_VCOMMAND_COMPONENT:
+ /* FIXME: what does this mean? */
+ break;
+ }
+
+ prop = icalcomponent_get_first_property (comp, ICAL_ANY_PROPERTY);
+ while (prop) {
+ switch (icalproperty_isa (prop)) {
+ case ICAL_CALSCALE_PROPERTY:
+ if (g_strcasecmp (icalproperty_get_calscale (prop),
+ "GREGORIAN"))
+ g_warning ("Unknown calendar format.");
+ break;
+ case ICAL_METHOD_PROPERTY:
+ /* FIXME: implement something here */
+ break;
+ case ICAL_ATTACH_PROPERTY:
+ /* FIXME: not yet implemented */
+ break;
+ case ICAL_CATEGORIES_PROPERTY:
+ copy_to_list (&ical->categories,
+ icalproperty_get_categories (prop));
+ break;
+ case ICAL_CLASS_PROPERTY:
+ copy_str (&ical->class, icalproperty_get_class (prop));
+ break;
+ case ICAL_COMMENT_PROPERTY:
+ /*tmpStr = icalproperty_get_comment (prop);*/
+ tmpStr = g_strconcat (icalproperty_get_comment (prop),
+ ical->comment,
+ NULL);
+ if (ical->comment)
+ g_free (ical->comment);
+ ical->comment = tmpStr;
+ break;
+ case ICAL_DESCRIPTION_PROPERTY:
+ copy_str (&ical->desc,
+ icalproperty_get_description (prop));
+ break;
+ case ICAL_GEO_PROPERTY:
+ geo = icalproperty_get_geo (prop);
+ ical->geo.latitude = geo.lat;
+ ical->geo.longitude = geo.lon;
+ ical->geo.valid = TRUE;
+ break;
+ case ICAL_LOCATION_PROPERTY:
+ copy_str (&ical->location,
+ icalproperty_get_location (prop));
+ break;
+ case ICAL_PERCENTCOMPLETE_PROPERTY:
+ ical->percent = icalproperty_get_percentcomplete (prop);
+ break;
+ case ICAL_PRIORITY_PROPERTY:
+ ical->priority = icalproperty_get_priority (prop);
+ if (ical->priority < 0 || ical->priority > 9)
+ g_warning ("Priority out-of-range (see RFC2445)");
+ break;
+ case ICAL_RESOURCES_PROPERTY:
+ copy_to_list (&ical->resources,
+ icalproperty_get_resources (prop));
+ break;
+ case ICAL_STATUS_PROPERTY:
+ copy_str (&ical->status,
+ icalproperty_get_status (prop));
+ break;
+ case ICAL_SUMMARY_PROPERTY:
+ copy_str (&ical->summary,
+ icalproperty_get_summary (prop));
+ break;
+ case ICAL_COMPLETED_PROPERTY:
+ ictime = icalproperty_get_completed (prop);
+ ical->completed = icaltime_to_timet (&ictime);
+ break;
+ case ICAL_DTEND_PROPERTY:
+ ictime = icalproperty_get_dtend (prop);
+ ical->dtend = icaltime_to_timet (&ictime);
+ param = icalproperty_get_first_parameter (prop,
+ ICAL_VALUE_PARAMETER);
+ ical->date_only = (icalparameter_get_value (param) ==
+ ICAL_VALUE_DATE);
+ /* FIXME: We should handle timezone specifiers */
+ break;
+ case ICAL_DUE_PROPERTY:
+ ictime = icalproperty_get_due (prop);
+ ical->dtend = icaltime_to_timet (&ictime);
+ param = icalproperty_get_first_parameter (prop,
+ ICAL_VALUE_PARAMETER);
+ ical->date_only = (icalparameter_get_value (param) ==
+ ICAL_VALUE_DATE);
+ /* FIXME: We should handle timezone specifiers */
+ break;
+ case ICAL_DTSTART_PROPERTY:
+ ictime = icalproperty_get_dtstart (prop);
+ ical->dtstart = icaltime_to_timet (&ictime);
+ param = icalproperty_get_first_parameter (prop,
+ ICAL_VALUE_PARAMETER);
+ ical->date_only = (icalparameter_get_value (param) ==
+ ICAL_VALUE_DATE);
+ /* FIXME: We should handle timezone specifiers */
+ break;
+ case ICAL_DURATION_PROPERTY:
+ /* FIXME: I don't see the necessary libical function */
+ break;
+ case ICAL_FREEBUSY_PROPERTY:
+ period = icalproperty_get_freebusy (prop);
+ ical->dtstart = icaltime_to_timet (&(period.start));
+ /* FIXME: period.end is specified as being relative to start, so
+this may not be correct */
+ ical->dtend = icaltime_to_timet (&(period.end));
+ break;
+ case ICAL_TRANSP_PROPERTY:
+ tmpStr = icalproperty_get_transp (prop);
+ /* do not i18n the following string constant! */
+ if (!g_strcasecmp (tmpStr, "TRANSPARENT"))
+ ical->transp = ICAL_TRANSPARENT;
+ else
+ ical->transp = ICAL_OPAQUE;
+ break;
+ case ICAL_TZID_PROPERTY:
+ case ICAL_TZNAME_PROPERTY:
+ case ICAL_TZOFFSETFROM_PROPERTY:
+ case ICAL_TZOFFSETTO_PROPERTY:
+ case ICAL_TZURL_PROPERTY:
+ /* no implementation for now */
+ break;
+ case ICAL_ATTENDEE_PROPERTY:
+ tmpStr = icalproperty_get_attendee (prop);
+ person = parse_person (prop, tmpStr);
+ ical->attendee = g_list_prepend (ical->attendee,
+ person);
+ break;
+ case ICAL_CONTACT_PROPERTY:
+ tmpStr = icalproperty_get_contact (prop);
+ person = parse_person (prop, tmpStr);
+ ical->contact = g_list_prepend (ical->contact, person);
+ break;
+ case ICAL_ORGANIZER_PROPERTY:
+ tmpStr = icalproperty_get_organizer (prop);
+ person = parse_person (prop, tmpStr);
+ if (ical->organizer)
+ g_free (ical->organizer);
+ ical->organizer = person;
+ break;
+ case ICAL_RECURRENCEID_PROPERTY:
+ ictime = icalproperty_get_recurrenceid (prop);
+ ical->recurid = icaltime_to_timet (&ictime);
+ /* FIXME: Range parameter not implemented */
+ break;
+ case ICAL_RELATEDTO_PROPERTY:
+ ical->related = g_list_prepend (ical->related,
+ parse_related (prop));
+ break;
+ case ICAL_URL_PROPERTY:
+ copy_str (&ical->url,
+ icalproperty_get_url (prop));
+ break;
+ case ICAL_UID_PROPERTY:
+ copy_str (&ical->uid,
+ icalproperty_get_uid (prop));
+ break;
+ case ICAL_EXDATE_PROPERTY:
+ /* FIXME: This does not appear to parse
+ multiple exdate values in one property, as
+ allowed by the RFC; needs a libical fix */
+ ictime = icalproperty_get_exdate (prop);
+ pt = g_new0 (time_t, 1);
+ *pt = icaltime_to_timet (&ictime);
+ ical->exdate = g_list_prepend (ical->exdate, pt);
+ break;
+ case ICAL_EXRULE_PROPERTY:
+ case ICAL_RDATE_PROPERTY:
+ case ICAL_RRULE_PROPERTY:
+ /* FIXME: need recursion processing */
+ break;
+ case ICAL_ACTION_PROPERTY:
+ case ICAL_REPEAT_PROPERTY:
+ case ICAL_TRIGGER_PROPERTY:
+ /* should only occur in VALARM's, handled below */
+ g_assert_not_reached();
+ break;
+ case ICAL_CREATED_PROPERTY:
+ ictime = icalproperty_get_created (prop);
+ ical->created = icaltime_to_timet (&ictime);
+ break;
+ case ICAL_DTSTAMP_PROPERTY:
+ ictime = icalproperty_get_dtstamp (prop);
+ ical->dtstamp = icaltime_to_timet (&ictime);
+ break;
+ case ICAL_LASTMODIFIED_PROPERTY:
+ ictime = icalproperty_get_lastmodified (prop);
+ ical->last_mod = icaltime_to_timet (&ictime);
+ break;
+ case ICAL_SEQUENCE_PROPERTY:
+ ical->seq = icalproperty_get_sequence (prop);
+ break;
+ case ICAL_REQUESTSTATUS_PROPERTY:
+ copy_str (&ical->rstatus,
+ icalproperty_get_requeststatus (prop));
+ break;
+ case ICAL_X_PROPERTY:
+ g_warning ("Unsupported X-property: %s",
+ icalproperty_as_ical_string (prop));
+ break;
+ case ICAL_XLICERROR_PROPERTY:
+ g_warning ("Unsupported property: %s",
+ icalproperty_get_xlicerror (prop));
+ break;
+ case ICAL_PRODID_PROPERTY:
+ case ICAL_VERSION_PROPERTY:
+ /* nothing to do for this property */
+ break;
+ default:
+ g_warning ("Unsupported property: %s", icalproperty_as_ical_string
+(prop));
+ break;
+
+ }
+
+ prop = icalcomponent_get_next_property (comp,
+ ICAL_ANY_PROPERTY);
+ }
+
+ /* now parse subcomponents --- should only be VALARM's */
+ subcomp = icalcomponent_get_first_component (comp,
+ ICAL_ANY_COMPONENT);
+ while (subcomp) {
+ compType = icalcomponent_isa (subcomp);
+ switch (compType) {
+ case ICAL_VALARM_COMPONENT:
+ alarm = parse_alarm (subcomp);
+ if (alarm)
+ ical->alarms = g_list_prepend (ical->alarms,
+ alarm);
+ break;
+ default:
+ g_warning ("Only nested VALARM components are supported.");
+ }
+
+ subcomp = icalcomponent_get_next_component (comp,
+ ICAL_ANY_COMPONENT);
+ }
+
+ return ical;
+}
+
+
+static time_t icaltime_to_timet (struct icaltimetype* i)
+{
+ extern long timezone;
+ struct tm t;
+ time_t ret;
+
+ t.tm_year = i->year - 1900;
+ t.tm_mon = i->month - 1;
+ t.tm_mday = i->day;
+ if (!i->is_date) {
+ t.tm_hour = i->hour;
+ t.tm_min = i->minute;
+ t.tm_sec = i->second;
+ } else {
+ t.tm_hour = 0;
+ t.tm_min = 0;
+ t.tm_sec = 0;
+ }
+
+ ret = mktime(&t);
+
+ return ret - (i->is_utc ? timezone : 0);
+}
+
+static iCalPerson*
+parse_person (icalproperty* prop, gchar* value)
+{
+ icalparameter* param;
+ icalparameter_role role;
+ icalparameter_partstat partstat;
+ icalparameter_cutype cutype;
+
+ iCalPerson* ret;
+
+ ret = g_new0 (iCalPerson, 1);
+
+ ret->addr = g_strdup (value);
+
+ param = icalproperty_get_first_parameter (prop,
+ ICAL_CN_PARAMETER);
+ ret->name = g_strdup (icalparameter_get_cn (param));
+
+ param = icalproperty_get_first_parameter (prop,
+ ICAL_ROLE_PARAMETER);
+ if (param) {
+ role = icalparameter_get_role (param);
+ switch (role) {
+ case ICAL_ROLE_CHAIR:
+ ret->role = g_strdup ("CHAIR");
+ break;
+ case ICAL_ROLE_REQPARTICIPANT:
+ ret->role = g_strdup ("REQPARTICIPANT");
+ break;
+ case ICAL_ROLE_OPTPARTICIPANT:
+ ret->role = g_strdup ("OPTPARTICIPANT");
+ break;
+ case ICAL_ROLE_NONPARTICIPANT:
+ ret->role = g_strdup ("NONPARTICIPANT");
+ break;
+ case ICAL_ROLE_XNAME:
+ default:
+ ret->role = g_strdup ("UNKNOWN");
+ break;
+ }
+ } else
+ ret->role = g_strdup ("REQPARTICIPANT");
+
+ param = icalproperty_get_first_parameter (prop, ICAL_PARTSTAT_PARAMETER);
+ if (param) {
+ partstat = icalparameter_get_partstat (param);
+ switch (partstat) {
+ case ICAL_PARTSTAT_NEEDSACTION:
+ ret->partstat = g_strdup ("NEEDSACTION");
+ break;
+ case ICAL_PARTSTAT_ACCEPTED:
+ ret->partstat = g_strdup ("ACCEPTED");
+ break;
+ case ICAL_PARTSTAT_DECLINED:
+ ret->partstat = g_strdup ("DECLINED");
+ break;
+ case ICAL_PARTSTAT_TENTATIVE:
+ ret->partstat = g_strdup ("TENTATIVE");
+ break;
+ case ICAL_PARTSTAT_DELEGATED:
+ ret->partstat = g_strdup ("DELEGATED");
+ break;
+ case ICAL_PARTSTAT_COMPLETED:
+ ret->partstat = g_strdup ("COMPLETED");
+ break;
+ case ICAL_PARTSTAT_INPROCESS:
+ ret->partstat = g_strdup ("INPROCESS");
+ break;
+ case ICAL_PARTSTAT_XNAME:
+ ret->partstat = g_strdup (icalparameter_get_xvalue (param));
+ break;
+ default:
+ ret->partstat = g_strdup ("UNKNOWN");
+ break;
+ }
+ } else
+ ret->partstat = g_strdup ("NEEDSACTION");
+
+ param = icalproperty_get_first_parameter (prop, ICAL_RSVP_PARAMETER);
+ if (param)
+ ret->rsvp = icalparameter_get_rsvp (param);
+ else
+ ret->rsvp = FALSE;
+
+ param = icalproperty_get_first_parameter (prop, ICAL_CUTYPE_PARAMETER
+);
+ if (param) {
+ cutype = icalparameter_get_cutype (param);
+ switch (cutype) {
+ case ICAL_CUTYPE_INDIVIDUAL:
+ ret->cutype = g_strdup ("INDIVIDUAL");
+ break;
+ case ICAL_CUTYPE_GROUP:
+ ret->cutype = g_strdup ("GROUP");
+ break;
+ case ICAL_CUTYPE_RESOURCE:
+ ret->cutype = g_strdup ("RESOURCE");
+ break;
+ case ICAL_CUTYPE_ROOM:
+ ret->cutype = g_strdup ("ROOM");
+ break;
+ case ICAL_CUTYPE_UNKNOWN:
+ case ICAL_CUTYPE_XNAME:
+ default:
+ ret->cutype = g_strdup ("UNKNOWN");
+ break;
+ }
+ } else
+ ret->cutype = g_strdup ("INDIVIDUAL");
+
+ param = icalproperty_get_first_parameter (prop, ICAL_MEMBER_PARAMETER
+);
+ while (param) {
+ copy_to_list (&ret->member, icalparameter_get_member (param));
+ param = icalproperty_get_next_parameter (prop,
+ ICAL_MEMBER_PARAMETER);
+ }
+
+ param = icalproperty_get_first_parameter (prop, ICAL_DELEGATEDTO_PARAMETER);
+ while (param) {
+ copy_to_list (&ret->deleg_to,
+ icalparameter_get_delegatedto (param));
+ param = icalproperty_get_next_parameter (prop,
+ ICAL_DELEGATEDTO_PARAMETER);
+ }
+
+ param = icalproperty_get_first_parameter (prop, ICAL_DELEGATEDFROM_PARAMETER);
+ while (param) {
+ copy_to_list (&ret->deleg_from,
+ icalparameter_get_delegatedfrom (param));
+ param = icalproperty_get_next_parameter (prop,
+ ICAL_DELEGATEDFROM_PARAMETER);
+ }
+
+ param = icalproperty_get_first_parameter (prop, ICAL_SENTBY_PARAMETER
+);
+ copy_str (&ret->sent_by,
+ icalparameter_get_sentby (param));
+
+ param = icalproperty_get_first_parameter (prop, ICAL_DIR_PARAMETER);
+ while (param) {
+ copy_to_list (&ret->deleg_to,
+ icalparameter_get_delegatedto (param));
+ param = icalproperty_get_next_parameter (prop,
+ ICAL_DIR_PARAMETER);
+ }
+
+ return ret;
+}
+
+static iCalRelation*
+parse_related (icalproperty* prop)
+{
+ iCalRelation* rel;
+ icalparameter* param;
+ icalparameter_reltype type;
+
+ rel = g_new0 (iCalRelation, 1);
+ rel->uid = g_strdup (icalproperty_get_relatedto (prop));
+
+ param = icalproperty_get_first_parameter (prop,
+ ICAL_RELTYPE_PARAMETER);
+ if (param) {
+ type = icalparameter_get_reltype (param);
+ switch (type) {
+ case ICAL_RELTYPE_PARENT:
+ rel->reltype = g_strdup ("PARENT");
+ break;
+ case ICAL_RELTYPE_CHILD:
+ rel->reltype = g_strdup ("CHILD");
+ break;
+ case ICAL_RELTYPE_SIBLING:
+ rel->reltype = g_strdup ("SIBLING");
+ break;
+ case ICAL_RELTYPE_XNAME:
+ rel->reltype = g_strdup (icalparameter_get_xvalue (param));
+ break;
+ default:
+ rel->reltype = g_strdup ("UNKNOWN");
+ break;
+ }
+ } else
+ rel->reltype = g_strdup ("PARENT");
+
+ return rel;
+}
+
+#ifdef TEST
+
+int main(int argc, char* argv[])
+{
+ icalcomponent* comp;
+ comp = icalendar_parse_file (argv[1]);
+ printf ("%s\n", icalcomponent_as_ical_string (comp));
+ return 0;
+}
+
+#endif
+
+
+static CalendarAlarm*
+parse_alarm (icalcomponent* comp)
+{
+ CalendarAlarm *alarm;
+ icalproperty *prop;
+ char *tmpStr;
+ struct icaldurationtype dur;
+ struct icalattachtype attach;
+
+ g_return_val_if_fail (comp != NULL, NULL);
+
+ alarm = g_new0 (CalendarAlarm, 1);
+
+ prop = icalcomponent_get_first_property (comp, ICAL_ANY_PROPERTY);
+ while (prop) {
+ switch (icalproperty_isa (prop)) {
+ case ICAL_ACTION_PROPERTY:
+ tmpStr = icalproperty_get_action (prop);
+ if (!g_strcasecmp (tmpStr, "AUDIO"))
+ alarm->type = ALARM_AUDIO;
+ else if (!g_strcasecmp (tmpStr, "DISPLAY"))
+ alarm->type = ALARM_DISPLAY;
+ else if (!g_strcasecmp (tmpStr, "EMAIL"))
+ alarm->type = ALARM_MAIL;
+ else if (!g_strcasecmp (tmpStr, "PROCEDURE"))
+ alarm->type = ALARM_PROGRAM;
+ else
+ g_warning ("Unsupported alarm type!");
+ break;
+ case ICAL_TRIGGER_PROPERTY:
+ /* FIXME: waiting on proper libical support */
+ break;
+ case ICAL_REPEAT_PROPERTY:
+ alarm->snooze_repeat = icalproperty_get_repeat (prop);
+ break;
+ case ICAL_DURATION_PROPERTY:
+ dur = icalproperty_get_duration (prop);
+ alarm->snooze_secs = icaldurationtype_as_timet (dur);
+ break;
+ case ICAL_ATTACH_PROPERTY:
+ attach = icalproperty_get_attach (prop);
+ copy_str (&alarm->attach,
+ icalattachtype_get_url (&attach));
+ break;
+ case ICAL_DESCRIPTION_PROPERTY:
+ copy_str (&alarm->desc,
+ icalproperty_get_description (prop));
+ break;
+ case ICAL_SUMMARY_PROPERTY:
+ copy_str (&alarm->summary,
+ icalproperty_get_summary (prop));
+ break;
+ case ICAL_ATTENDEE_PROPERTY:
+ copy_str (&alarm->attendee,
+ icalproperty_get_attendee (prop));
+ break;
+ default:
+ g_warning ("Unsupported alarm property: %s",
+ icalproperty_as_ical_string (prop));
+ break;
+ }
+
+ prop = icalcomponent_get_next_property (comp,
+ ICAL_ANY_PROPERTY);
+ }
+
+ return alarm;
+}