aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--plugins/itip-formatter/.cvsignore6
-rw-r--r--plugins/itip-formatter/ChangeLog4
-rw-r--r--plugins/itip-formatter/Makefile.am14
-rw-r--r--plugins/itip-formatter/itip-formatter.c275
-rw-r--r--plugins/itip-formatter/itip-view.c720
-rw-r--r--plugins/itip-formatter/itip-view.h102
-rw-r--r--plugins/itip-formatter/org-gnome-itip-formatter.eplug.in14
7 files changed, 1135 insertions, 0 deletions
diff --git a/plugins/itip-formatter/.cvsignore b/plugins/itip-formatter/.cvsignore
new file mode 100644
index 0000000000..76bd16c42d
--- /dev/null
+++ b/plugins/itip-formatter/.cvsignore
@@ -0,0 +1,6 @@
+.deps
+.libs
+Makefile
+Makefile.in
+*.eplug
+backup \ No newline at end of file
diff --git a/plugins/itip-formatter/ChangeLog b/plugins/itip-formatter/ChangeLog
new file mode 100644
index 0000000000..c2fbae2bad
--- /dev/null
+++ b/plugins/itip-formatter/ChangeLog
@@ -0,0 +1,4 @@
+2004-12-22 JP Rosevear <jpr@novell.com>
+
+ * Initial checkin of new itip formatter
+
diff --git a/plugins/itip-formatter/Makefile.am b/plugins/itip-formatter/Makefile.am
new file mode 100644
index 0000000000..418d43830c
--- /dev/null
+++ b/plugins/itip-formatter/Makefile.am
@@ -0,0 +1,14 @@
+INCLUDES = \
+ -I$(top_srcdir) \
+ $(EVOLUTION_MAIL_CFLAGS) \
+ $(EVOLUTION_CALENDAR_CFLAGS)
+
+@EVO_PLUGIN_RULE@
+
+plugin_DATA = org-gnome-itip-formatter.eplug
+plugin_LTLIBRARIES = liborg-gnome-itip-formatter.la
+
+liborg_gnome_itip_formatter_la_SOURCES = itip-formatter.c itip-view.c itip-view.h
+liborg_gnome_itip_formatter_la_LDFLAGS = -module -avoid-version
+
+EXTRA_DIST = org-gnome-itip-formatter.eplug.in \ No newline at end of file
diff --git a/plugins/itip-formatter/itip-formatter.c b/plugins/itip-formatter/itip-formatter.c
new file mode 100644
index 0000000000..c16cc24826
--- /dev/null
+++ b/plugins/itip-formatter/itip-formatter.c
@@ -0,0 +1,275 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Authors: JP Rosevear <jpr@novell.com>
+ *
+ * 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 <config.h>
+#endif
+
+#include <string.h>
+#include <glib.h>
+#include <gtk/gtk.h>
+#include <libgnome/gnome-i18n.h>
+#include <gconf/gconf-client.h>
+#include <camel/camel-stream.h>
+#include <camel/camel-stream-mem.h>
+#include <camel/camel-medium.h>
+#include <camel/camel-mime-message.h>
+#include <libecal/e-cal.h>
+#include <libecal/e-cal-time-util.h>
+#include <gtkhtml/gtkhtml-embedded.h>
+#include <mail/em-format-hook.h>
+#include <mail/em-format-html.h>
+#include <e-util/e-account-list.h>
+#include <e-util/e-icon-factory.h>
+#include <calendar/gui/itip-utils.h>
+#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, "<table border=0 width=\"100%%\" cellpadding=3><tr>");
+ camel_stream_printf (target->stream, "<td valign=top><object classid=\"%s\"></object></td><td width=100%% valign=top>", CLASSID);
+ camel_stream_printf (target->stream, "</td></tr></table>");
+}
diff --git a/plugins/itip-formatter/itip-view.c b/plugins/itip-formatter/itip-view.c
new file mode 100644
index 0000000000..e58506605b
--- /dev/null
+++ b/plugins/itip-formatter/itip-view.c
@@ -0,0 +1,720 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Authors: JP Rosevear <jpr@novell.com>
+ *
+ * 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.
+ *
+ */
+
+#include <string.h>
+#include <glib.h>
+#include <gtk/gtk.h>
+#include <libgnome/gnome-i18n.h>
+#include <gconf/gconf-client.h>
+#include <camel/camel-stream.h>
+#include <camel/camel-stream-mem.h>
+#include <camel/camel-medium.h>
+#include <camel/camel-mime-message.h>
+#include <libecal/e-cal.h>
+#include <gtkhtml/gtkhtml-embedded.h>
+#include <mail/em-format-hook.h>
+#include <mail/em-format-html.h>
+#include <e-util/e-account-list.h>
+#include <e-util/e-icon-factory.h>
+#include <e-util/e-time-utils.h>
+#include <calendar/gui/itip-utils.h>
+#include "itip-view.h"
+
+#define MEETING_ICON "stock_new-meeting"
+
+G_DEFINE_TYPE (ItipView, itip_view, GTK_TYPE_HBOX);
+
+struct _ItipViewPrivate {
+ ItipViewMode mode;
+
+ GtkWidget *sender_label;
+ char *organizer;
+ char *sentby;
+ char *delegator;
+ char *attendee;
+
+ GtkWidget *summary_label;
+ char *summary;
+
+ GtkWidget *location_header;
+ GtkWidget *location_label;
+ char *location;
+
+ GtkWidget *start_header;
+ GtkWidget *start_label;
+ struct tm *start_tm;
+
+ GtkWidget *end_header;
+ GtkWidget *end_label;
+ struct tm *end_tm;
+};
+
+static void
+format_date_and_time_x (struct tm *date_tm,
+ struct tm *current_tm,
+ gboolean use_24_hour_format,
+ gboolean show_midnight,
+ gboolean show_zero_seconds,
+ char *buffer,
+ int buffer_size)
+{
+ char *format;
+
+ /* Today */
+ if (date_tm->tm_mday == current_tm->tm_mday &&
+ date_tm->tm_mon == current_tm->tm_mon &&
+ date_tm->tm_year == current_tm->tm_year) {
+ if (!show_midnight && date_tm->tm_hour == 0
+ && date_tm->tm_min == 0 && date_tm->tm_sec == 0) {
+ /* strftime format of a weekday and a date. */
+ format = _("Today");
+ } else if (use_24_hour_format) {
+ if (!show_zero_seconds && date_tm->tm_sec == 0)
+ /* strftime format of a weekday, a date and a
+ time, in 24-hour format, without seconds. */
+ format = _("Today %H:%M");
+ else
+ /* strftime format of a weekday, a date and a
+ time, in 24-hour format. */
+ format = _("Today %H:%M:%S");
+ } else {
+ if (!show_zero_seconds && date_tm->tm_sec == 0)
+ /* strftime format of a weekday, a date and a
+ time, in 12-hour format, without seconds. */
+ format = _("Today %I:%M %p");
+ else
+ /* strftime format of a weekday, a date and a
+ time, in 12-hour format. */
+ format = _("Today %I:%M:%S %p");
+ }
+
+ /* Tomorrow */
+ } else if (date_tm->tm_year == current_tm->tm_year) {
+ if (!show_midnight && date_tm->tm_hour == 0
+ && date_tm->tm_min == 0 && date_tm->tm_sec == 0) {
+ /* strftime format of a weekday and a date. */
+ format = _("%A, %B %e");
+ } else if (use_24_hour_format) {
+ if (!show_zero_seconds && date_tm->tm_sec == 0)
+ /* strftime format of a weekday, a date and a
+ time, in 24-hour format, without seconds. */
+ format = _("%A, %B %e %H:%M");
+ else
+ /* strftime format of a weekday, a date and a
+ time, in 24-hour format. */
+ format = _("%A, %B %e %H:%M:%S");
+ } else {
+ if (!show_zero_seconds && date_tm->tm_sec == 0)
+ /* strftime format of a weekday, a date and a
+ time, in 12-hour format, without seconds. */
+ format = _("%A, %B %e %I:%M %p");
+ else
+ /* strftime format of a weekday, a date and a
+ time, in 12-hour format. */
+ format = _("%A, %B %e %I:%M:%S %p");
+ }
+
+ /* Within 7 days */
+ } else if (date_tm->tm_year == current_tm->tm_year) {
+ if (!show_midnight && date_tm->tm_hour == 0
+ && date_tm->tm_min == 0 && date_tm->tm_sec == 0) {
+ /* strftime format of a weekday and a date. */
+ format = _("%A");
+ } else if (use_24_hour_format) {
+ if (!show_zero_seconds && date_tm->tm_sec == 0)
+ /* strftime format of a weekday, a date and a
+ time, in 24-hour format, without seconds. */
+ format = _("%A %H:%M");
+ else
+ /* strftime format of a weekday, a date and a
+ time, in 24-hour format. */
+ format = _("%A %H:%M:%S");
+ } else {
+ if (!show_zero_seconds && date_tm->tm_sec == 0)
+ /* strftime format of a weekday, a date and a
+ time, in 12-hour format, without seconds. */
+ format = _("%A %I:%M %p");
+ else
+ /* strftime format of a weekday, a date and a
+ time, in 12-hour format. */
+ format = _("%A %I:%M:%S %p");
+ }
+
+ /* This Year */
+ } else if (date_tm->tm_year == current_tm->tm_year) {
+ if (!show_midnight && date_tm->tm_hour == 0
+ && date_tm->tm_min == 0 && date_tm->tm_sec == 0) {
+ /* strftime format of a weekday and a date. */
+ format = _("%A, %B %e");
+ } else if (use_24_hour_format) {
+ if (!show_zero_seconds && date_tm->tm_sec == 0)
+ /* strftime format of a weekday, a date and a
+ time, in 24-hour format, without seconds. */
+ format = _("%A, %B %e %H:%M");
+ else
+ /* strftime format of a weekday, a date and a
+ time, in 24-hour format. */
+ format = _("%A, %B %e %H:%M:%S");
+ } else {
+ if (!show_zero_seconds && date_tm->tm_sec == 0)
+ /* strftime format of a weekday, a date and a
+ time, in 12-hour format, without seconds. */
+ format = _("%A, %B %e %I:%M %p");
+ else
+ /* strftime format of a weekday, a date and a
+ time, in 12-hour format. */
+ format = _("%A, %B %e %I:%M:%S %p");
+ }
+ } else {
+ if (!show_midnight && date_tm->tm_hour == 0
+ && date_tm->tm_min == 0 && date_tm->tm_sec == 0) {
+ /* strftime format of a weekday and a date. */
+ format = _("%A, %B %e, %Y");
+ } else if (use_24_hour_format) {
+ if (!show_zero_seconds && date_tm->tm_sec == 0)
+ /* strftime format of a weekday, a date and a
+ time, in 24-hour format, without seconds. */
+ format = _("%A, %B %e, %Y %H:%M");
+ else
+ /* strftime format of a weekday, a date and a
+ time, in 24-hour format. */
+ format = _("%A, %B %e, %Y %H:%M:%S");
+ } else {
+ if (!show_zero_seconds && date_tm->tm_sec == 0)
+ /* strftime format of a weekday, a date and a
+ time, in 12-hour format, without seconds. */
+ format = _("%A, %B %e, %Y %I:%M %p");
+ else
+ /* strftime format of a weekday, a date and a
+ time, in 12-hour format. */
+ format = _("%A, %B %e, %Y %I:%M:%S %p");
+ }
+ }
+
+ /* strftime returns 0 if the string doesn't fit, and leaves the buffer
+ undefined, so we set it to the empty string in that case. */
+ if (e_utf8_strftime (buffer, buffer_size, format, date_tm) == 0)
+ buffer[0] = '\0';
+}
+
+static void
+set_sender_text (ItipView *view)
+{
+ ItipViewPrivate *priv;
+ const char *organizer, *attendee;
+ char *sender = NULL;
+
+ priv = view->priv;
+
+ organizer = priv->organizer ? priv->organizer : _("An unknown person");
+ attendee = priv->attendee ? priv->attendee : _("An unknown person");
+
+ switch (priv->mode) {
+ case ITIP_VIEW_MODE_PUBLISH:
+ if (priv->sentby)
+ sender = g_strdup_printf (_("<b>%s</b> through %s has published meeting information."), organizer, priv->sentby);
+ else
+ sender = g_strdup_printf (_("<b>%s</b> has published meeting information."), organizer);
+ break;
+ case ITIP_VIEW_MODE_REQUEST:
+ /* FIXME is the delegator stuff handled correctly here? */
+ if (priv->delegator) {
+ sender = g_strdup_printf (_("<b>%s</b> requests the presence of %s at a meeting."), organizer, priv->delegator);
+ } else {
+ if (priv->sentby)
+ sender = g_strdup_printf (_("<b>%s</b> through %s requests your presence at a meeting."), organizer, priv->sentby);
+ else
+ sender = g_strdup_printf (_("<b>%s</b> requests your presence at a meeting."), organizer);
+ }
+ break;
+ case ITIP_VIEW_MODE_ADD:
+ if (priv->sentby)
+ sender = g_strdup_printf (_("<b>%s</b> through %s wishes to add to an existing meeting."), organizer, priv->sentby);
+ else
+ sender = g_strdup_printf (_("<b>%s</b> wishes to add to an existing meeting."), organizer);
+ break;
+ case ITIP_VIEW_MODE_REFRESH:
+ sender = g_strdup_printf (_("<b>%s</b> wishes to receive the latest meeting information."), attendee);
+ break;
+ case ITIP_VIEW_MODE_REPLY:
+ sender = g_strdup_printf (_("<b>%s</b> has replied to a meeting invitation."), attendee);
+ break;
+ case ITIP_VIEW_MODE_CANCEL:
+ if (priv->sentby)
+ sender = g_strdup_printf (_("<b>%s</b> through %s has cancelled a meeting."), organizer, priv->sentby);
+ else
+ sender = g_strdup_printf (_("<b>%s</b> has cancelled a meeting."), organizer);
+ break;
+ default:
+ break;
+ }
+
+ gtk_label_set_text (GTK_LABEL (priv->sender_label), sender);
+ gtk_label_set_use_markup (GTK_LABEL (priv->sender_label), TRUE);
+
+ g_free (sender);
+}
+
+static void
+set_summary_text (ItipView *view)
+{
+ ItipViewPrivate *priv;
+ char *summary = NULL;
+
+ priv = view->priv;
+
+ summary = g_strdup_printf ("<b>%s</b>", priv->summary);
+
+ gtk_label_set_text (GTK_LABEL (priv->summary_label), summary);
+ gtk_label_set_use_markup (GTK_LABEL (priv->summary_label), TRUE);
+
+ g_free (summary);
+}
+
+static void
+set_location_text (ItipView *view)
+{
+ ItipViewPrivate *priv;
+
+ priv = view->priv;
+
+ gtk_label_set_text (GTK_LABEL (priv->location_label), priv->location);
+
+ priv->location ? gtk_widget_show (priv->location_header) : gtk_widget_hide (priv->location_header);
+ priv->location ? gtk_widget_show (priv->location_label) : gtk_widget_hide (priv->location_label);
+}
+
+static void
+set_start_text (ItipView *view)
+{
+ ItipViewPrivate *priv;
+ char buffer[256];
+ time_t now;
+ struct tm *now_tm;
+
+ priv = view->priv;
+
+ now = time (NULL);
+ now_tm = localtime (&now);
+
+ if (priv->start_tm) {
+ format_date_and_time_x (priv->start_tm, now_tm, FALSE, TRUE, FALSE, buffer, 256);
+ gtk_label_set_text (GTK_LABEL (priv->start_label), buffer);
+ } else {
+ gtk_label_set_text (GTK_LABEL (priv->start_label), NULL);
+ }
+
+ priv->start_tm ? gtk_widget_show (priv->start_header) : gtk_widget_hide (priv->start_header);
+ priv->start_tm ? gtk_widget_show (priv->start_label) : gtk_widget_hide (priv->start_label);
+}
+
+static void
+set_end_text (ItipView *view)
+{
+ ItipViewPrivate *priv;
+ char buffer[256];
+ time_t now;
+ struct tm *now_tm;
+
+ priv = view->priv;
+
+ now = time (NULL);
+ now_tm = localtime (&now);
+
+ if (priv->end_tm) {
+ format_date_and_time_x (priv->end_tm, now_tm, FALSE, TRUE, FALSE, buffer, 256);
+ gtk_label_set_text (GTK_LABEL (priv->end_label), buffer);
+ } else {
+ gtk_label_set_text (GTK_LABEL (priv->end_label), NULL);
+ }
+
+ priv->end_tm ? gtk_widget_show (priv->end_header) : gtk_widget_hide (priv->end_header);
+ priv->end_tm ? gtk_widget_show (priv->end_label) : gtk_widget_hide (priv->end_label);
+}
+
+static void
+itip_view_destroy (GtkObject *object)
+{
+ ItipView *view = ITIP_VIEW (object);
+ ItipViewPrivate *priv = view->priv;
+
+ if (priv) {
+ g_free (priv->organizer);
+ g_free (priv->sentby);
+ g_free (priv->delegator);
+ g_free (priv->attendee);
+ g_free (priv->location);
+ g_free (priv->start_tm);
+ g_free (priv->end_tm);
+
+ g_free (priv);
+ view->priv = NULL;
+ }
+
+ GTK_OBJECT_CLASS (itip_view_parent_class)->destroy (object);
+}
+
+static void
+itip_view_class_init (ItipViewClass *klass)
+{
+ GObjectClass *object_class;
+ GtkObjectClass *gtkobject_class;
+
+ object_class = G_OBJECT_CLASS (klass);
+ gtkobject_class = GTK_OBJECT_CLASS (klass);
+
+ gtkobject_class->destroy = itip_view_destroy;
+}
+
+static void
+itip_view_init (ItipView *view)
+{
+ ItipViewPrivate *priv;
+ GtkWidget *icon, *vbox, *separator, *table;
+
+ priv = g_new0 (ItipViewPrivate, 1);
+ view->priv = priv;
+
+ priv->mode = ITIP_VIEW_MODE_NONE;
+
+ /* The icon on the LHS */
+ icon = e_icon_factory_get_image (MEETING_ICON, E_ICON_SIZE_LARGE_TOOLBAR);
+ gtk_misc_set_alignment (GTK_MISC (icon), 0, 0);
+ gtk_widget_show (icon);
+
+ gtk_box_pack_start (GTK_BOX (view), icon, FALSE, FALSE, 6);
+
+ /* The RHS */
+ vbox = gtk_vbox_new (FALSE, 0);
+ gtk_widget_show (vbox);
+ gtk_box_pack_start (GTK_BOX (view), vbox, FALSE, FALSE, 6);
+
+ /* The first section listing the sender */
+ /* FIXME What to do if the send and organizer do not match */
+ priv->sender_label = gtk_label_new (NULL);
+ gtk_widget_show (priv->sender_label);
+ gtk_box_pack_start (GTK_BOX (vbox), priv->sender_label, FALSE, FALSE, 6);
+
+ separator = gtk_hseparator_new ();
+ gtk_widget_show (separator);
+ gtk_box_pack_start (GTK_BOX (vbox), separator, FALSE, FALSE, 6);
+
+ /* A table with information on the meeting and any extra info/warnings */
+ table = gtk_table_new (3, 2, FALSE);
+ gtk_table_set_row_spacings (GTK_TABLE (table), 6);
+ gtk_table_set_col_spacings (GTK_TABLE (table), 6);
+ gtk_widget_show (table);
+ gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 6);
+
+ /* Summary */
+ priv->summary_label = gtk_label_new (NULL);
+ gtk_misc_set_alignment (GTK_MISC (priv->summary_label), 0, 0.5);
+ gtk_widget_show (priv->summary_label);
+ gtk_table_attach (GTK_TABLE (table), priv->summary_label, 0, 2, 0, 1, GTK_FILL, 0, 0, 0);
+
+ /* Location */
+ priv->location_header = gtk_label_new (_("Location:"));
+ priv->location_label = gtk_label_new (NULL);
+ gtk_misc_set_alignment (GTK_MISC (priv->location_label), 0, 0.5);
+ gtk_table_attach (GTK_TABLE (table), priv->location_header, 0, 1, 1, 2, GTK_FILL, 0, 0, 0);
+ gtk_table_attach (GTK_TABLE (table), priv->location_label, 1, 2, 1, 2, GTK_FILL, 0, 0, 0);
+
+ priv->start_header = gtk_label_new (_("Starts:"));
+ priv->start_label = gtk_label_new (NULL);
+ gtk_misc_set_alignment (GTK_MISC (priv->start_header), 0, 0.5);
+ gtk_misc_set_alignment (GTK_MISC (priv->start_label), 0, 0.5);
+ gtk_widget_show (priv->start_header);
+ gtk_table_attach (GTK_TABLE (table), priv->start_header, 0, 1, 2, 3, GTK_FILL, 0, 0, 0);
+ gtk_table_attach (GTK_TABLE (table), priv->start_label, 1, 2, 2, 3, GTK_FILL, 0, 0, 0);
+
+ priv->end_header = gtk_label_new (_("Ends:"));
+ priv->end_label = gtk_label_new (NULL);
+ gtk_misc_set_alignment (GTK_MISC (priv->end_header), 0, 0.5);
+ gtk_misc_set_alignment (GTK_MISC (priv->end_label), 0, 0.5);
+ gtk_table_attach (GTK_TABLE (table), priv->end_header, 0, 1, 3, 4, GTK_FILL, 0, 0, 0);
+ gtk_table_attach (GTK_TABLE (table), priv->end_label, 1, 2, 3, 4, GTK_FILL, 0, 0, 0);
+
+ /* The buttons for actions */
+}
+
+GtkWidget *
+itip_view_new (void)
+{
+ ItipView *itip_view = g_object_new (ITIP_TYPE_VIEW, "homogeneous", FALSE, "spacing", 6, NULL);
+
+ return GTK_WIDGET (itip_view);
+}
+
+void
+itip_view_set_mode (ItipView *view, ItipViewMode mode)
+{
+ ItipViewPrivate *priv;
+
+ g_return_if_fail (view != NULL);
+ g_return_if_fail (ITIP_IS_VIEW (view));
+
+ priv = view->priv;
+
+ priv->mode = mode;
+
+ set_sender_text (view);
+}
+
+ItipViewMode
+itip_view_get_mode (ItipView *view)
+{
+ ItipViewPrivate *priv;
+
+ g_return_val_if_fail (view != NULL, ITIP_VIEW_MODE_NONE);
+ g_return_val_if_fail (ITIP_IS_VIEW (view), ITIP_VIEW_MODE_NONE);
+
+ priv = view->priv;
+
+ return priv->mode;
+}
+
+void
+itip_view_set_organizer (ItipView *view, const char *organizer)
+{
+ ItipViewPrivate *priv;
+
+ g_return_if_fail (view != NULL);
+ g_return_if_fail (ITIP_IS_VIEW (view));
+
+ priv = view->priv;
+
+ if (priv->organizer)
+ g_free (priv->organizer);
+
+ priv->organizer = g_strdup (organizer);
+
+ set_sender_text (view);
+}
+
+const char *
+itip_view_get_organizer (ItipView *view)
+{
+ ItipViewPrivate *priv;
+
+ g_return_val_if_fail (view != NULL, NULL);
+ g_return_val_if_fail (ITIP_IS_VIEW (view), NULL);
+
+ priv = view->priv;
+
+ return priv->organizer;
+}
+
+void
+itip_view_set_sentby (ItipView *view, const char *sentby)
+{
+ ItipViewPrivate *priv;
+
+ g_return_if_fail (view != NULL);
+ g_return_if_fail (ITIP_IS_VIEW (view));
+
+ priv = view->priv;
+
+ if (priv->sentby)
+ g_free (priv->sentby);
+
+ priv->sentby = g_strdup (sentby);
+
+ set_sender_text (view);
+}
+
+const char *
+itip_view_get_sentby (ItipView *view)
+{
+ ItipViewPrivate *priv;
+
+ g_return_val_if_fail (view != NULL, NULL);
+ g_return_val_if_fail (ITIP_IS_VIEW (view), NULL);
+
+ priv = view->priv;
+
+ return priv->sentby;
+}
+
+void
+itip_view_set_attendee (ItipView *view, const char *attendee)
+{
+ ItipViewPrivate *priv;
+
+ g_return_if_fail (view != NULL);
+ g_return_if_fail (ITIP_IS_VIEW (view));
+
+ priv = view->priv;
+
+ if (priv->attendee)
+ g_free (priv->attendee);
+
+ priv->attendee = g_strdup (attendee);
+
+ set_sender_text (view);
+}
+
+const char *
+itip_view_get_attendee (ItipView *view)
+{
+ ItipViewPrivate *priv;
+
+ g_return_val_if_fail (view != NULL, NULL);
+ g_return_val_if_fail (ITIP_IS_VIEW (view), NULL);
+
+ priv = view->priv;
+
+ return priv->attendee;
+}
+
+void
+itip_view_set_summary (ItipView *view, const char *summary)
+{
+ ItipViewPrivate *priv;
+
+ g_return_if_fail (view != NULL);
+ g_return_if_fail (ITIP_IS_VIEW (view));
+
+ priv = view->priv;
+
+ if (priv->summary)
+ g_free (priv->summary);
+
+ priv->summary = g_strdup (summary);
+
+ set_summary_text (view);
+}
+
+const char *
+itip_view_get_summary (ItipView *view)
+{
+ ItipViewPrivate *priv;
+
+ g_return_val_if_fail (view != NULL, NULL);
+ g_return_val_if_fail (ITIP_IS_VIEW (view), NULL);
+
+ priv = view->priv;
+
+ return priv->summary;
+}
+
+void
+itip_view_set_location (ItipView *view, const char *location)
+{
+ ItipViewPrivate *priv;
+
+ g_return_if_fail (view != NULL);
+ g_return_if_fail (ITIP_IS_VIEW (view));
+
+ priv = view->priv;
+
+ if (priv->location)
+ g_free (priv->location);
+
+ priv->location = g_strdup (location);
+
+ set_location_text (view);
+}
+
+const char *
+itip_view_get_location (ItipView *view)
+{
+ ItipViewPrivate *priv;
+
+ g_return_val_if_fail (view != NULL, NULL);
+ g_return_val_if_fail (ITIP_IS_VIEW (view), NULL);
+
+ priv = view->priv;
+
+ return priv->location;
+}
+
+void
+itip_view_set_start (ItipView *view, struct tm *start)
+{
+ ItipViewPrivate *priv;
+
+ g_return_if_fail (view != NULL);
+ g_return_if_fail (ITIP_IS_VIEW (view));
+
+ priv = view->priv;
+
+ if (priv->start_tm && !start) {
+ g_free (priv->start_tm);
+ priv->start_tm = NULL;
+ } else if (start) {
+ if (!priv->start_tm)
+ priv->start_tm = g_new0 (struct tm, 1);
+
+ *priv->start_tm = *start;
+ }
+
+ set_start_text (view);
+}
+
+const struct tm *
+itip_view_get_start (ItipView *view)
+{
+ ItipViewPrivate *priv;
+
+ g_return_val_if_fail (view != NULL, NULL);
+ g_return_val_if_fail (ITIP_IS_VIEW (view), NULL);
+
+ priv = view->priv;
+
+ return priv->start_tm;
+}
+
+void
+itip_view_set_end (ItipView *view, struct tm *end)
+{
+ ItipViewPrivate *priv;
+
+ g_return_if_fail (view != NULL);
+ g_return_if_fail (ITIP_IS_VIEW (view));
+
+ priv = view->priv;
+
+ if (priv->end_tm && !end) {
+ g_free (priv->end_tm);
+ priv->end_tm = NULL;
+ } else if (end) {
+ if (!priv->end_tm)
+ priv->end_tm = g_new0 (struct tm, 1);
+
+ *priv->end_tm = *end;
+ }
+
+ set_end_text (view);
+}
+
+const struct tm *
+itip_view_get_end (ItipView *view)
+{
+ ItipViewPrivate *priv;
+
+ g_return_val_if_fail (view != NULL, NULL);
+ g_return_val_if_fail (ITIP_IS_VIEW (view), NULL);
+
+ priv = view->priv;
+
+ return priv->end_tm;
+}
diff --git a/plugins/itip-formatter/itip-view.h b/plugins/itip-formatter/itip-view.h
new file mode 100644
index 0000000000..ac9305bf2e
--- /dev/null
+++ b/plugins/itip-formatter/itip-view.h
@@ -0,0 +1,102 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* itip-view.h
+ *
+ * Copyright (C) 2004 Novell, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * 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 Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: JP Rosevear
+ */
+
+#ifndef _ITIP_VIEW_H_
+#define _ITIP_VIEW_H_
+
+#include <glib-object.h>
+#include <gtk/gtkhbox.h>
+
+G_BEGIN_DECLS
+
+#define ITIP_TYPE_VIEW (itip_view_get_type ())
+#define ITIP_VIEW(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), ITIP_TYPE_VIEW, ItipView))
+#define ITIP_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), ITIP_TYPE_VIEW, ItipViewClass))
+#define ITIP_IS_VIEW(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), ITIP_TYPE_VIEW))
+#define ITIP_IS_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), ITIP_TYPE_VIEW))
+#define ITIP_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), ITIP_TYPE_VIEW, ItipViewClass))
+
+typedef struct _ItipView ItipView;
+typedef struct _ItipViewPrivate ItipViewPrivate;
+typedef struct _ItipViewClass ItipViewClass;
+
+typedef enum {
+ ITIP_VIEW_MODE_NONE,
+ ITIP_VIEW_MODE_PUBLISH,
+ ITIP_VIEW_MODE_REQUEST,
+ ITIP_VIEW_MODE_ADD,
+ ITIP_VIEW_MODE_REPLY,
+ ITIP_VIEW_MODE_REFRESH,
+ ITIP_VIEW_MODE_CANCEL
+} ItipViewMode;
+
+typedef enum {
+ ITIP_VIEW_RESPONSE_NONE,
+ ITIP_VIEW_RESPONSE_ACCEPT,
+ ITIP_VIEW_RESPONSE_TENTATIVE,
+ ITIP_VIEW_RESPONSE_DECLINE,
+ ITIP_VIEW_RESPONSE_UPDATE,
+ ITIP_VIEW_RESPONSE_SEND
+} ItipViewResponse;
+
+struct _ItipView
+{
+ GtkHBox parent_instance;
+
+ ItipViewPrivate *priv;
+};
+
+struct _ItipViewClass
+{
+ GtkHBoxClass parent_class;
+};
+
+GType itip_view_get_type (void);
+GtkWidget *itip_view_new (void);
+
+void itip_view_set_mode (ItipView *view, ItipViewMode mode);
+ItipViewMode itip_view_get_mode (ItipView *view);
+
+void itip_view_set_organizer (ItipView *view, const char *organizer);
+const char *itip_view_get_organizer (ItipView *view);
+
+void itip_view_set_sentby (ItipView *view, const char *sentby);
+const char *itip_view_get_sentby (ItipView *view);
+
+void itip_view_set_attendee (ItipView *view, const char *attendee);
+const char *itip_view_get_attendee (ItipView *view);
+
+void itip_view_set_summary (ItipView *view, const char *summary);
+const char *itip_view_get_summary (ItipView *view);
+
+void itip_view_set_location (ItipView *view, const char *location);
+const char *itip_view_get_location (ItipView *view);
+
+void itip_view_set_start (ItipView *view, struct tm *start);
+const struct tm *itip_view_get_start (ItipView *view);
+
+void itip_view_set_end (ItipView *view, struct tm *end);
+const struct tm *itip_view_get_end (ItipView *view);
+
+G_END_DECLS
+
+#endif
diff --git a/plugins/itip-formatter/org-gnome-itip-formatter.eplug.in b/plugins/itip-formatter/org-gnome-itip-formatter.eplug.in
new file mode 100644
index 0000000000..901e695bd0
--- /dev/null
+++ b/plugins/itip-formatter/org-gnome-itip-formatter.eplug.in
@@ -0,0 +1,14 @@
+<e-plugin-list>
+ <e-plugin id="org.gnome.evolution.itip_formatter" type="shlib" name="Itip Formatter" description="Displays text/calendar parts in messages"
+ location="@PLUGINDIR@/liborg-gnome-itip-formatter.so">
+
+ <hook class="org.gnome.evolution.mail.format:1.0">
+ <group id="EMFormatHTMLDisplay">
+ <item mime_type="text/calendar" flags="inline_disposition" format="format_itip"/>
+ </group>
+ <group id="EMFormat">
+ <item mime_type="text/calendar" flags="inline_disposition" format="format_itip"/>
+ </group>
+ </hook>
+ </e-plugin>
+</e-plugin-list> \ No newline at end of file