/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* * Authors: JP Rosevear * * Copyright 2004 Novell, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA. * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "itip-view.h" #define CLASSID "itip://" void format_itip (EPlugin *ep, EMFormatHookTarget *target); typedef struct { EMFormatHTMLPObject pobject; GtkWidget *view; ESourceList *source_lists[E_CAL_SOURCE_TYPE_LAST]; GHashTable *ecals[E_CAL_SOURCE_TYPE_LAST]; ECal *current_ecal; ECalSourceType type; char action; gboolean rsvp; GtkWidget *ok; GtkWidget *hbox; GtkWidget *vbox; char *vcalendar; ECalComponent *comp; icalcomponent *main_comp; icalcomponent *ical_comp; icalcomponent *top_level; icalcompiter iter; icalproperty_method method; int current; int total; gchar *calendar_uid; EAccountList *accounts; gchar *from_address; gchar *delegator_address; gchar *delegator_name; gchar *my_address; gint view_only; } FormatItipPObject; static icalcomponent * get_next (icalcompiter *iter) { icalcomponent *ret = NULL; icalcomponent_kind kind; do { icalcompiter_next (iter); ret = icalcompiter_deref (iter); if (ret == NULL) break; kind = icalcomponent_isa (ret); } while (ret != NULL && kind != ICAL_VEVENT_COMPONENT && kind != ICAL_VTODO_COMPONENT && kind != ICAL_VFREEBUSY_COMPONENT); return ret; } static void extract_itip_data (FormatItipPObject *pitip) { CamelDataWrapper *content; CamelStream *mem; icalproperty *prop; icalcomponent_kind kind = ICAL_NO_COMPONENT; icalcomponent *tz_comp; icalcompiter tz_iter; /* FIXME try and match sender with organizer/attendee/sentby? pd->from_address = camel_address_encode ((CamelAddress *)from); g_message ("Detected from address %s", pd->from_address); */ content = camel_medium_get_content_object ((CamelMedium *) pitip->pobject.part); mem = camel_stream_mem_new (); camel_data_wrapper_write_to_stream (content, mem); pitip->vcalendar = g_strndup (((CamelStreamMem *) mem)->buffer->data, ((CamelStreamMem *) mem)->buffer->len); /* FIXME unref the content object as well? */ camel_object_unref (mem); pitip->top_level = e_cal_util_new_top_level (); pitip->main_comp = icalparser_parse_string (pitip->vcalendar); if (pitip->main_comp == NULL) { // write_error_html (itip, _("The attachment does not contain a valid calendar message")); return; } prop = icalcomponent_get_first_property (pitip->main_comp, ICAL_METHOD_PROPERTY); if (prop == NULL) { pitip->method = ICAL_METHOD_PUBLISH; } else { pitip->method = icalproperty_get_method (prop); } tz_iter = icalcomponent_begin_component (pitip->main_comp, ICAL_VTIMEZONE_COMPONENT); while ((tz_comp = icalcompiter_deref (&tz_iter)) != NULL) { icalcomponent *clone; clone = icalcomponent_new_clone (tz_comp); icalcomponent_add_component (pitip->top_level, clone); icalcompiter_next (&tz_iter); } pitip->iter = icalcomponent_begin_component (pitip->main_comp, ICAL_ANY_COMPONENT); pitip->ical_comp = icalcompiter_deref (&pitip->iter); if (pitip->ical_comp != NULL) { kind = icalcomponent_isa (pitip->ical_comp); if (kind != ICAL_VEVENT_COMPONENT && kind != ICAL_VTODO_COMPONENT && kind != ICAL_VFREEBUSY_COMPONENT) pitip->ical_comp = get_next (&pitip->iter); } if (pitip->ical_comp == NULL) { // write_error_html (itip, _("The attachment has no viewable calendar items")); return; } pitip->total = icalcomponent_count_components (pitip->main_comp, ICAL_VEVENT_COMPONENT); pitip->total += icalcomponent_count_components (pitip->main_comp, ICAL_VTODO_COMPONENT); pitip->total += icalcomponent_count_components (pitip->main_comp, ICAL_VFREEBUSY_COMPONENT); if (pitip->total > 0) pitip->current = 1; else pitip->current = 0; pitip->comp = e_cal_component_new (); if (!e_cal_component_set_icalcomponent (pitip->comp, pitip->ical_comp)) { // write_error_html (itip, _("The message does not appear to be properly formed")); g_object_unref (pitip->comp); pitip->comp = NULL; return; }; // show_current (itip); } static gboolean format_itip_object (EMFormatHTML *efh, GtkHTMLEmbedded *eb, EMFormatHTMLPObject *pobject) { FormatItipPObject *pitip = (FormatItipPObject *) pobject; ECalComponentText text; ECalComponentOrganizer organizer; ECalComponentDateTime datetime; icaltimezone *from_zone, *to_zone; const char *string; /* FIXME Error handling? */ extract_itip_data (pitip); pitip->view = itip_view_new (); gtk_widget_show (pitip->view); itip_view_set_mode (ITIP_VIEW (pitip->view), ITIP_VIEW_MODE_REQUEST); e_cal_component_get_organizer (pitip->comp, &organizer); itip_view_set_organizer (ITIP_VIEW (pitip->view), organizer.cn ? organizer.cn : itip_strip_mailto (organizer.value)); /* FIXME, do i need to strip the sentby somehow? Maybe with camel? */ itip_view_set_sentby (ITIP_VIEW (pitip->view), organizer.sentby); e_cal_component_get_summary (pitip->comp, &text); itip_view_set_summary (ITIP_VIEW (pitip->view), text.value ? text.value : _("None")); e_cal_component_get_location (pitip->comp, &string); itip_view_set_location (ITIP_VIEW (pitip->view), string); to_zone = calendar_config_get_icaltimezone (); e_cal_component_get_dtstart (pitip->comp, &datetime); if (datetime.value) { struct tm start_tm; /* FIXME Handle tzid that is not in the component - treat as "local" time */ if (!datetime.value->is_utc && datetime.tzid) from_zone = icalcomponent_get_timezone (pitip->top_level, datetime.tzid); else from_zone = NULL; start_tm = icaltimetype_to_tm_with_zone (datetime.value, from_zone, to_zone); itip_view_set_start (ITIP_VIEW (pitip->view), &start_tm); } e_cal_component_free_datetime (&datetime); e_cal_component_get_dtend (pitip->comp, &datetime); if (datetime.value) { struct tm end_tm; /* FIXME Handle tzid that is not in the component - treat as "local" time */ if (!datetime.value->is_utc && datetime.tzid) from_zone = icalcomponent_get_timezone (pitip->top_level, datetime.tzid); else from_zone = NULL; end_tm = icaltimetype_to_tm_with_zone (datetime.value, from_zone, to_zone); itip_view_set_end (ITIP_VIEW (pitip->view), &end_tm); } e_cal_component_free_datetime (&datetime); gtk_container_add (GTK_CONTAINER (eb), pitip->view); return TRUE; } void format_itip (EPlugin *ep, EMFormatHookTarget *target) { FormatItipPObject *pitip; calendar_config_init (); pitip = (FormatItipPObject *) em_format_html_add_pobject ((EMFormatHTML *) target->format, sizeof (FormatItipPObject), CLASSID, target->part, format_itip_object); // FIXME set the free function // pitip->object.free = pitip_free; camel_stream_printf (target->stream, ""); camel_stream_printf (target->stream, "
", CLASSID); camel_stream_printf (target->stream, "
"); }