diff options
author | Dan Vrátil <dvratil@redhat.com> | 2012-06-06 21:29:38 +0800 |
---|---|---|
committer | Dan Vrátil <dvratil@redhat.com> | 2012-06-06 21:29:38 +0800 |
commit | 931191474643164e96b5778c790e42cca517e729 (patch) | |
tree | aec00f3303dbcd95a8a3f18ee324ac80594ff9b5 | |
parent | 5b8340563c271fb684a88c6e5bb6dd3bfb629058 (diff) | |
download | gsoc2013-evolution-931191474643164e96b5778c790e42cca517e729.tar gsoc2013-evolution-931191474643164e96b5778c790e42cca517e729.tar.gz gsoc2013-evolution-931191474643164e96b5778c790e42cca517e729.tar.bz2 gsoc2013-evolution-931191474643164e96b5778c790e42cca517e729.tar.lz gsoc2013-evolution-931191474643164e96b5778c790e42cca517e729.tar.xz gsoc2013-evolution-931191474643164e96b5778c790e42cca517e729.tar.zst gsoc2013-evolution-931191474643164e96b5778c790e42cca517e729.zip |
Mail formatter rewrite - convert some plugins to modules
audio-inline, itip-formatter, prefer-plain, tnef-attachments
and vcard-inline plugins were converted to modules so that they
can fit into concept of the new formatter.
Every module still installs .eplug file, because there is no
suitable API at the moment to register plugins to the plugins dialog
and to extend the Preferences dialog.
64 files changed, 7680 insertions, 5418 deletions
diff --git a/configure.ac b/configure.ac index f234723df8..1a18edb4a8 100644 --- a/configure.ac +++ b/configure.ac @@ -1106,8 +1106,9 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM( )], [tnef_ok=yes], [tnef_ok=no]) if test "$tnef_ok" = "yes"; then AC_MSG_RESULT([yes]) - TNEF_ATTACHMENTS="tnef-attachments" TNEF_CFLAGS="-DHAVE_YTNEF_H" + AC_DEFINE(ENABLE_TNEF,1,[Define if TNEF attachments parser should be built]) + else AC_COMPILE_IFELSE([AC_LANG_PROGRAM( [[ @@ -1118,14 +1119,14 @@ else )], [tnef_ok=yes], [tnef_ok=no]) if test "$tnef_ok" = "yes"; then AC_MSG_RESULT([yes]) - TNEF_ATTACHMENTS="tnef-attachments" TNEF_CFLAGS="-DHAVE_LIBYTNEF_YTNEF_H" + AC_DEFINE(ENABLE_TNEF,1,[Define if TNEF attachments parser should be built]) else AC_MSG_RESULT([no]) - TNEF_ATTACHMENTS="" TNEF_CFLAGS="" fi fi +AM_CONDITIONAL([ENABLE_TNEF], [test "$tnef_ok" = "yes"]) AC_SUBST(TNEF_CFLAGS) dnl ******************************* @@ -1298,20 +1299,20 @@ AC_ARG_ENABLE([plugins], [enable_plugins="$enableval"],[enable_plugins=all]) dnl Add any new plugins here -plugins_base_always="itip-formatter mark-all-read publish-calendar" +plugins_base_always="mark-all-read publish-calendar" plugins_base="$plugins_base_always" dist_plugins_base="$plugins_base_always" -plugins_standard_always="bbdb save-calendar mail-to-task mailing-list-actions prefer-plain mail-notification attachment-reminder email-custom-header face templates vcard-inline dbx-import external-editor" +plugins_standard_always="bbdb save-calendar mail-to-task mailing-list-actions mail-notification attachment-reminder email-custom-header face templates dbx-import external-editor" plugins_standard="$plugins_standard_always" -dist_plugins_standard="$plugins_standard audio-inline image-inline pst-import" +dist_plugins_standard="$plugins_standard image-inline pst-import" plugins_experimental_always="" -plugins_experimental="$plugins_experimental_always $TNEF_ATTACHMENTS" -dist_plugins_experimental="$plugins_experimental_always tnef-attachments" +plugins_experimental="$plugins_experimental_always" +dist_plugins_experimental="$plugins_experimental_always" dnl ****************************************************************** dnl The following plugins have additional library dependencies. @@ -1332,12 +1333,14 @@ if test "x$enable_audio_inline" = "xyes"; then AC_SUBST(GSTREAMER_LIBS) if test "x$have_gst" = "xyes"; then - plugins_standard="$plugins_standard audio-inline" + AC_DEFINE(ENABLE_AUDIO_INLINE, 1, [Define to add support for inlining audio attachments]) else AC_MSG_ERROR([gstreamer-0.10 is required for the audio-inline plugin. Use --disable-audio-inline to exclude the plugin.]) fi fi +AM_CONDITIONAL([ENABLE_AUDIO_INLINE], [test "x$enable_audio_inline" = "xyes"]) + dnl ************************************** dnl Weather calendars require gweather-3.0 dnl ************************************** @@ -1627,8 +1630,11 @@ mail/importers/Makefile maint/Makefile modules/Makefile modules/addressbook/Makefile +modules/audio-inline/Makefile modules/bogofilter/Makefile modules/calendar/Makefile +modules/itip-formatter/Makefile +modules/itip-formatter/plugin/Makefile modules/mail/Makefile modules/backup-restore/Makefile modules/book-config-google/Makefile @@ -1652,30 +1658,30 @@ modules/plugin-lib/Makefile modules/plugin-manager/Makefile modules/plugin-mono/Makefile modules/plugin-python/Makefile +modules/prefer-plain/Makefile +modules/prefer-plain/plugin/Makefile modules/spamassassin/Makefile modules/startup-wizard/Makefile +modules/text-highlight/Makefile +modules/tnef-attachment/Makefile +modules/vcard-inline/Makefile modules/web-inspector/Makefile plugins/Makefile plugins/attachment-reminder/Makefile -plugins/audio-inline/Makefile plugins/bbdb/Makefile plugins/dbx-import/Makefile plugins/email-custom-header/Makefile plugins/external-editor/Makefile plugins/face/Makefile plugins/image-inline/Makefile -plugins/itip-formatter/Makefile plugins/mail-notification/Makefile plugins/mail-to-task/Makefile plugins/mailing-list-actions/Makefile plugins/mark-all-read/Makefile -plugins/prefer-plain/Makefile plugins/pst-import/Makefile plugins/publish-calendar/Makefile plugins/save-calendar/Makefile plugins/templates/Makefile -plugins/tnef-attachments/Makefile -plugins/vcard-inline/Makefile smclient/Makefile smime/Makefile smime/lib/Makefile diff --git a/modules/Makefile.am b/modules/Makefile.am index b26d161e36..16810fd55c 100644 --- a/modules/Makefile.am +++ b/modules/Makefile.am @@ -18,6 +18,14 @@ if ENABLE_ONLINE_ACCOUNTS ONLINE_ACCOUNTS_DIR = online-accounts endif +if ENABLE_TNEF +TNEF_ATTACHMENT_DIR = tnef-attachment +endif + +if ENABLE_AUDIO_INLINE +AUDIO_INLINE_DIR = audio-inline +endif + SUBDIRS = \ addressbook \ bogofilter \ @@ -36,17 +44,23 @@ SUBDIRS = \ cal-config-webcal \ composer-autosave \ imap-features \ + itip-formatter \ mail-config \ mailto-handler \ mdn \ offline-alert \ plugin-lib \ plugin-manager \ + prefer-plain \ spamassassin \ startup-wizard \ + text-highlight \ + vcard-inline \ web-inspector \ $(MONO_DIR) \ $(PYTHON_DIR) \ - $(ONLINE_ACCOUNTS_DIR) + $(ONLINE_ACCOUNTS_DIR) \ + $(TNEF_ATTACHMENT_DIR) \ + $(AUDIO_INLINE_DIR) -include $(top_srcdir)/git.mk diff --git a/modules/audio-inline/Makefile.am b/modules/audio-inline/Makefile.am new file mode 100644 index 0000000000..152086ba08 --- /dev/null +++ b/modules/audio-inline/Makefile.am @@ -0,0 +1,31 @@ +module_LTLIBRARIES = module-audio-inline.la + +module_audio_inline_la_CPPFLAGS = \ + $(AM_CPPFLAGS) \ + -I$(top_srcdir) \ + -I$(top_srcdir)/widgets \ + -DEVOLUTION_PRIVDATADIR=\""$(privdatadir)"\" \ + -DG_LOG_DOMAIN=\"evolution-module-audio-inline\" \ + $(EVOLUTION_DATA_SERVER_CFLAGS) \ + $(GNOME_PLATFORM_CFLAGS) \ + $(GSTREAMER_CFLAGS) + +module_audio_inline_la_SOURCES = \ + e-mail-formatter-audio-inline.c \ + e-mail-formatter-audio-inline.h \ + e-mail-parser-audio-inline.c \ + e-mail-parser-audio-inline.h \ + evolution-module-audio-inline.c + +module_audio_inline_la_LIBADD = \ + $(top_builddir)/e-util/libeutil.la \ + $(top_builddir)/mail/libevolution-mail.la \ + $(top_builddir)/em-format/libemformat.la \ + $(EVOLUTION_DATA_SERVER_LIBS) \ + $(GNOME_PLATFORM_LIBS) \ + $(GSTREAMER_LIBS) + +module_audio_inline_la_LDFLAGS = \ + -avoid-version -module $(NO_UNDEFINED) + +-include $(top_srcdir)/git.mk diff --git a/modules/audio-inline/e-mail-formatter-audio-inline.c b/modules/audio-inline/e-mail-formatter-audio-inline.c new file mode 100644 index 0000000000..4116748923 --- /dev/null +++ b/modules/audio-inline/e-mail-formatter-audio-inline.c @@ -0,0 +1,383 @@ +/* + * e-mail-formatter-audio-inline.c + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see <http://www.gnu.org/licenses/> + * + */ + +#include "e-mail-formatter-audio-inline.h" + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <glib/gi18n-lib.h> + +#include <libebackend/libebackend.h> + +#include <em-format/e-mail-formatter-extension.h> +#include <em-format/e-mail-formatter.h> + +#include "e-util/e-mktemp.h" + +#include <camel/camel.h> +#include <gst/gst.h> + +#include "e-mail-part-audio-inline.h" + +#define d(x) + +typedef struct _EMailFormatterAudioInline { + EExtension parent; +} EMailFormatterAudioInline; + +typedef struct _EMailFormatterAudioInlineClass { + EExtensionClass parent_class; +} EMailFormatterAudioInlineClass; + +GType e_mail_formatter_audio_inline_get_type (void); +static void e_mail_formatter_formatter_extension_interface_init (EMailFormatterExtensionInterface *iface); +static void e_mail_formatter_mail_extension_interface_init (EMailExtensionInterface *iface); + +G_DEFINE_DYNAMIC_TYPE_EXTENDED ( + EMailFormatterAudioInline, + e_mail_formatter_audio_inline, + E_TYPE_EXTENSION, + 0, + G_IMPLEMENT_INTERFACE_DYNAMIC ( + E_TYPE_MAIL_EXTENSION, + e_mail_formatter_mail_extension_interface_init) + G_IMPLEMENT_INTERFACE_DYNAMIC ( + E_TYPE_MAIL_FORMATTER_EXTENSION, + e_mail_formatter_formatter_extension_interface_init)); + +static const gchar* formatter_mime_types[] = { "application/vnd.evolution.widget.audio-inline", + "audio/ac3", "audio/x-ac3", + "audio/basic", "audio/mpeg", + "audio/x-mpeg", "audio/mpeg3", + "audio/x-mpeg3", "audio/mp3", + "audio/x-mp3", "audio/mp4", + "audio/flac", "audio/x-flac", + "audio/mod", "audio/x-mod", + "audio/x-wav", "audio/microsoft-wav", + "audio/x-wma", "audio/x-ms-wma", + "application/ogg", "application/x-ogg", + NULL }; + +static void +pause_clicked (GtkWidget *button, + EMailPartAudioInline *part) +{ + if (part->playbin) { + /* pause playing */ + gst_element_set_state (part->playbin, GST_STATE_PAUSED); + } +} + +static void +stop_clicked (GtkWidget *button, + EMailPartAudioInline *part) +{ + if (part->playbin) { + /* ready to play */ + gst_element_set_state (part->playbin, GST_STATE_READY); + part->target_state = GST_STATE_READY; + } +} + +static void +set_audiosink (GstElement *playbin) +{ + GstElement *audiosink; + + /* now it's time to get the audio sink */ + audiosink = gst_element_factory_make ("gconfaudiosink", "play_audio"); + if (audiosink == NULL) { + audiosink = gst_element_factory_make ("autoaudiosink", "play_audio"); + } + + if (audiosink) { + g_object_set (playbin, "audio-sink", audiosink, NULL); + } +} + +static gboolean +gst_callback (GstBus *bus, + GstMessage *message, + gpointer data) +{ + EMailPartAudioInline *part = data; + GstMessageType msg_type; + + g_return_val_if_fail (part != NULL, TRUE); + g_return_val_if_fail (part->playbin != NULL, TRUE); + + msg_type = GST_MESSAGE_TYPE (message); + + switch (msg_type) { + case GST_MESSAGE_ERROR: + gst_element_set_state (part->playbin, GST_STATE_NULL); + break; + case GST_MESSAGE_EOS: + gst_element_set_state (part->playbin, GST_STATE_READY); + break; + case GST_MESSAGE_STATE_CHANGED: + { + GstState old_state, new_state; + + if (GST_MESSAGE_SRC (message) != GST_OBJECT (part->playbin)) + break; + + gst_message_parse_state_changed (message, &old_state, &new_state, NULL); + + if (old_state == new_state) + break; + + if (part->play_button) + gtk_widget_set_sensitive ( + part->play_button, + new_state <= GST_STATE_PAUSED); + if (part->pause_button) + gtk_widget_set_sensitive ( + part->pause_button, + new_state > GST_STATE_PAUSED); + if (part->stop_button) + gtk_widget_set_sensitive ( + part->stop_button, + new_state >= GST_STATE_PAUSED); + } + + break; + default: + break; + } + + return TRUE; +} + +static void +play_clicked (GtkWidget *button, + EMailPartAudioInline *part) +{ + GstState cur_state; + + d(printf ("audio inline formatter: play\n")); + + if (!part->filename) { + CamelStream *stream; + CamelDataWrapper *data; + GError *error = NULL; + gint argc = 1; + const gchar *argv [] = { "org_gnome_audio_inline", NULL }; + + /* FIXME this is ugly, we should stream this directly to gstreamer */ + part->filename = e_mktemp ("org-gnome-audio-inline-file-XXXXXX"); + + d(printf ("audio inline formatter: write to temp file %s\n", po->filename)); + + stream = camel_stream_fs_new_with_name ( + part->filename, O_RDWR | O_CREAT | O_TRUNC, 0600, NULL); + data = camel_medium_get_content (CAMEL_MEDIUM (part->parent.part)); + camel_data_wrapper_decode_to_stream_sync (data, stream, NULL, NULL); + camel_stream_flush (stream, NULL, NULL); + g_object_unref (stream); + + d(printf ("audio inline formatter: init gst playbin\n")); + + if (gst_init_check (&argc, (gchar ***) &argv, &error)) { + gchar *uri; + GstBus *bus; + + /* create a disk reader */ + part->playbin = gst_element_factory_make ("playbin", "playbin"); + if (part->playbin == NULL) { + g_printerr ("Failed to create gst_element_factory playbin; check your installation\n"); + return; + + } + + uri = g_filename_to_uri (part->filename, NULL, NULL); + g_object_set (part->playbin, "uri", uri, NULL); + g_free (uri); + set_audiosink (part->playbin); + + bus = gst_element_get_bus (part->playbin); + part->bus_id = gst_bus_add_watch (bus, gst_callback, part); + gst_object_unref (bus); + + } else { + g_printerr ("GStreamer failed to initialize: %s",error ? error->message : ""); + g_error_free (error); + } + } + + gst_element_get_state (part->playbin, &cur_state, NULL, 0); + + if (cur_state >= GST_STATE_PAUSED) { + gst_element_set_state (part->playbin, GST_STATE_READY); + } + + if (part->playbin) { + /* start playing */ + gst_element_set_state (part->playbin, GST_STATE_PLAYING); + } +} + +static GtkWidget * +add_button (GtkWidget *box, + const gchar *stock_icon, + GCallback cb, + gpointer data, + gboolean sensitive) +{ + GtkWidget *button; + + button = gtk_button_new_from_stock (stock_icon); + gtk_widget_set_sensitive (button, sensitive); + g_signal_connect (button, "clicked", cb, data); + + gtk_widget_show (button); + gtk_box_pack_end (GTK_BOX (box), button, TRUE, TRUE, 0); + + return button; +} + +static gboolean +emfe_audio_inline_format (EMailFormatterExtension *extension, + EMailFormatter *formatter, + EMailFormatterContext *context, + EMailPart *part, + CamelStream *stream, + GCancellable *cancellable) +{ + gchar *str; + + str = g_strdup_printf ( + "<object type=\"application/vnd.evolution.widget.audio-inline\" " + "width=\"100%%\" height=\"auto\" data=\"%s\" id=\"%s\"></object>", + part->id, part->id); + + camel_stream_write_string (stream, str, cancellable, NULL); + + g_free (str); + + return TRUE; +} + +static GtkWidget * +emfe_audio_inline_get_widget (EMailFormatterExtension *extension, + EMailPartList *context, + EMailPart *part, + GHashTable *params) +{ + GtkWidget *box; + EMailPartAudioInline *ai_part; + + g_return_val_if_fail (E_MAIL_PART_IS (part, EMailPartAudioInline), NULL); + ai_part = (EMailPartAudioInline *) part; + + /* it is OK to call UI functions here, since we are called from UI thread */ + box = gtk_hbutton_box_new (); + ai_part->play_button = g_object_ref ( + add_button (box, GTK_STOCK_MEDIA_PLAY, + G_CALLBACK (play_clicked), part, TRUE)); + ai_part->pause_button = g_object_ref ( + add_button (box, GTK_STOCK_MEDIA_PAUSE, + G_CALLBACK (pause_clicked), part, FALSE)); + ai_part->stop_button = g_object_ref ( + add_button (box, GTK_STOCK_MEDIA_STOP, + G_CALLBACK (stop_clicked), part, FALSE)); + + gtk_widget_show (box); + + return box; +} + +static const gchar * +emfe_audio_inline_get_display_name (EMailFormatterExtension *extension) +{ + return _("Audio Player"); +} + +static const gchar * +emfe_audio_inline_get_description (EMailFormatterExtension *extension) +{ + return _("Play the attachment in embedded audio player"); +} + +static const gchar ** +emfe_audio_inline_mime_types (EMailExtension *extension) +{ + return formatter_mime_types; +} + +static void +e_mail_formatter_audio_inline_constructed (GObject *object) +{ + EExtensible *extensible; + EMailExtensionRegistry *reg; + + extensible = e_extension_get_extensible (E_EXTENSION (object)); + reg = E_MAIL_EXTENSION_REGISTRY (extensible); + + e_mail_extension_registry_add_extension (reg, E_MAIL_EXTENSION (object)); +} + +static void +e_mail_formatter_audio_inline_class_init (EMailFormatterAudioInlineClass *klass) +{ + GObjectClass *object_class; + EExtensionClass *extension_class; + + e_mail_formatter_audio_inline_parent_class = g_type_class_peek_parent (klass); + + object_class = G_OBJECT_CLASS (klass); + object_class->constructed = e_mail_formatter_audio_inline_constructed; + + extension_class = E_EXTENSION_CLASS (klass); + extension_class->extensible_type = E_TYPE_MAIL_FORMATTER_EXTENSION_REGISTRY; +} + +static void +e_mail_formatter_formatter_extension_interface_init (EMailFormatterExtensionInterface *iface) +{ + iface->format = emfe_audio_inline_format; + iface->get_widget = emfe_audio_inline_get_widget; + iface->get_display_name = emfe_audio_inline_get_display_name; + iface->get_description = emfe_audio_inline_get_description; +} + +static void +e_mail_formatter_mail_extension_interface_init (EMailExtensionInterface *iface) +{ + iface->mime_types = emfe_audio_inline_mime_types; +} + +static void +e_mail_formatter_audio_inline_init (EMailFormatterAudioInline *formatter) +{ + +} + +void +e_mail_formatter_audio_inline_type_register (GTypeModule *type_module) +{ + e_mail_formatter_audio_inline_register_type (type_module); +} + +static void +e_mail_formatter_audio_inline_class_finalize (EMailFormatterAudioInlineClass *klass) +{ + +} diff --git a/modules/audio-inline/e-mail-formatter-audio-inline.h b/modules/audio-inline/e-mail-formatter-audio-inline.h new file mode 100644 index 0000000000..1960f382da --- /dev/null +++ b/modules/audio-inline/e-mail-formatter-audio-inline.h @@ -0,0 +1,30 @@ +/* + * e-mail-formatter-audio-inline.h + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see <http://www.gnu.org/licenses/> + * + */ + +#ifndef E_MAIL_FORMATTER_AUDIO_INLINE_H +#define E_MAIL_FORMATTER_AUDIO_INLINE_H + +#include <glib-object.h> + +G_BEGIN_DECLS + +void e_mail_formatter_audio_inline_type_register (GTypeModule *type_module); + +G_END_DECLS + +#endif /* E_MAIL_FORMATTER_AUDIO_INLINE_H */ diff --git a/modules/audio-inline/e-mail-parser-audio-inline.c b/modules/audio-inline/e-mail-parser-audio-inline.c new file mode 100644 index 0000000000..0e872971f4 --- /dev/null +++ b/modules/audio-inline/e-mail-parser-audio-inline.c @@ -0,0 +1,199 @@ +/* + * e-mail-parser-audio-inline.c + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see <http://www.gnu.org/licenses/> + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <string.h> +#include <gtk/gtk.h> +#include <glib.h> +#include <glib/gi18n.h> +#include <glib/gstdio.h> + +#include "e-mail-parser-audio-inline.h" +#include "e-mail-part-audio-inline.h" + +#include <camel/camel.h> + +#include <em-format/e-mail-extension-registry.h> +#include <em-format/e-mail-parser-extension.h> +#include <em-format/e-mail-part.h> + +#include <libebackend/libebackend.h> + +#define d(x) + +typedef struct _EMailParserInlineAudio { + EExtension parent; +} EMailParserAudioInline; + +typedef struct _EMailParserAudioInlineClass { + EExtensionClass parent_class; +} EMailParserAudioInlineClass; + +GType e_mail_parser_audio_inline_get_type (void); +static void e_mail_parser_mail_extension_interface_init (EMailExtensionInterface *iface); +static void e_mail_parser_parser_extension_interface_init (EMailParserExtensionInterface *iface); + +G_DEFINE_DYNAMIC_TYPE_EXTENDED ( + EMailParserAudioInline, + e_mail_parser_audio_inline, + E_TYPE_EXTENSION, + 0, + G_IMPLEMENT_INTERFACE_DYNAMIC ( + E_TYPE_MAIL_EXTENSION, + e_mail_parser_mail_extension_interface_init) + G_IMPLEMENT_INTERFACE_DYNAMIC ( + E_TYPE_MAIL_PARSER_EXTENSION, + e_mail_parser_parser_extension_interface_init)); + +static const gchar* parser_mime_types[] = { "audio/ac3", "audio/x-ac3", + "audio/basic", "audio/mpeg", + "audio/x-mpeg", "audio/mpeg3", + "audio/x-mpeg3", "audio/mp3", + "audio/x-mp3", "audio/mp4", + "audio/flac", "audio/x-flac", + "audio/mod", "audio/x-mod", + "audio/x-wav", "audio/microsoft-wav", + "audio/x-wma", "audio/x-ms-wma", + "application/ogg", "application/x-ogg", + NULL }; + +static void +mail_part_audio_inline_free (EMailPart *mail_part) +{ + EMailPartAudioInline *ai_part = (EMailPartAudioInline *) mail_part; + + g_clear_object (&ai_part->play_button); + g_clear_object (&ai_part->pause_button); + g_clear_object (&ai_part->stop_button); + + if (ai_part->filename) { + g_unlink (ai_part->filename); + g_free (ai_part->filename); + ai_part->filename = NULL; + } + + if (ai_part->bus_id) { + g_source_remove (ai_part->bus_id); + ai_part->bus_id = 0; + } + + if (ai_part->playbin) { + gst_element_set_state (ai_part->playbin, GST_STATE_NULL); + gst_object_unref (ai_part->playbin); + ai_part->playbin = NULL; + } +} + +static GSList * +empe_audio_inline_parse (EMailParserExtension *extension, + EMailParser *parser, + CamelMimePart *part, + GString *part_id, + GCancellable *cancellable) +{ + EMailPartAudioInline *mail_part; + gint len; + + len = part_id->len; + g_string_append (part_id, ".org-gnome-audio-inline-button-panel"); + + d(printf ("audio inline formatter: format classid %s\n", part_id->str)); + + mail_part = (EMailPartAudioInline *) e_mail_part_subclass_new ( + part, part_id->str, sizeof (EMailPartAudioInline), + (GFreeFunc) mail_part_audio_inline_free); + mail_part->parent.mime_type = camel_content_type_simple ( + camel_mime_part_get_content_type (part)); + mail_part->parent.is_attachment = TRUE; + g_string_truncate (part_id, len); + + return e_mail_parser_wrap_as_attachment ( + parser, part, g_slist_append (NULL, mail_part), + part_id, cancellable); +} + +static guint32 +empe_audio_inline_get_flags (EMailParserExtension *extension) +{ + return E_MAIL_PARSER_EXTENSION_INLINE_DISPOSITION; +} + +static const gchar ** +empe_mime_types (EMailExtension *extension) +{ + return parser_mime_types; +} + +void +e_mail_parser_audio_inline_type_register (GTypeModule *type_module) +{ + e_mail_parser_audio_inline_register_type (type_module); +} + +static void +e_mail_parser_mail_extension_interface_init (EMailExtensionInterface *iface) +{ + iface->mime_types = empe_mime_types; +} + +static void +e_mail_parser_parser_extension_interface_init (EMailParserExtensionInterface *iface) +{ + iface->parse = empe_audio_inline_parse; + iface->get_flags = empe_audio_inline_get_flags; +} + +static void +e_mail_parser_audio_inline_constructed (GObject *object) +{ + EExtensible *extensible; + EMailExtensionRegistry *reg; + + extensible = e_extension_get_extensible (E_EXTENSION (object)); + reg = E_MAIL_EXTENSION_REGISTRY (extensible); + + e_mail_extension_registry_add_extension (reg, E_MAIL_EXTENSION (object)); +} + +static void +e_mail_parser_audio_inline_class_init (EMailParserAudioInlineClass *klass) +{ + GObjectClass *object_class; + EExtensionClass *extension_class; + + e_mail_parser_audio_inline_parent_class = g_type_class_peek_parent (klass); + + object_class = G_OBJECT_CLASS (klass); + object_class->constructed = e_mail_parser_audio_inline_constructed; + + extension_class = E_EXTENSION_CLASS (klass); + extension_class->extensible_type = E_TYPE_MAIL_PARSER_EXTENSION_REGISTRY; +} + +static void +e_mail_parser_audio_inline_class_finalize (EMailParserAudioInlineClass *klass) +{ + +} + +static void +e_mail_parser_audio_inline_init (EMailParserAudioInline *self) +{ +} diff --git a/modules/audio-inline/e-mail-parser-audio-inline.h b/modules/audio-inline/e-mail-parser-audio-inline.h new file mode 100644 index 0000000000..8c80becb20 --- /dev/null +++ b/modules/audio-inline/e-mail-parser-audio-inline.h @@ -0,0 +1,30 @@ +/* + * e-mail-parser-audio-inline.h + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see <http://www.gnu.org/licenses/> + * + */ + +#ifndef E_MAIL_PARSER_AUDIO_INLINE_H +#define E_MAIL_PARSER_AUDIO_INLINE_H + +#include <glib-object.h> + +G_BEGIN_DECLS + +void e_mail_parser_audio_inline_type_register (GTypeModule *type_module); + +G_END_DECLS + +#endif /* E_MAIL_PARSER_AUDIO_INLINE_H */ diff --git a/modules/audio-inline/e-mail-part-audio-inline.h b/modules/audio-inline/e-mail-part-audio-inline.h new file mode 100644 index 0000000000..e087ecdff6 --- /dev/null +++ b/modules/audio-inline/e-mail-part-audio-inline.h @@ -0,0 +1,46 @@ +/* + * e-mail-part-audio-inline.h + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see <http://www.gnu.org/licenses/> + * + */ + +#ifndef E_MAIL_PART_AUDIO_INLINE_H +#define E_MAIL_PART_AUDIO_INLINE_H + +#include <glib-object.h> + +#include <em-format/e-mail-part.h> +#include <gst/gst.h> + +G_BEGIN_DECLS + +typedef struct _EMailPartAudioInline EMailPartAudioInline; + +struct _EMailPartAudioInline { + EMailPart parent; + + gchar *filename; + GstElement *playbin; + gulong bus_id; + GstState target_state; + GtkWidget *play_button; + GtkWidget *pause_button; + GtkWidget *stop_button; +}; + +G_END_DECLS + +#endif /* E_MAIL_PART_AUDIO_INLINE_H */ + diff --git a/modules/audio-inline/evolution-module-audio-inline.c b/modules/audio-inline/evolution-module-audio-inline.c new file mode 100644 index 0000000000..b5dffb183e --- /dev/null +++ b/modules/audio-inline/evolution-module-audio-inline.c @@ -0,0 +1,54 @@ +/* + * evolution-module-audio-inline.c + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see <http://www.gnu.org/licenses/> + * + */ + +#include "e-mail-formatter-audio-inline.h" +#include "e-mail-parser-audio-inline.h" + +#include <gmodule.h> + +void e_module_load (GTypeModule *type_module); +void e_module_unload (GTypeModule *type_module); +const gchar * g_module_check_init (GModule *module); + +G_MODULE_EXPORT void +e_module_load (GTypeModule *type_module) +{ + /* Register dynamically loaded types. */ + + e_mail_parser_audio_inline_type_register (type_module); + e_mail_formatter_audio_inline_type_register (type_module); +} + +G_MODULE_EXPORT void +e_module_unload (GTypeModule *type_module) +{ +} + +G_MODULE_EXPORT const gchar * +g_module_check_init (GModule *module) +{ + /* FIXME Until mail is split into a module library and a + * reusable shared library, prevent the module from + * being unloaded. Unloading the module resets all + * static variables, which screws up foo_get_type() + * functions among other things. */ + g_module_make_resident (module); + + return NULL; +} + diff --git a/modules/bogofilter/evolution-bogofilter.c b/modules/bogofilter/evolution-bogofilter.c index 0467c0f654..7d00888565 100644 --- a/modules/bogofilter/evolution-bogofilter.c +++ b/modules/bogofilter/evolution-bogofilter.c @@ -16,6 +16,10 @@ * */ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + #include <config.h> #include <sys/types.h> #include <sys/wait.h> diff --git a/modules/itip-formatter/Makefile.am b/modules/itip-formatter/Makefile.am new file mode 100644 index 0000000000..84fd8830a3 --- /dev/null +++ b/modules/itip-formatter/Makefile.am @@ -0,0 +1,51 @@ +module_LTLIBRARIES = module-itip-formatter.la + +module_itip_formatter_la_CPPFLAGS = \ + $(AM_CPPFLAGS) \ + -I$(top_srcdir) \ + -I$(top_srcdir)/widgets \ + -DEVOLUTION_PRIVDATADIR=\""$(privdatadir)"\" \ + -DG_LOG_DOMAIN=\"evolution-module-itip-formatter\" \ + $(EVOLUTION_DATA_SERVER_CFLAGS) \ + $(GNOME_PLATFORM_CFLAGS) + +module_itip_formatter_la_SOURCES = \ + e-conflict-search-selector.c \ + e-conflict-search-selector.h \ + e-mail-formatter-itip.c \ + e-mail-formatter-itip.h \ + e-mail-parser-itip.c \ + e-mail-parser-itip.h \ + e-source-conflict-search.c \ + e-sourec-conflict-search.h \ + itip-view.c \ + itip-view.h \ + evolution-module-itip-formatter.c + +module_itip_formatter_la_LIBADD = \ + $(top_builddir)/e-util/libeutil.la \ + $(top_builddir)/calendar/gui/libevolution-calendar.la \ + $(top_builddir)/mail/libevolution-mail.la \ + $(top_builddir)/shell/libeshell.la \ + $(top_builddir)/em-format/libemformat.la \ + $(top_builddir)/widgets/misc/libemiscwidgets.la \ + $(top_builddir)/libemail-utils/libemail-utils.la \ + $(top_builddir)/libemail-engine/libemail-engine.la \ + $(top_builddir)/libevolution-utils/libevolution-utils.la \ + $(EVOLUTION_DATA_SERVER_LIBS) \ + $(GNOME_PLATFORM_LIBS) + +module_itip_formatter_la_LDFLAGS = \ + -avoid-version -module $(NO_UNDEFINED) + +error_DATA = org-gnome-itip-formatter.error.xml +errordir = $(privdatadir)/errors + +BUILT_SOURCES = $(error_DATA) + +CLEANFILES = $(BUILT_SOURCES) + +EXTRA_DIST = \ + org-gnome-itip-formatter.error.xml + +-include $(top_srcdir)/git.mk diff --git a/plugins/itip-formatter/e-conflict-search-selector.c b/modules/itip-formatter/e-conflict-search-selector.c index 8f497f5d4f..8f497f5d4f 100644 --- a/plugins/itip-formatter/e-conflict-search-selector.c +++ b/modules/itip-formatter/e-conflict-search-selector.c diff --git a/plugins/itip-formatter/e-conflict-search-selector.h b/modules/itip-formatter/e-conflict-search-selector.h index 091e1c9328..091e1c9328 100644 --- a/plugins/itip-formatter/e-conflict-search-selector.h +++ b/modules/itip-formatter/e-conflict-search-selector.h diff --git a/modules/itip-formatter/e-mail-formatter-itip.c b/modules/itip-formatter/e-mail-formatter-itip.c new file mode 100644 index 0000000000..ebec6bc56c --- /dev/null +++ b/modules/itip-formatter/e-mail-formatter-itip.c @@ -0,0 +1,219 @@ +/* + * e-mail-formatter-itip.c + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see <http://www.gnu.org/licenses/> + * + */ + +#include "e-mail-formatter-itip.h" + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <glib/gi18n-lib.h> + +#include <em-format/e-mail-formatter-extension.h> +#include <em-format/e-mail-formatter.h> +#include <em-format/e-mail-part-utils.h> +#include <libebackend/libebackend.h> + +#include "itip-view.h" +#include "e-mail-part-itip.h" + +#define d(x) + +typedef struct _EMailFormatterItip { + EExtension parent; +} EMailFormatterItip; + +typedef struct _EMailFormatterItipClass { + EExtensionClass parent_class; +} EMailFormatterItipClass; + +GType e_mail_formatter_itip_get_type (void); +static void e_mail_formatter_formatter_extension_interface_init (EMailFormatterExtensionInterface *iface); +static void e_mail_formatter_mail_extension_interface_init (EMailExtensionInterface *iface); + +G_DEFINE_DYNAMIC_TYPE_EXTENDED ( + EMailFormatterItip, + e_mail_formatter_itip, + E_TYPE_EXTENSION, + 0, + G_IMPLEMENT_INTERFACE_DYNAMIC ( + E_TYPE_MAIL_EXTENSION, + e_mail_formatter_mail_extension_interface_init) + G_IMPLEMENT_INTERFACE_DYNAMIC ( + E_TYPE_MAIL_FORMATTER_EXTENSION, + e_mail_formatter_formatter_extension_interface_init)); + +static const gchar* formatter_mime_types[] = { "text/calendar" , NULL }; + +static gboolean +emfe_itip_format (EMailFormatterExtension *extension, + EMailFormatter *formatter, + EMailFormatterContext *context, + EMailPart *part, + CamelStream *stream, + GCancellable *cancellable) +{ + GString *buffer; + EMailPartItip *itip_part; + + g_return_val_if_fail (E_MAIL_PART_IS (part, EMailPartItip), FALSE); + itip_part = (EMailPartItip *) part; + + if (context->mode == E_MAIL_FORMATTER_MODE_PRINTING) { + buffer = g_string_sized_new (1024); + + itip_part->view = itip_view_new (itip_part, itip_part->registry); + + itip_view_init_view (itip_part->view); + itip_view_write_for_printing (itip_part->view, buffer); + + } else if (context->mode == E_MAIL_FORMATTER_MODE_RAW) { + buffer = g_string_sized_new (2048); + + itip_view_write (buffer); + + } else { + gchar *uri; + + /* mark message as containing calendar, thus it will show the + * icon in message list now on */ + if (context->message_uid && context->folder && + !camel_folder_get_message_user_flag ( + context->folder, context->message_uid, "$has_cal")) { + + camel_folder_set_message_user_flag ( + context->folder, context->message_uid, + "$has_cal", TRUE); + } + + itip_part->folder = g_object_ref (context->folder); + itip_part->uid = g_strdup (context->message_uid); + itip_part->msg = g_object_ref (context->message); + + uri = e_mail_part_build_uri (context->folder, context->message_uid, + "part_id", G_TYPE_STRING, part->id, + "mode", G_TYPE_INT, E_MAIL_FORMATTER_MODE_RAW, + NULL); + + buffer = g_string_sized_new (256); + g_string_append_printf (buffer, + "<div class=\"part-container\" " + "style=\"border: none; background: none;\">" + "<iframe width=\"100%%\" height=\"auto\"" + " frameborder=\"0\" src=\"%s\" name=\"%s\" id=\"%s\"></iframe>" + "</div>", + uri, part->id, part->id); + + g_free (uri); + } + + camel_stream_write_string (stream, buffer->str, cancellable, NULL); + + g_string_free (buffer, TRUE); + + return TRUE; +} + +static const gchar * +emfe_itip_get_display_name (EMailFormatterExtension *extension) +{ + return _("ITIP"); +} + +static const gchar * +emfe_itip_get_description (EMailFormatterExtension *extension) +{ + return _("Display part as an invitation"); +} + +static const gchar ** +emfe_itip_mime_types (EMailExtension *extension) +{ + return formatter_mime_types; +} + +static void +e_mail_formatter_itip_constructed (GObject *object) +{ + EExtensible *extensible; + EMailExtensionRegistry *reg; + + extensible = e_extension_get_extensible (E_EXTENSION (object)); + reg = E_MAIL_EXTENSION_REGISTRY (extensible); + + e_mail_extension_registry_add_extension (reg, E_MAIL_EXTENSION (object)); +} + +static void +e_mail_formatter_itip_finalize (GObject *object) +{ + EExtensible *extensible; + EMailExtensionRegistry *reg; + + extensible = e_extension_get_extensible (E_EXTENSION (object)); + reg = E_MAIL_EXTENSION_REGISTRY (extensible); + + e_mail_extension_registry_remove_extension (reg, E_MAIL_EXTENSION (object)); +} + +static void +e_mail_formatter_itip_class_init (EMailFormatterItipClass *klass) +{ + GObjectClass *object_class; + EExtensionClass *extension_class; + + e_mail_formatter_itip_parent_class = g_type_class_peek_parent (klass); + + object_class = G_OBJECT_CLASS (klass); + object_class->constructed = e_mail_formatter_itip_constructed; + object_class->finalize = e_mail_formatter_itip_finalize; + + extension_class = E_EXTENSION_CLASS (klass); + extension_class->extensible_type = E_TYPE_MAIL_FORMATTER_EXTENSION_REGISTRY; +} + +static void +e_mail_formatter_formatter_extension_interface_init (EMailFormatterExtensionInterface *iface) +{ + iface->format = emfe_itip_format; + iface->get_display_name = emfe_itip_get_display_name; + iface->get_description = emfe_itip_get_description; +} + +static void +e_mail_formatter_mail_extension_interface_init (EMailExtensionInterface *iface) +{ + iface->mime_types = emfe_itip_mime_types; +} + +static void +e_mail_formatter_itip_init (EMailFormatterItip *formatter) +{ +} + +void +e_mail_formatter_itip_type_register (GTypeModule *type_module) +{ + e_mail_formatter_itip_register_type (type_module); +} + +static void +e_mail_formatter_itip_class_finalize (EMailFormatterItipClass *klass) +{ + +} diff --git a/modules/itip-formatter/e-mail-formatter-itip.h b/modules/itip-formatter/e-mail-formatter-itip.h new file mode 100644 index 0000000000..737926d578 --- /dev/null +++ b/modules/itip-formatter/e-mail-formatter-itip.h @@ -0,0 +1,30 @@ +/* + * e-mail-formatter-itip.h + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see <http://www.gnu.org/licenses/> + * + */ + +#ifndef E_MAIL_FORMATTER_ITIP_H +#define E_MAIL_FORMATTER_ITIP_H + +#include <glib-object.h> + +G_BEGIN_DECLS + +void e_mail_formatter_itip_type_register (GTypeModule *type_module); + +G_END_DECLS + +#endif /* E_MAIL_FORMATTER_ITIP_H */ diff --git a/modules/itip-formatter/e-mail-parser-itip.c b/modules/itip-formatter/e-mail-parser-itip.c new file mode 100644 index 0000000000..f8000aa46f --- /dev/null +++ b/modules/itip-formatter/e-mail-parser-itip.c @@ -0,0 +1,314 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see <http://www.gnu.org/licenses/> + * + * + * Authors: + * JP Rosevear <jpr@novell.com> + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <string.h> +#include <gtk/gtk.h> +#include <glib/gi18n.h> + +#include "e-mail-parser-itip.h" + +#include <em-format/e-mail-extension-registry.h> +#include <em-format/e-mail-parser-extension.h> +#include <em-format/e-mail-part.h> + +#include <misc/e-attachment.h> + +#include "e-mail-part-itip.h" +#include "itip-view.h" +#include <shell/e-shell.h> + +#define CONF_KEY_DELETE "delete-processed" + +#define d(x) + +typedef struct _EMailParserItip { + EExtension parent; +} EMailParserItip; + +typedef struct _EMailParserItipClass { + EExtensionClass parent_class; +} EMailParserItipClass; + +GType e_mail_parser_itip_get_type (void); +static void e_mail_parser_mail_extension_interface_init (EMailExtensionInterface *iface); +static void e_mail_parser_parser_extension_interface_init (EMailParserExtensionInterface *iface); + +G_DEFINE_DYNAMIC_TYPE_EXTENDED ( + EMailParserItip, + e_mail_parser_itip, + E_TYPE_EXTENSION, + 0, + G_IMPLEMENT_INTERFACE_DYNAMIC ( + E_TYPE_MAIL_EXTENSION, + e_mail_parser_mail_extension_interface_init) + G_IMPLEMENT_INTERFACE_DYNAMIC ( + E_TYPE_MAIL_PARSER_EXTENSION, + e_mail_parser_parser_extension_interface_init)); + +static const gchar* parser_mime_types[] = { "text/calendar", NULL }; + +static void +mail_part_itip_free (EMailPart *mail_part) +{ + EMailPartItip *pitip = (EMailPartItip *) mail_part; + gint i; + + g_cancellable_cancel (pitip->cancellable); + g_clear_object (&pitip->cancellable); + g_clear_object (&pitip->registry); + + for (i = 0; i < E_CAL_CLIENT_SOURCE_TYPE_LAST; i++) { + g_hash_table_destroy (pitip->clients[i]); + pitip->clients[i] = NULL; + } + + g_free (pitip->vcalendar); + pitip->vcalendar = NULL; + + if (pitip->comp) { + g_object_unref (pitip->comp); + pitip->comp = NULL; + } + + if (pitip->top_level) { + icalcomponent_free (pitip->top_level); + pitip->top_level = NULL; + } + + if (pitip->main_comp) { + icalcomponent_free (pitip->main_comp); + pitip->main_comp = NULL; + } + pitip->ical_comp = NULL; + + g_free (pitip->calendar_uid); + pitip->calendar_uid = NULL; + + g_free (pitip->from_address); + pitip->from_address = NULL; + g_free (pitip->from_name); + pitip->from_name = NULL; + g_free (pitip->to_address); + pitip->to_address = NULL; + g_free (pitip->to_name); + pitip->to_name = NULL; + g_free (pitip->delegator_address); + pitip->delegator_address = NULL; + g_free (pitip->delegator_name); + pitip->delegator_name = NULL; + g_free (pitip->my_address); + pitip->my_address = NULL; + g_free (pitip->uid); + g_hash_table_destroy (pitip->real_comps); + + g_clear_object (&pitip->view); +} + +/******************************************************************************/ + +static void +bind_itip_view (EMailPart *part, + WebKitDOMElement *element) +{ + GString *buffer; + WebKitDOMDocument *document; + ItipView *view; + EMailPartItip *pitip; + + if (!WEBKIT_DOM_IS_HTML_IFRAME_ELEMENT (element)) { + + WebKitDOMNodeList *nodes; + guint length, i; + + nodes = webkit_dom_element_get_elements_by_tag_name ( + element, "iframe"); + length = webkit_dom_node_list_get_length (nodes); + for (i = 0; i < length; i++) { + + element = WEBKIT_DOM_ELEMENT ( + webkit_dom_node_list_item (nodes, i)); + break; + } + + } + + g_return_if_fail (WEBKIT_DOM_IS_HTML_IFRAME_ELEMENT (element)); + + buffer = g_string_new (""); + document = webkit_dom_html_iframe_element_get_content_document ( + WEBKIT_DOM_HTML_IFRAME_ELEMENT (element)); + pitip = E_MAIL_PART_ITIP (part); + + view = itip_view_new (pitip, pitip->registry); + g_object_set_data_full ( + G_OBJECT (element), "view", view, + (GDestroyNotify) g_object_unref); + + itip_view_create_dom_bindings (view, + webkit_dom_document_get_document_element (document)); + + itip_view_init_view (view); + g_string_free (buffer, TRUE); +} + +/*******************************************************************************/ + +static GSList * +empe_itip_parse (EMailParserExtension *extension, + EMailParser *parser, + CamelMimePart *part, + GString *part_id, + GCancellable *cancellable) +{ + EShell *shell; + GSettings *settings; + EMailPartItip *itip_part; + CamelDataWrapper *content; + CamelStream *stream; + GByteArray *byte_array; + gint len; + + len = part_id->len; + g_string_append_printf (part_id, ".itip"); + + settings = g_settings_new ("org.gnome.evolution.plugin.itip"); + shell = e_shell_get_default (); + + itip_part = (EMailPartItip *) e_mail_part_subclass_new ( + part, part_id->str, sizeof (EMailPartItip), + (GFreeFunc) mail_part_itip_free); + itip_part->parent.mime_type = g_strdup ("text/calendar"); + itip_part->parent.bind_func = bind_itip_view; + itip_part->delete_message = g_settings_get_boolean (settings, CONF_KEY_DELETE); + itip_part->has_organizer = FALSE; + itip_part->no_reply_wanted = FALSE; + itip_part->part = part; + itip_part->cancellable = g_cancellable_new (); + itip_part->real_comps = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); + itip_part->registry = g_object_ref (e_shell_get_registry (shell)); + + g_object_unref (settings); + + /* This is non-gui thread. Download the part for using in the main thread */ + content = camel_medium_get_content ((CamelMedium *) part); + + byte_array = g_byte_array_new (); + stream = camel_stream_mem_new_with_byte_array (byte_array); + camel_data_wrapper_decode_to_stream_sync (content, stream, NULL, NULL); + + if (byte_array->len == 0) + itip_part->vcalendar = NULL; + else + itip_part->vcalendar = g_strndup ( + (gchar *) byte_array->data, byte_array->len); + + g_object_unref (stream); + g_string_truncate (part_id, len); + + return g_slist_append (NULL, itip_part); +} + +static guint32 +empe_itip_get_flags (EMailParserExtension *extension) +{ + return E_MAIL_PARSER_EXTENSION_INLINE_DISPOSITION; +} + +static const gchar ** +empe_mime_types (EMailExtension *extension) +{ + return parser_mime_types; +} + +void +e_mail_parser_itip_type_register (GTypeModule *type_module) +{ + e_mail_parser_itip_register_type (type_module); +} + +static void +e_mail_parser_mail_extension_interface_init (EMailExtensionInterface *iface) +{ + iface->mime_types = empe_mime_types; +} + +static void +e_mail_parser_parser_extension_interface_init (EMailParserExtensionInterface *iface) +{ + iface->parse = empe_itip_parse; + iface->get_flags = empe_itip_get_flags; +} + +static void +e_mail_parser_itip_constructed (GObject *object) +{ + EExtensible *extensible; + EMailExtensionRegistry *reg; + + extensible = e_extension_get_extensible (E_EXTENSION (object)); + reg = E_MAIL_EXTENSION_REGISTRY (extensible); + + e_mail_extension_registry_add_extension (reg, E_MAIL_EXTENSION (object)); +} + +static void +e_mail_parser_itip_finalize (GObject *object) +{ + EExtensible *extensible; + EMailExtensionRegistry *reg; + + extensible = e_extension_get_extensible (E_EXTENSION (object)); + reg = E_MAIL_EXTENSION_REGISTRY (extensible); + + e_mail_extension_registry_remove_extension (reg, E_MAIL_EXTENSION (object)); +} + +static void +e_mail_parser_itip_class_init (EMailParserItipClass *klass) +{ + GObjectClass *object_class; + EExtensionClass *extension_class; + + e_mail_parser_itip_parent_class = g_type_class_peek_parent (klass); + + object_class = G_OBJECT_CLASS (klass); + object_class->constructed = e_mail_parser_itip_constructed; + object_class->finalize = e_mail_parser_itip_finalize; + + extension_class = E_EXTENSION_CLASS (klass); + extension_class->extensible_type = E_TYPE_MAIL_PARSER_EXTENSION_REGISTRY; +} + +static void +e_mail_parser_itip_class_finalize (EMailParserItipClass *klass) +{ + +} + +static void +e_mail_parser_itip_init (EMailParserItip *self) +{ +} diff --git a/modules/itip-formatter/e-mail-parser-itip.h b/modules/itip-formatter/e-mail-parser-itip.h new file mode 100644 index 0000000000..956af460d0 --- /dev/null +++ b/modules/itip-formatter/e-mail-parser-itip.h @@ -0,0 +1,30 @@ +/* + * e-mail-parser-itip.h + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see <http://www.gnu.org/licenses/> + * + */ + +#ifndef E_MAIL_PARSER_ITIP_H +#define E_MAIL_PARSER_ITIP_H + +#include <glib-object.h> + +G_BEGIN_DECLS + +void e_mail_parser_itip_type_register (GTypeModule *type_module); + +G_END_DECLS + +#endif /* E_MAIL_PARSER_ITIP_H */ diff --git a/modules/itip-formatter/e-mail-part-itip.h b/modules/itip-formatter/e-mail-part-itip.h new file mode 100644 index 0000000000..d1d577a675 --- /dev/null +++ b/modules/itip-formatter/e-mail-part-itip.h @@ -0,0 +1,123 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see <http://www.gnu.org/licenses/> + * + */ + +#ifndef E_MAIL_PART_ITIP_H +#define E_MAIL_PART_ITIP_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <libecal/libecal.h> +#include <libedataserverui/libedataserverui.h> +#include <libebackend/libebackend.h> + +#include <em-format/e-mail-part.h> + +#include "itip-view.h" + +#define E_MAIL_PART_ITIP(p) ((EMailPartItip *) p) + +G_BEGIN_DECLS + +typedef struct _EMailPartItip EMailPartItip; + +struct _EMailPartItip { + EMailPart parent; + + CamelFolder *folder; + CamelMimeMessage *msg; + CamelMimePart *part; + + gchar *uid; + + ESourceRegistry *registry; + GHashTable *clients[E_CAL_CLIENT_SOURCE_TYPE_LAST]; + + ECalClient *current_client; + ECalClientSourceType type; + + /* cancelled when freeing the puri */ + GCancellable *cancellable; + + gchar *vcalendar; + ECalComponent *comp; + icalcomponent *main_comp; + icalcomponent *ical_comp; + icalcomponent *top_level; + icalcompiter iter; + icalproperty_method method; + time_t start_time; + time_t end_time; + + gint current; + gint total; + + gchar *calendar_uid; + + gchar *from_address; + gchar *from_name; + gchar *to_address; + gchar *to_name; + gchar *delegator_address; + gchar *delegator_name; + gchar *my_address; + gint view_only; + + guint progress_info_id; + + gboolean delete_message; + /* a reply can only be sent if and only if there is an organizer */ + gboolean has_organizer; + /* + * Usually replies are sent unless the user unchecks that option. + * There are some cases when the default is not to sent a reply + * (but the user can still chose to do so by checking the option): + * - the organizer explicitly set RSVP=FALSE for the current user + * - the event has no ATTENDEEs: that's the case for most non-meeting + * events + * + * The last case is meant for forwarded non-meeting + * events. Traditionally Evolution hasn't offered to send a + * reply, therefore the updated implementation mimics that + * behavior. + * + * Unfortunately some software apparently strips all ATTENDEEs + * when forwarding a meeting; in that case sending a reply is + * also unchecked by default. So the check for ATTENDEEs is a + * tradeoff between sending unwanted replies in cases where + * that wasn't done in the past and not sending a possibly + * wanted reply where that wasn't possible in the past + * (because replies to forwarded events were not + * supported). Overall that should be an improvement, and the + * user can always override the default. + */ + gboolean no_reply_wanted; + + guint update_item_progress_info_id; + guint update_item_error_info_id; + ItipViewResponse update_item_response; + gboolean can_delete_invitation_from_cache; + GHashTable *real_comps; /* ESource's UID -> ECalComponent stored on the server */ + + ItipView *view; +}; + +typedef struct _EMailPartItip EMailPartItip; + +G_END_DECLS + +#endif /* E_MAIL_PART_ITIP_H */ diff --git a/plugins/itip-formatter/e-source-conflict-search.c b/modules/itip-formatter/e-source-conflict-search.c index c2f5eb6e99..c2f5eb6e99 100644 --- a/plugins/itip-formatter/e-source-conflict-search.c +++ b/modules/itip-formatter/e-source-conflict-search.c diff --git a/plugins/itip-formatter/e-source-conflict-search.h b/modules/itip-formatter/e-source-conflict-search.h index f91fcc4d43..f91fcc4d43 100644 --- a/plugins/itip-formatter/e-source-conflict-search.h +++ b/modules/itip-formatter/e-source-conflict-search.h diff --git a/modules/itip-formatter/evolution-module-itip-formatter.c b/modules/itip-formatter/evolution-module-itip-formatter.c new file mode 100644 index 0000000000..13a73a30d7 --- /dev/null +++ b/modules/itip-formatter/evolution-module-itip-formatter.c @@ -0,0 +1,75 @@ +/* + * evolution-module-itip-formatter.c + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see <http://www.gnu.org/licenses/> + * + */ + +#include "e-mail-formatter-itip.h" +#include "e-mail-parser-itip.h" + +#include <gmodule.h> +#include <gio/gio.h> + +void e_module_load (GTypeModule *type_module); +void e_module_unload (GTypeModule *type_module); +const gchar * g_module_check_init (GModule *module); + +G_MODULE_EXPORT void +e_module_load (GTypeModule *type_module) +{ + GSettings *settings; + gchar **disabled_plugins; + gint i = 0; + + settings = g_settings_new ("org.gnome.evolution"); + disabled_plugins = g_settings_get_strv (settings, "disabled-eplugins"); + + for (i = 0; disabled_plugins && disabled_plugins[i] != NULL; i++) { + + if (g_strcmp0 ( + disabled_plugins[i], + "org.gnome.evolution.itip_formatter") == 0) { + + g_strfreev (disabled_plugins); + g_object_unref (settings); + return; + } + + } + + e_mail_parser_itip_type_register (type_module); + e_mail_formatter_itip_type_register (type_module); + + g_strfreev (disabled_plugins); + g_object_unref (settings); +} + +G_MODULE_EXPORT void +e_module_unload (GTypeModule *type_module) +{ +} + +G_MODULE_EXPORT const gchar * +g_module_check_init (GModule *module) +{ + /* FIXME Until mail is split into a module library and a + * reusable shared library, prevent the module from + * being unloaded. Unloading the module resets all + * static variables, which screws up foo_get_type() + * functions among other things. */ + g_module_make_resident (module); + + return NULL; +} diff --git a/plugins/itip-formatter/itip-formatter.c b/modules/itip-formatter/itip-view.c index 6780d09505..5e655eb74d 100644 --- a/plugins/itip-formatter/itip-formatter.c +++ b/modules/itip-formatter/itip-view.c @@ -25,11 +25,14 @@ #endif #include <string.h> -#include <gtk/gtk.h> #include <glib/gi18n.h> - -#include <libecal/libecal.h> #include <libedataserverui/libedataserverui.h> +#include <libedataserver/libedataserver.h> + +#include <e-util/e-util.h> +#include <e-util/e-unicode.h> +#include <calendar/gui/itip-utils.h> +#include <webkit/webkitdom.h> #include <libevolution-utils/e-alert-dialog.h> #include <e-util/e-mktemp.h> @@ -42,109 +45,3060 @@ #include <libemail-engine/mail-folder-cache.h> #include <libemail-engine/mail-tools.h> -#include <mail/em-format-hook.h> #include <mail/em-config.h> -#include <mail/em-format-html.h> #include <mail/em-utils.h> -#include <misc/e-attachment.h> - #include <calendar/gui/itip-utils.h> #include "e-conflict-search-selector.h" #include "e-source-conflict-search.h" #include "itip-view.h" - -#define CONF_KEY_DELETE "delete-processed" +#include "e-mail-part-itip.h" #define d(x) -struct _ItipPURI { - EMFormatPURI puri; +#define MEETING_ICON "stock_new-meeting" - const EMFormatHandler *handle; - CamelFolder *folder; - CamelMimeMessage *msg; - CamelMimePart *part; +#define ITIP_VIEW_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE \ + ((obj), ITIP_TYPE_VIEW, ItipViewPrivate)) - gchar *uid; +G_DEFINE_TYPE (ItipView, itip_view, G_TYPE_OBJECT) + +typedef struct { + ItipViewInfoItemType type; + gchar *message; + + guint id; +} ItipViewInfoItem; +struct _ItipViewPrivate { ESourceRegistry *registry; - GHashTable *clients[E_CAL_CLIENT_SOURCE_TYPE_LAST]; + gulong source_added_id; + gulong source_removed_id; + gchar *extension_name; - ECalClient *current_client; + ItipViewMode mode; ECalClientSourceType type; - /* cancelled when freeing the puri */ - GCancellable *cancellable; + gchar *sender; + gchar *organizer; + gchar *organizer_sentby; + gchar *delegator; + gchar *attendee; + gchar *attendee_sentby; + gchar *proxy; - gchar *vcalendar; - ECalComponent *comp; - icalcomponent *main_comp; - icalcomponent *ical_comp; - icalcomponent *top_level; - icalcompiter iter; - icalproperty_method method; - time_t start_time; - time_t end_time; - - gint current; - gint total; - - gchar *calendar_uid; - - gchar *from_address; - gchar *from_name; - gchar *to_address; - gchar *to_name; - gchar *delegator_address; - gchar *delegator_name; - gchar *my_address; - gint view_only; - - guint progress_info_id; - - gboolean delete_message; - /* a reply can only be sent if and only if there is an organizer */ - gboolean has_organizer; - /* - * Usually replies are sent unless the user unchecks that option. - * There are some cases when the default is not to sent a reply - * (but the user can still chose to do so by checking the option): - * - the organizer explicitly set RSVP=FALSE for the current user - * - the event has no ATTENDEEs: that's the case for most non-meeting - * events - * - * The last case is meant for forwarded non-meeting - * events. Traditionally Evolution hasn't offered to send a - * reply, therefore the updated implementation mimics that - * behavior. - * - * Unfortunately some software apparently strips all ATTENDEEs - * when forwarding a meeting; in that case sending a reply is - * also unchecked by default. So the check for ATTENDEEs is a - * tradeoff between sending unwanted replies in cases where - * that wasn't done in the past and not sending a possibly - * wanted reply where that wasn't possible in the past - * (because replies to forwarded events were not - * supported). Overall that should be an improvement, and the - * user can always override the default. - */ - gboolean no_reply_wanted; + gchar *summary; + + gchar *location; + gchar *status; + gchar *comment; + + struct tm *start_tm; + gint start_tm_is_date : 1; + gchar *start_label; + const gchar *start_header; + + struct tm *end_tm; + gint end_tm_is_date : 1; + gchar *end_label; + const gchar *end_header; + + GSList *upper_info_items; + GSList *lower_info_items; + + guint next_info_item_id; + + gchar *description; + + gint buttons_sensitive : 1; - guint update_item_progress_info_id; - guint update_item_error_info_id; - ItipViewResponse update_item_response; - gboolean can_delete_invitation_from_cache; - GHashTable *real_comps; /* ESource's UID -> ECalComponent stored on the server */ + gboolean is_recur_set; + + gint needs_decline : 1; + + WebKitDOMDocument *dom_document; + EMailPartItip *itip_part; + + gchar *error; +}; + +#define TEXT_ROW_SENDER "text_row_sender" +#define TABLE_ROW_SUMMARY "table_row_summary" +#define TABLE_ROW_LOCATION "table_row_location" +#define TABLE_ROW_START_DATE "table_row_start_time" +#define TABLE_ROW_END_DATE "table_row_end_time" +#define TABLE_ROW_STATUS "table_row_status" +#define TABLE_ROW_COMMENT "table_row_comment" +#define TABLE_ROW_DESCRIPTION "table_row_description" +#define TABLE_ROW_RSVP_COMMENT "table_row_rsvp_comment" +#define TABLE_ROW_ESCB "table_row_escb" +#define TABLE_ROW_BUTTONS "table_row_buttons" +#define TABLE_ROW_ESCB_LABEL "table_row_escb_label" + +#define TABLE_BUTTONS "table_buttons" + +#define SELECT_ESOURCE "select_esource" +#define TEXTAREA_RSVP_COMMENT "textarea_rsvp_comment" + +#define CHECKBOX_RSVP "checkbox_rsvp" +#define CHECKBOX_RECUR "checkbox_recur" +#define CHECKBOX_UPDATE "checkbox_update" +#define CHECKBOX_FREE_TIME "checkbox_free_time" +#define CHECKBOX_KEEP_ALARM "checkbox_keep_alarm" +#define CHECKBOX_INHERIT_ALARM "checkbox_inherit_alarm" + +#define BUTTON_OPEN_CALENDAR "button_open_calendar" +#define BUTTON_DECLINE "button_decline" +#define BUTTON_DECLINE_ALL "button_decline_all" +#define BUTTON_ACCEPT "button_accept" +#define BUTTON_ACCEPT_ALL "button_accept_all" +#define BUTTON_TENTATIVE "button_tentative" +#define BUTTON_TENTATIVE_ALL "button_tentative_all" +#define BUTTON_SEND_INFORMATION "button_send_information" +#define BUTTON_UPDATE "button_update" +#define BUTTON_UPDATE_ATTENDEE_STATUS "button_update_attendee_status" +#define BUTTON_SAVE "button_save" + +#define TABLE_UPPER_ITIP_INFO "table_upper_itip_info" +#define TABLE_LOWER_ITIP_INFO "table_lower_itip_info" + +#define DIV_ITIP_CONTENT "div_itip_content" +#define DIV_ITIP_ERROR "div_itip_error" + +enum { + PROP_0, + PROP_EXTENSION_NAME, + PROP_REGISTRY }; -void format_itip (EPlugin *ep, EMFormatHookTarget *target); -GtkWidget *itip_formatter_page_factory (EPlugin *ep, EConfigHookItemFactoryData *hook_data); -gint e_plugin_lib_enable (EPlugin *ep, gint enable); +enum { + SOURCE_SELECTED, + RESPONSE, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + +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, + gboolean is_date, + gchar *buffer, + gint buffer_size) +{ + gchar *format; + struct tm tomorrow_tm, week_tm; + + /* Calculate a normalized "tomorrow" */ + tomorrow_tm = *current_tm; + /* Don't need this if date is in the past. Also, year assumption won't fail. */ + if (date_tm->tm_year >= current_tm->tm_year && tomorrow_tm.tm_mday == time_days_in_month (current_tm->tm_year + 1900, current_tm->tm_mon)) { + tomorrow_tm.tm_mday = 1; + if (tomorrow_tm.tm_mon == 11) { + tomorrow_tm.tm_mon = 1; + tomorrow_tm.tm_year++; + } else { + tomorrow_tm.tm_mon++; + } + } else { + tomorrow_tm.tm_mday++; + } + + /* Calculate a normalized "next seven days" */ + week_tm = *current_tm; + /* Don't need this if date is in the past. Also, year assumption won't fail. */ + if (date_tm->tm_year >= current_tm->tm_year && week_tm.tm_mday + 6 > time_days_in_month (date_tm->tm_year + 1900, date_tm->tm_mon)) { + week_tm.tm_mday = (week_tm.tm_mday + 6) % time_days_in_month (date_tm->tm_year + 1900, date_tm->tm_mon); + if (week_tm.tm_mon == 11) { + week_tm.tm_mon = 1; + week_tm.tm_year++; + } else { + week_tm.tm_mon++; + } + } else { + week_tm.tm_mday += 6; + } + + /* 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 (is_date || (!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 time, + * in 24-hour format, without seconds. */ + format = _("Today %H:%M"); + else + /* strftime format of 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 time, + * in 12-hour format, without seconds. */ + format = _("Today %l:%M %p"); + else + /* strftime format of a time, + * in 12-hour format. */ + format = _("Today %l:%M:%S %p"); + } + + /* Tomorrow */ + } else if (date_tm->tm_mday == tomorrow_tm.tm_mday && + date_tm->tm_mon == tomorrow_tm.tm_mon && + date_tm->tm_year == tomorrow_tm.tm_year) { + if (is_date || (!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 = _("Tomorrow"); + } else if (use_24_hour_format) { + if (!show_zero_seconds && date_tm->tm_sec == 0) + /* strftime format of a time, + * in 24-hour format, without seconds. */ + format = _("Tomorrow %H:%M"); + else + /* strftime format of a time, + * in 24-hour format. */ + format = _("Tomorrow %H:%M:%S"); + } else { + if (!show_zero_seconds && date_tm->tm_sec == 0) + /* strftime format of a time, + * in 12-hour format, without seconds. */ + format = _("Tomorrow %l:%M %p"); + else + /* strftime format of a time, + * in 12-hour format. */ + format = _("Tomorrow %l:%M:%S %p"); + } + + /* Within 6 days */ + } else if ((date_tm->tm_year >= current_tm->tm_year && + date_tm->tm_mon >= current_tm->tm_mon && + date_tm->tm_mday >= current_tm->tm_mday) && + + (date_tm->tm_year < week_tm.tm_year || + + (date_tm->tm_year == week_tm.tm_year && + date_tm->tm_mon < week_tm.tm_mon) || + + (date_tm->tm_year == week_tm.tm_year && + date_tm->tm_mon == week_tm.tm_mon && + date_tm->tm_mday < week_tm.tm_mday))) { + if (is_date || (!show_midnight && date_tm->tm_hour == 0 + && date_tm->tm_min == 0 && date_tm->tm_sec == 0)) { + /* strftime format of a weekday. */ + format = _("%A"); + } else if (use_24_hour_format) { + if (!show_zero_seconds && date_tm->tm_sec == 0) + /* strftime format of a weekday and a + * time, in 24-hour format, without seconds. */ + format = _("%A %H:%M"); + else + /* strftime format of a weekday 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 and a + * time, in 12-hour format, without seconds. */ + format = _("%A %l:%M %p"); + else + /* strftime format of a weekday and a + * time, in 12-hour format. */ + format = _("%A %l:%M:%S %p"); + } + + /* This Year */ + } else if (date_tm->tm_year == current_tm->tm_year) { + if (is_date || (!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 + * without a year. */ + 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 + * without a year and a time, + * in 24-hour format, without seconds. */ + format = _("%A, %B %e %H:%M"); + else + /* strftime format of a weekday, a date without a year + * 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 without a year + * and a time, in 12-hour format, without seconds. */ + format = _("%A, %B %e %l:%M %p"); + else + /* strftime format of a weekday, a date without a year + * and a time, in 12-hour format. */ + format = _("%A, %B %e %l:%M:%S %p"); + } + } else { + if (is_date || (!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 %l:%M %p"); + else + /* strftime format of a weekday, a date and a + * time, in 12-hour format. */ + format = _("%A, %B %e, %Y %l:%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_fix_am_pm (buffer, buffer_size, format, date_tm) == 0) + buffer[0] = '\0'; +} + +static gchar * +dupe_first_bold (const gchar *format, + const gchar *first, + const gchar *second) +{ + gchar *f, *s, *res; + + f = g_markup_printf_escaped ("<b>%s</b>", first ? first : ""); + s = g_markup_escape_text (second ? second : "", -1); + + res = g_strdup_printf (format, f, s); + + g_free (f); + g_free (s); + + return res; +} + +static gchar * +set_calendar_sender_text (ItipView *view) +{ + ItipViewPrivate *priv; + const gchar *organizer, *attendee; + gchar *sender = NULL; + gchar *on_behalf_of = NULL; + + priv = view->priv; + + organizer = priv->organizer ? priv->organizer : _("An unknown person"); + attendee = priv->attendee ? priv->attendee : _("An unknown person"); + + /* The current account ID (i.e. the delegatee) is receiving a copy of the request/response. Here we ask the delegatee to respond/accept on behalf of the delegator. */ + if (priv->organizer && priv->proxy) + on_behalf_of = dupe_first_bold (_("Please respond on behalf of %s"), priv->proxy, NULL); + else if (priv->attendee && priv->proxy) + on_behalf_of = dupe_first_bold (_("Received on behalf of %s"), priv->proxy, NULL); + + switch (priv->mode) { + case ITIP_VIEW_MODE_PUBLISH: + if (priv->organizer_sentby) + sender = dupe_first_bold (_("%s through %s has published the following meeting information:"), organizer, priv->organizer_sentby); + else + sender = dupe_first_bold (_("%s has published the following meeting information:"), organizer, NULL); + break; + case ITIP_VIEW_MODE_REQUEST: + /* FIXME is the delegator stuff handled correctly here? */ + if (priv->delegator) { + sender = dupe_first_bold (_("%s has delegated the following meeting to you:"), priv->delegator, NULL); + } else { + if (priv->organizer_sentby) + sender = dupe_first_bold (_("%s through %s requests your presence at the following meeting:"), organizer, priv->organizer_sentby); + else + sender = dupe_first_bold (_("%s requests your presence at the following meeting:"), organizer, NULL); + } + break; + case ITIP_VIEW_MODE_ADD: + /* FIXME What text for this? */ + if (priv->organizer_sentby) + sender = dupe_first_bold (_("%s through %s wishes to add to an existing meeting:"), organizer, priv->organizer_sentby); + else + sender = dupe_first_bold (_("%s wishes to add to an existing meeting:"), organizer, NULL); + break; + case ITIP_VIEW_MODE_REFRESH: + if (priv->attendee_sentby) + sender = dupe_first_bold (_("%s through %s wishes to receive the latest information for the following meeting:"), attendee, priv->attendee_sentby); + else + sender = dupe_first_bold (_("%s wishes to receive the latest information for the following meeting:"), attendee, NULL); + break; + case ITIP_VIEW_MODE_REPLY: + if (priv->attendee_sentby) + sender = dupe_first_bold (_("%s through %s has sent back the following meeting response:"), attendee, priv->attendee_sentby); + else + sender = dupe_first_bold (_("%s has sent back the following meeting response:"), attendee, NULL); + break; + case ITIP_VIEW_MODE_CANCEL: + if (priv->organizer_sentby) + sender = dupe_first_bold (_("%s through %s has canceled the following meeting:"), organizer, priv->organizer_sentby); + else + sender = dupe_first_bold (_("%s has canceled the following meeting:"), organizer, NULL); + break; + case ITIP_VIEW_MODE_COUNTER: + if (priv->attendee_sentby) + sender = dupe_first_bold (_("%s through %s has proposed the following meeting changes."), attendee, priv->attendee_sentby); + else + sender = dupe_first_bold (_("%s has proposed the following meeting changes:"), attendee, NULL); + break; + case ITIP_VIEW_MODE_DECLINECOUNTER: + if (priv->organizer_sentby) + sender = dupe_first_bold (_("%s through %s has declined the following meeting changes:"), organizer, priv->organizer_sentby); + else + sender = dupe_first_bold (_("%s has declined the following meeting changes:"), organizer, NULL); + break; + default: + break; + } + + if (sender && on_behalf_of) { + gchar *tmp; + tmp = g_strjoin (NULL, sender, "\n", on_behalf_of, NULL); + g_free (sender); + sender = tmp; + } + + g_free (on_behalf_of); + + return sender; +} + +static gchar * +set_tasklist_sender_text (ItipView *view) +{ + ItipViewPrivate *priv; + const gchar *organizer, *attendee; + gchar *sender = NULL; + gchar *on_behalf_of = NULL; + + priv = view->priv; + + organizer = priv->organizer ? priv->organizer : _("An unknown person"); + attendee = priv->attendee ? priv->attendee : _("An unknown person"); + + /* The current account ID (i.e. the delegatee) is receiving a copy of the request/response. Here we ask the delegatee to respond/accept on behalf of the delegator. */ + if (priv->organizer && priv->proxy) + on_behalf_of = dupe_first_bold (_("Please respond on behalf of %s"), priv->proxy, NULL); + else if (priv->attendee && priv->proxy) + on_behalf_of = dupe_first_bold (_("Received on behalf of %s"), priv->proxy, NULL); + + switch (priv->mode) { + case ITIP_VIEW_MODE_PUBLISH: + if (priv->organizer_sentby) + sender = dupe_first_bold (_("%s through %s has published the following task:"), organizer, priv->organizer_sentby); + else + sender = dupe_first_bold (_("%s has published the following task:"), organizer, NULL); + break; + case ITIP_VIEW_MODE_REQUEST: + /* FIXME is the delegator stuff handled correctly here? */ + if (priv->delegator) { + sender = dupe_first_bold (_("%s requests the assignment of %s to the following task:"), organizer, priv->delegator); + } else { + if (priv->organizer_sentby) + sender = dupe_first_bold (_("%s through %s has assigned you a task:"), organizer, priv->organizer_sentby); + else + sender = dupe_first_bold (_("%s has assigned you a task:"), organizer, NULL); + } + break; + case ITIP_VIEW_MODE_ADD: + /* FIXME What text for this? */ + if (priv->organizer_sentby) + sender = dupe_first_bold (_("%s through %s wishes to add to an existing task:"), organizer, priv->organizer_sentby); + else + sender = dupe_first_bold (_("%s wishes to add to an existing task:"), organizer, NULL); + break; + case ITIP_VIEW_MODE_REFRESH: + if (priv->attendee_sentby) + sender = dupe_first_bold (_("%s through %s wishes to receive the latest information for the following assigned task:"), attendee, priv->attendee_sentby); + else + sender = dupe_first_bold (_("%s wishes to receive the latest information for the following assigned task:"), attendee, NULL); + break; + case ITIP_VIEW_MODE_REPLY: + if (priv->attendee_sentby) + sender = dupe_first_bold (_("%s through %s has sent back the following assigned task response:"), attendee, priv->attendee_sentby); + else + sender = dupe_first_bold (_("%s has sent back the following assigned task response:"), attendee, NULL); + break; + case ITIP_VIEW_MODE_CANCEL: + if (priv->organizer_sentby) + sender = dupe_first_bold (_("%s through %s has canceled the following assigned task:"), organizer, priv->organizer_sentby); + else + sender = dupe_first_bold (_("%s has canceled the following assigned task:"), organizer, NULL); + break; + case ITIP_VIEW_MODE_COUNTER: + if (priv->attendee_sentby) + sender = dupe_first_bold (_("%s through %s has proposed the following task assignment changes:"), attendee, priv->attendee_sentby); + else + sender = dupe_first_bold (_("%s has proposed the following task assignment changes:"), attendee, NULL); + break; + case ITIP_VIEW_MODE_DECLINECOUNTER: + if (priv->organizer_sentby) + sender = dupe_first_bold (_("%s through %s has declined the following assigned task:"), organizer, priv->organizer_sentby); + else + sender = dupe_first_bold (_("%s has declined the following assigned task:"), organizer, NULL); + break; + default: + break; + } + + if (sender && on_behalf_of) { + gchar *tmp; + tmp = g_strjoin (NULL, sender, "\n", on_behalf_of, NULL); + g_free (sender); + sender = tmp; + } + + g_free (on_behalf_of); + + return sender; +} + +static gchar * +set_journal_sender_text (ItipView *view) +{ + ItipViewPrivate *priv; + const gchar *organizer; + gchar *sender = NULL; + gchar *on_behalf_of = NULL; + + priv = view->priv; + + organizer = priv->organizer ? priv->organizer : _("An unknown person"); + + /* The current account ID (i.e. the delegatee) is receiving a copy of the request/response. Here we ask the delegatee to respond/accept on behalf of the delegator. */ + if (priv->organizer && priv->proxy) + on_behalf_of = dupe_first_bold (_("Please respond on behalf of %s"), priv->proxy, NULL); + else if (priv->attendee && priv->proxy) + on_behalf_of = dupe_first_bold (_("Received on behalf of %s"), priv->proxy, NULL); + + switch (priv->mode) { + case ITIP_VIEW_MODE_PUBLISH: + if (priv->organizer_sentby) + sender = dupe_first_bold (_("%s through %s has published the following memo:"), organizer, priv->organizer_sentby); + else + sender = dupe_first_bold (_("%s has published the following memo:"), organizer, NULL); + break; + case ITIP_VIEW_MODE_ADD: + /* FIXME What text for this? */ + if (priv->organizer_sentby) + sender = dupe_first_bold (_("%s through %s wishes to add to an existing memo:"), organizer, priv->organizer_sentby); + else + sender = dupe_first_bold (_("%s wishes to add to an existing memo:"), organizer, NULL); + break; + case ITIP_VIEW_MODE_CANCEL: + if (priv->organizer_sentby) + sender = dupe_first_bold (_("%s through %s has canceled the following shared memo:"), organizer, priv->organizer_sentby); + else + sender = dupe_first_bold (_("%s has canceled the following shared memo:"), organizer, NULL); + break; + default: + break; + } + + if (sender && on_behalf_of) + sender = g_strjoin (NULL, sender, "\n", on_behalf_of, NULL); + + g_free (on_behalf_of); + + return sender; +} + +static void +set_sender_text (ItipView *view) +{ + ItipViewPrivate *priv; + priv = view->priv; + + if (priv->sender) + g_free (priv->sender); + + switch (priv->type) { + case E_CAL_CLIENT_SOURCE_TYPE_EVENTS: + priv->sender = set_calendar_sender_text (view); + break; + case E_CAL_CLIENT_SOURCE_TYPE_TASKS: + priv->sender = set_tasklist_sender_text (view); + break; + case E_CAL_CLIENT_SOURCE_TYPE_MEMOS: + priv->sender = set_journal_sender_text (view); + break; + default: + priv->sender = NULL; + break; + } + + if (priv->sender && priv->dom_document) { + WebKitDOMElement *div; + + div = webkit_dom_document_get_element_by_id ( + priv->dom_document, TEXT_ROW_SENDER); + webkit_dom_html_element_set_inner_html ( + WEBKIT_DOM_HTML_ELEMENT (div), priv->sender, NULL); + } +} + +static void +update_start_end_times (ItipView *view) +{ + ItipViewPrivate *priv; + WebKitDOMElement *row, *col; + gchar buffer[256]; + time_t now; + struct tm *now_tm; + + priv = view->priv; + + now = time (NULL); + now_tm = localtime (&now); + + if (priv->start_label) + g_free (priv->start_label); + if (priv->end_label) + g_free (priv->end_label); + + #define is_same(_member) (priv->start_tm->_member == priv->end_tm->_member) + if (priv->start_tm && priv->end_tm && priv->start_tm_is_date && priv->end_tm_is_date + && is_same (tm_mday) && is_same (tm_mon) && is_same (tm_year)) { + /* it's an all day event in one particular day */ + format_date_and_time_x (priv->start_tm, now_tm, FALSE, TRUE, FALSE, priv->start_tm_is_date, buffer, 256); + priv->start_label = g_strdup (buffer); + priv->start_header = _("All day:"); + priv->end_header = NULL; + priv->end_label = NULL; + } else { + if (priv->start_tm) { + format_date_and_time_x (priv->start_tm, now_tm, FALSE, TRUE, FALSE, priv->start_tm_is_date, buffer, 256); + priv->start_header = priv->start_tm_is_date ? _("Start day:") : _("Start time:"); + priv->start_label = g_strdup (buffer); + } else { + priv->start_header = NULL; + priv->start_label = NULL; + } + + if (priv->end_tm) { + format_date_and_time_x (priv->end_tm, now_tm, FALSE, TRUE, FALSE, priv->end_tm_is_date, buffer, 256); + priv->end_header = priv->end_tm_is_date ? _("End day:") : _("End time:"); + priv->end_label = g_strdup (buffer); + } else { + priv->end_header = NULL; + priv->end_label = NULL; + } + } + #undef is_same + + if (priv->dom_document) { + row = webkit_dom_document_get_element_by_id ( + priv->dom_document, TABLE_ROW_START_DATE); + if (priv->start_header && priv->start_label) { + webkit_dom_html_element_set_hidden ( + WEBKIT_DOM_HTML_ELEMENT (row), FALSE); + + col = webkit_dom_element_get_first_element_child (row); + webkit_dom_html_element_set_inner_html ( + WEBKIT_DOM_HTML_ELEMENT (col), priv->start_header, NULL); + + col = webkit_dom_element_get_last_element_child (row); + webkit_dom_html_element_set_inner_html ( + WEBKIT_DOM_HTML_ELEMENT (col), priv->start_label, NULL); + } else { + webkit_dom_html_element_set_hidden ( + WEBKIT_DOM_HTML_ELEMENT (row), TRUE); + } + + row = webkit_dom_document_get_element_by_id ( + priv->dom_document, TABLE_ROW_END_DATE); + if (priv->end_header && priv->end_label) { + webkit_dom_html_element_set_hidden ( + WEBKIT_DOM_HTML_ELEMENT (row), FALSE); + + col = webkit_dom_element_get_first_element_child (row); + webkit_dom_html_element_set_inner_html ( + WEBKIT_DOM_HTML_ELEMENT (col), priv->end_header, NULL); + + col = webkit_dom_element_get_last_element_child (row); + webkit_dom_html_element_set_inner_html ( + WEBKIT_DOM_HTML_ELEMENT (col), priv->end_label, NULL); + } else { + webkit_dom_html_element_set_hidden ( + WEBKIT_DOM_HTML_ELEMENT (row), TRUE); + } + } +} + +static void +button_clicked_cb (WebKitDOMElement *element, + WebKitDOMEvent *event, + gpointer data) +{ + ItipViewResponse response; + gchar *responseStr; + + responseStr = webkit_dom_html_button_element_get_value ( + WEBKIT_DOM_HTML_BUTTON_ELEMENT (element)); + + response = atoi (responseStr); + + //d(printf("Clicked btton %d\n", response)); + g_signal_emit (G_OBJECT (data), signals[RESPONSE], 0, response); +} + +static void +rsvp_toggled_cb (WebKitDOMHTMLInputElement *input, + WebKitDOMEvent *event, + gpointer data) +{ + WebKitDOMElement *el; + + ItipView *view = data; + gboolean rsvp; + + rsvp = webkit_dom_html_input_element_get_checked (input); + + el = webkit_dom_document_get_element_by_id ( + view->priv->dom_document, TEXTAREA_RSVP_COMMENT); + webkit_dom_html_text_area_element_set_disabled ( + WEBKIT_DOM_HTML_TEXT_AREA_ELEMENT (el), !rsvp); +} + +static void +recur_toggled_cb (WebKitDOMHTMLInputElement *input, + WebKitDOMEvent *event, + gpointer data) +{ + ItipView *view = data; + + itip_view_set_mode (view, view->priv->mode); +} + +/* + alarm_check_toggled_cb + check1 was changed, so make the second available based on state of the first check. +*/ +static void +alarm_check_toggled_cb (WebKitDOMHTMLInputElement *check1, + WebKitDOMEvent *event, + ItipView *view) +{ + WebKitDOMElement *check2; + gchar *id = webkit_dom_html_element_get_id (WEBKIT_DOM_HTML_ELEMENT (check1)); + + if (g_strcmp0 (id, CHECKBOX_INHERIT_ALARM)) { + check2 = webkit_dom_document_get_element_by_id ( + view->priv->dom_document, CHECKBOX_KEEP_ALARM); + } else { + check2 = webkit_dom_document_get_element_by_id ( + view->priv->dom_document, CHECKBOX_INHERIT_ALARM); + } + + g_free (id); + + webkit_dom_html_input_element_set_disabled ( + WEBKIT_DOM_HTML_INPUT_ELEMENT (check2), + (webkit_dom_html_element_get_hidden ( + WEBKIT_DOM_HTML_ELEMENT (check1)) && + webkit_dom_html_input_element_get_checked (check1))); +} + +static void +source_changed_cb (WebKitDOMElement *select, + WebKitDOMEvent *event, + ItipView *view) +{ + ESource *source; + + source = itip_view_ref_source (view); + + d(printf("Source changed to '%s'\n", e_source_get_display_name (source))); + g_signal_emit (view, signals[SOURCE_SELECTED], 0, source); + + g_object_unref (source); +} + +static gchar * +parse_html_mnemonics (const gchar *label, + gchar **access_key) +{ + const gchar *pos = NULL; + gchar ak = 0; + GString *html_label = NULL; + + pos = strstr (label, "_"); + if (pos != NULL) { + ak = pos[1]; + + /* Convert to uppercase */ + if (ak >= 'a') + ak = ak - 32; + + html_label = g_string_new (""); + g_string_append_len (html_label, label, pos - label); + g_string_append_printf (html_label, "<u>%c</u>", pos[1]); + g_string_append (html_label, &pos[2]); + + if (access_key) { + if (ak) { + *access_key = g_strdup_printf ("%c", ak); + } else { + *access_key = NULL; + } + } + + } else { + html_label = g_string_new (label); + + if (access_key) { + *access_key = NULL; + } + } + + return g_string_free (html_label, FALSE); +} + +static void +append_checkbox_table_row (GString *buffer, + const gchar *name, + const gchar *label) +{ + gchar *access_key, *html_label; + + html_label = parse_html_mnemonics (label, &access_key); + + g_string_append_printf ( + buffer, + "<tr id=\"table_row_%s\" hidden=\"\"><td colspan=\"2\">" + "<input type=\"checkbox\" name=\"%s\" id=\"%s\" value=\"%s\" >" + "<label for=\"%s\" accesskey=\"%s\">%s</label>" + "</td></tr>\n", + name, name, name, name, name, + access_key ? access_key : "", html_label); + + g_free (html_label); + + if (access_key) + g_free (access_key); +} + +static void +append_text_table_row (GString *buffer, + const gchar *id, + const gchar *label, + const gchar *value) +{ + if (label && *label) { + + g_string_append_printf (buffer, + "<tr id=\"%s\" %s><th>%s</th><td>%s</td></tr>\n", + id, (value && *value) ? "" : "hidden=\"\"", label, value); + + } else { + + g_string_append_printf ( + buffer, + "<tr id=\"%s\" hidden=\"\"><td colspan=\"2\"></td></tr>\n", + id); + + } +} + +static void +append_info_item_row (ItipView *view, + const gchar *table_id, + ItipViewInfoItem *item) +{ + WebKitDOMElement *table; + WebKitDOMHTMLElement *row, *cell; + const gchar *icon_name; + gchar *id; + + table = webkit_dom_document_get_element_by_id ( + view->priv->dom_document, table_id); + row = webkit_dom_html_table_element_insert_row ( + WEBKIT_DOM_HTML_TABLE_ELEMENT (table), -1, NULL); + + id = g_strdup_printf ("%s_row_%d", table_id, item->id); + webkit_dom_html_element_set_id (row, id); + g_free (id); + + switch (item->type) { + case ITIP_VIEW_INFO_ITEM_TYPE_INFO: + icon_name = GTK_STOCK_DIALOG_INFO; + break; + case ITIP_VIEW_INFO_ITEM_TYPE_WARNING: + icon_name = GTK_STOCK_DIALOG_WARNING; + break; + case ITIP_VIEW_INFO_ITEM_TYPE_ERROR: + icon_name = GTK_STOCK_DIALOG_ERROR; + break; + case ITIP_VIEW_INFO_ITEM_TYPE_PROGRESS: + icon_name = GTK_STOCK_FIND; + break; + case ITIP_VIEW_INFO_ITEM_TYPE_NONE: + default: + icon_name = NULL; + } + + cell = webkit_dom_html_table_row_element_insert_cell ( + (WebKitDOMHTMLTableRowElement *) row, -1, NULL); + + if (icon_name) { + WebKitDOMElement *image; + gchar *icon_uri; + + image = webkit_dom_document_create_element ( + view->priv->dom_document, "IMG", NULL); + + icon_uri = g_strdup_printf ("gtk-stock://%s", icon_name); + webkit_dom_html_image_element_set_src ( + WEBKIT_DOM_HTML_IMAGE_ELEMENT (image), icon_uri); + g_free (icon_uri); + + webkit_dom_node_append_child ( + WEBKIT_DOM_NODE (cell), + WEBKIT_DOM_NODE (image), + NULL); + } + + cell = webkit_dom_html_table_row_element_insert_cell ( + (WebKitDOMHTMLTableRowElement *) row, -1, NULL); + + webkit_dom_html_element_set_inner_html (cell, item->message, NULL); + + d(printf("Added row %s_row_%d ('%s')\n", table_id, item->id, item->message)); +} + +static void +remove_info_item_row (ItipView *view, + const gchar *table_id, + guint id) +{ + WebKitDOMElement *row; + gchar *row_id; + + row_id = g_strdup_printf ("%s_row_%d", table_id, id); + row = webkit_dom_document_get_element_by_id ( + view->priv->dom_document, row_id); + g_free (row_id); + + webkit_dom_node_remove_child ( + webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (row)), + WEBKIT_DOM_NODE (row), + NULL); + + d(printf("Removed row %s_row_%d\n", table_id, id)); +} + +static void +buttons_table_write_button (GString *buffer, + const gchar *name, + const gchar *label, + const gchar *icon, + ItipViewResponse response) +{ + gchar *access_key, *html_label; + + html_label = parse_html_mnemonics (label, &access_key); + + g_string_append_printf ( + buffer, + "<td><button type=\"button\" name=\"%s\" value=\"%d\" id=\"%s\" accesskey=\"%s\" hidden>" + "<div><img src=\"gtk-stock://%s?size=%d\"> <span>%s</span></div>" + "</button></td>\n", + name, response, name, access_key ? access_key : "" , icon, + GTK_ICON_SIZE_BUTTON, html_label); + + g_free (html_label); + + if (access_key) + g_free (access_key); +} + +static void +append_buttons_table (GString *buffer) +{ + g_string_append (buffer, + "<table class=\"itip buttons\" border=\"0\" " + "id=\"" TABLE_BUTTONS "\" cellspacing=\"6\" " + "cellpadding=\"0\" >" + "<tr id=\"" TABLE_ROW_BUTTONS "\">"); + + /* Everything gets the open button */ + buttons_table_write_button ( + buffer, BUTTON_OPEN_CALENDAR, _("_Open Calendar"), + GTK_STOCK_JUMP_TO, ITIP_VIEW_RESPONSE_OPEN); + buttons_table_write_button ( + buffer, BUTTON_DECLINE_ALL, _("_Decline all"), + GTK_STOCK_CANCEL, ITIP_VIEW_RESPONSE_DECLINE); + buttons_table_write_button ( + buffer, BUTTON_DECLINE, _("_Decline"), + GTK_STOCK_CANCEL, ITIP_VIEW_RESPONSE_DECLINE); + buttons_table_write_button ( + buffer, BUTTON_TENTATIVE_ALL, _("_Tentative all"), + GTK_STOCK_DIALOG_QUESTION, ITIP_VIEW_RESPONSE_TENTATIVE); + buttons_table_write_button ( + buffer, BUTTON_TENTATIVE, _("_Tentative"), + GTK_STOCK_DIALOG_QUESTION, ITIP_VIEW_RESPONSE_TENTATIVE); + buttons_table_write_button ( + buffer, BUTTON_ACCEPT_ALL, _("A_ccept all"), + GTK_STOCK_APPLY, ITIP_VIEW_RESPONSE_ACCEPT); + buttons_table_write_button ( + buffer, BUTTON_ACCEPT, _("A_ccept"), + GTK_STOCK_APPLY, ITIP_VIEW_RESPONSE_ACCEPT); + buttons_table_write_button ( + buffer, BUTTON_SEND_INFORMATION, _("_Send Information"), + GTK_STOCK_REFRESH, ITIP_VIEW_RESPONSE_REFRESH); + buttons_table_write_button ( + buffer, BUTTON_UPDATE_ATTENDEE_STATUS, _("_Update Attendee Status"), + GTK_STOCK_REFRESH, ITIP_VIEW_RESPONSE_UPDATE); + buttons_table_write_button ( + buffer, BUTTON_UPDATE, _("_Update"), + GTK_STOCK_REFRESH, ITIP_VIEW_RESPONSE_CANCEL); + + g_string_append (buffer, "</tr></table>"); +} + +static void +itip_view_rebuild_source_list (ItipView *view) +{ + ESourceRegistry *registry; + WebKitDOMElement *select; + GList *list, *link; + const gchar *extension_name; + + d(printf("Assigning a new source list!\n")); + + if (!view->priv->dom_document) + return; + + registry = itip_view_get_registry (view); + extension_name = itip_view_get_extension_name (view); + + select = webkit_dom_document_get_element_by_id ( + view->priv->dom_document, SELECT_ESOURCE); + + while (webkit_dom_node_has_child_nodes (WEBKIT_DOM_NODE (select))) { + webkit_dom_node_remove_child ( + WEBKIT_DOM_NODE (select), + webkit_dom_node_get_last_child (WEBKIT_DOM_NODE (select)), + NULL); + } + + if (extension_name == NULL) + return; + + list = e_source_registry_list_sources (registry, extension_name); + + for (link = list; link != NULL; link = g_list_next (link)) { + ESource *source = E_SOURCE (link->data); + WebKitDOMElement *option; + + option = webkit_dom_document_create_element ( + view->priv->dom_document, "OPTION", NULL); + webkit_dom_html_option_element_set_value ( + WEBKIT_DOM_HTML_OPTION_ELEMENT (option), + e_source_get_uid (source)); + webkit_dom_html_option_element_set_label ( + WEBKIT_DOM_HTML_OPTION_ELEMENT (option), + e_source_get_display_name (source)); + webkit_dom_html_element_set_inner_html ( + WEBKIT_DOM_HTML_ELEMENT (option), + e_source_get_display_name (source), NULL); + webkit_dom_html_element_set_class_name ( + WEBKIT_DOM_HTML_ELEMENT (option), "calendar"); + + webkit_dom_node_append_child ( + WEBKIT_DOM_NODE (select), + WEBKIT_DOM_NODE (option), + NULL); + } + + g_list_free_full (list, (GDestroyNotify) g_object_unref); + + source_changed_cb (select, NULL, view); +} + +static void +itip_view_source_added_cb (ESourceRegistry *registry, + ESource *source, + ItipView *view) +{ + const gchar *extension_name; + + extension_name = itip_view_get_extension_name (view); + + /* If we don't have an extension name set + * yet then disregard the signal emission. */ + if (extension_name == NULL) + return; + + if (e_source_has_extension (source, extension_name)) + itip_view_rebuild_source_list (view); +} + +static void +itip_view_source_removed_cb (ESourceRegistry *registry, + ESource *source, + ItipView *view) +{ + const gchar *extension_name; + + extension_name = itip_view_get_extension_name (view); + + /* If we don't have an extension name set + * yet then disregard the signal emission. */ + if (extension_name == NULL) + return; + + if (e_source_has_extension (source, extension_name)) + itip_view_rebuild_source_list (view); +} + +static void +itip_view_set_registry (ItipView *view, + ESourceRegistry *registry) +{ + g_return_if_fail (E_IS_SOURCE_REGISTRY (registry)); + g_return_if_fail (view->priv->registry == NULL); + + view->priv->registry = g_object_ref (registry); +} + +static void +itip_view_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_EXTENSION_NAME: + itip_view_set_extension_name ( + ITIP_VIEW (object), + g_value_get_string (value)); + return; + + case PROP_REGISTRY: + itip_view_set_registry ( + ITIP_VIEW (object), + g_value_get_object (value)); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +itip_view_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_EXTENSION_NAME: + g_value_set_string ( + value, itip_view_get_extension_name ( + ITIP_VIEW (object))); + return; + + case PROP_REGISTRY: + g_value_set_object ( + value, itip_view_get_registry ( + ITIP_VIEW (object))); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +itip_view_dispose (GObject *object) +{ + ItipViewPrivate *priv; + + priv = ITIP_VIEW_GET_PRIVATE (object); + + if (priv->registry != NULL) { + g_signal_handler_disconnect ( + priv->registry, priv->source_added_id); + g_signal_handler_disconnect ( + priv->registry, priv->source_removed_id); + g_object_unref (priv->registry); + priv->registry = NULL; + } + + /* Chain up to parent's dispose() method. */ + G_OBJECT_CLASS (itip_view_parent_class)->dispose (object); +} + +static void +itip_view_finalize (GObject *object) +{ + ItipViewPrivate *priv; + GSList *iter; + + priv = ITIP_VIEW_GET_PRIVATE (object); + + d(printf("Itip view finalized!\n")); + + g_free (priv->extension_name); + g_free (priv->sender); + g_free (priv->organizer); + g_free (priv->organizer_sentby); + g_free (priv->delegator); + g_free (priv->attendee); + g_free (priv->attendee_sentby); + g_free (priv->proxy); + g_free (priv->summary); + g_free (priv->location); + g_free (priv->status); + g_free (priv->comment); + g_free (priv->start_tm); + g_free (priv->start_label); + g_free (priv->end_tm); + g_free (priv->end_label); + g_free (priv->description); + g_free (priv->error); + + for (iter = priv->lower_info_items; iter; iter = iter->next) { + ItipViewInfoItem *item = iter->data; + g_free (item->message); + g_free (item); + } + + g_slist_free (priv->lower_info_items); + + for (iter = priv->upper_info_items; iter; iter = iter->next) { + ItipViewInfoItem *item = iter->data; + g_free (item->message); + g_free (item); + } + + g_slist_free (priv->upper_info_items); + + /* Chain up to parent's finalize() method. */ + G_OBJECT_CLASS (itip_view_parent_class)->finalize (object); +} + +static void +itip_view_constructed (GObject *object) +{ + ItipView *view; + ESourceRegistry *registry; + + view = ITIP_VIEW (object); + registry = itip_view_get_registry (view); + + view->priv->source_added_id = g_signal_connect ( + registry, "source-added", + G_CALLBACK (itip_view_source_added_cb), view); + + view->priv->source_removed_id = g_signal_connect ( + registry, "source-removed", + G_CALLBACK (itip_view_source_removed_cb), view); + + /* Chain up to parent's constructed() method. */ + G_OBJECT_CLASS (itip_view_parent_class)->constructed (object); +} + +static void +itip_view_class_init (ItipViewClass *class) +{ + GObjectClass *object_class; + + g_type_class_add_private (class, sizeof (ItipViewPrivate)); + + object_class = G_OBJECT_CLASS (class); + object_class->set_property = itip_view_set_property; + object_class->get_property = itip_view_get_property; + object_class->dispose = itip_view_dispose; + object_class->finalize = itip_view_finalize; + object_class->constructed = itip_view_constructed; + + g_object_class_install_property ( + object_class, + PROP_REGISTRY, + g_param_spec_string ( + "extension-name", + "Extension Name", + "Show only data sources with this extension", + NULL, + G_PARAM_READWRITE)); + + g_object_class_install_property ( + object_class, + PROP_REGISTRY, + g_param_spec_object ( + "registry", + "Registry", + "Data source registry", + E_TYPE_SOURCE_REGISTRY, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY)); + + signals[SOURCE_SELECTED] = g_signal_new ( + "source_selected", + G_TYPE_FROM_CLASS (class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (ItipViewClass, source_selected), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, + E_TYPE_SOURCE); + + signals[RESPONSE] = g_signal_new ( + "response", + G_TYPE_FROM_CLASS (class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (ItipViewClass, response), + NULL, NULL, + g_cclosure_marshal_VOID__INT, + G_TYPE_NONE, 1, + G_TYPE_INT); +} + +EMailPartItip * +itip_view_get_mail_part (ItipView *view) +{ + g_return_val_if_fail (ITIP_IS_VIEW (view), NULL); + + return view->priv->itip_part; +} + +ESourceRegistry * +itip_view_get_registry (ItipView *view) +{ + g_return_val_if_fail (ITIP_IS_VIEW (view), NULL); + + return view->priv->registry; +} + +const gchar * +itip_view_get_extension_name (ItipView *view) +{ + g_return_val_if_fail (ITIP_IS_VIEW (view), NULL); + + return view->priv->extension_name; +} + +void +itip_view_set_extension_name (ItipView *view, + const gchar *extension_name) +{ + g_return_if_fail (ITIP_IS_VIEW (view)); + + /* Avoid unnecessary rebuilds. */ + if (g_strcmp0 (extension_name, view->priv->extension_name) == 0) + return; + + g_free (view->priv->extension_name); + view->priv->extension_name = g_strdup (extension_name); + + g_object_notify (G_OBJECT (view), "extension-name"); + + itip_view_rebuild_source_list (view); +} + +void +itip_view_write (GString *buffer) +{ + g_string_append (buffer, + "<html>\n" + "<head>\n" + "<title>ITIP</title>\n" + "<link type=\"text/css\" rel=\"stylesheet\" href=\"evo-file://" EVOLUTION_PRIVDATADIR "/theme/webview.css\" />\n" + "</head>\n" + "<body>\n"); + + g_string_append_printf (buffer, + "<img src=\"gtk-stock://%s?size=%d\" class=\"itip icon\" />\n", + MEETING_ICON, GTK_ICON_SIZE_BUTTON); + + g_string_append (buffer, + "<div class=\"itip content\" id=\"" DIV_ITIP_CONTENT "\">\n"); + + /* The first section listing the sender */ + /* FIXME What to do if the send and organizer do not match */ + g_string_append (buffer, + "<div id=\"" TEXT_ROW_SENDER "\" class=\"itip sender\"></div>\n"); + + g_string_append (buffer, "<hr>\n"); + + /* Elementary event information */ + g_string_append (buffer, + "<table class=\"itip table\" border=\"0\" " + "cellspacing=\"5\" cellpadding=\"0\">\n"); + + append_text_table_row (buffer, TABLE_ROW_SUMMARY, NULL, NULL); + append_text_table_row (buffer, TABLE_ROW_LOCATION, _("Location:"), NULL); + append_text_table_row (buffer, TABLE_ROW_START_DATE, _("Start time:"), NULL); + append_text_table_row (buffer, TABLE_ROW_END_DATE, _("End time:"), NULL); + append_text_table_row (buffer, TABLE_ROW_STATUS, _("Status:"), NULL); + append_text_table_row (buffer, TABLE_ROW_COMMENT, _("Comment:"), NULL); + + g_string_append (buffer, "</table>\n"); + + /* Upper Info items */ + g_string_append (buffer, + "<table class=\"itip info\" id=\"" TABLE_UPPER_ITIP_INFO "\" border=\"0\" " + "cellspacing=\"5\" cellpadding=\"0\">"); + + /* Description */ + g_string_append (buffer, + "<div id=\"" TABLE_ROW_DESCRIPTION "\" class=\"itip description\" hidden=\"\"></div>\n"); + + g_string_append (buffer, "<hr>\n"); + + /* Lower Info items */ + g_string_append (buffer, + "<table class=\"itip info\" id=\"" TABLE_LOWER_ITIP_INFO "\" border=\"0\" " + "cellspacing=\"5\" cellpadding=\"0\">"); + + g_string_append (buffer, + "<table class=\"itip table\" border=\"0\" " + "cellspacing=\"5\" cellpadding=\"0\">\n"); + + g_string_append (buffer, + "<tr id=\"" TABLE_ROW_ESCB "\" hidden=\"\""">" + "<th><label id=\"" TABLE_ROW_ESCB_LABEL "\" for=\"" SELECT_ESOURCE "\"></label></th>" + "<td><select name=\"" SELECT_ESOURCE "\" id=\"" SELECT_ESOURCE "\"></select></td>" + "</tr>\n"); + + /* RSVP area */ + append_checkbox_table_row (buffer, CHECKBOX_RSVP, _("Send reply to sender")); + + /* Comments */ + g_string_append_printf (buffer, + "<tr id=\"" TABLE_ROW_RSVP_COMMENT "\" hidden=\"\">" + "<th>%s</th>" + "<td><textarea name=\"" TEXTAREA_RSVP_COMMENT "\" " + "id=\"" TEXTAREA_RSVP_COMMENT "\" " + "rows=\"3\" cols=\"40\" disabled=\"\">" + "</textarea></td>\n" + "</tr>\n", + _("Comment:")); + + /* Updates */ + append_checkbox_table_row (buffer, CHECKBOX_UPDATE, _("Send _updates to attendees")); + + /* The recurrence check button */ + append_checkbox_table_row (buffer, CHECKBOX_RECUR, _("_Apply to all instances")); + append_checkbox_table_row (buffer, CHECKBOX_FREE_TIME, _("Show time as _free")); + append_checkbox_table_row (buffer, CHECKBOX_KEEP_ALARM, _("_Preserve my reminder")); + append_checkbox_table_row (buffer, CHECKBOX_INHERIT_ALARM, _("_Inherit reminder")); + + g_string_append (buffer, "</table>\n"); + + /* Buttons table */ + append_buttons_table (buffer); + + /* <div class="itip content" > */ + g_string_append (buffer, "</div>\n"); + + g_string_append (buffer, "<div class=\"itip error\" id=\"" DIV_ITIP_ERROR "\"></div>"); + + g_string_append (buffer, "</body></html>"); +} + +void +itip_view_write_for_printing (ItipView *view, + GString *buffer) +{ + if (view->priv->error && *view->priv->error) { + g_string_append (buffer, view->priv->error); + return; + } + + g_string_append (buffer, + "<div class=\"itip print_content\" id=\"" DIV_ITIP_CONTENT "\">\n"); + + /* The first section listing the sender */ + /* FIXME What to do if the send and organizer do not match */ + g_string_append_printf (buffer, + "<div id=\"" TEXT_ROW_SENDER "\" class=\"itip sender\">%s</div>\n", + view->priv->sender ? view->priv->sender : ""); + + g_string_append (buffer, "<hr>\n"); + + /* Elementary event information */ + g_string_append (buffer, + "<table class=\"itip table\" border=\"0\" " + "cellspacing=\"5\" cellpadding=\"0\">\n"); + + append_text_table_row ( + buffer, TABLE_ROW_SUMMARY, + NULL, view->priv->summary); + append_text_table_row ( + buffer, TABLE_ROW_LOCATION, + _("Location:"), view->priv->location); + append_text_table_row ( + buffer, TABLE_ROW_START_DATE, + view->priv->start_header, view->priv->start_label); + append_text_table_row ( + buffer, TABLE_ROW_END_DATE, + view->priv->end_header, view->priv->end_label); + append_text_table_row ( + buffer, TABLE_ROW_STATUS, + _("Status:"), view->priv->status); + append_text_table_row ( + buffer, TABLE_ROW_COMMENT, + _("Comment:"), view->priv->comment); + + g_string_append (buffer, "</table>\n"); + + /* Description */ + g_string_append_printf ( + buffer, + "<div id=\"" TABLE_ROW_DESCRIPTION "\" " + "class=\"itip description\" %s>%s</div>\n", + view->priv->description ? "" : "hidden=\"\"", view->priv->description); + + g_string_append (buffer, "</div>"); +} + +void +itip_view_create_dom_bindings (ItipView *view, + WebKitDOMElement *element) +{ + WebKitDOMElement *el; + WebKitDOMDocument *doc; + + doc = webkit_dom_node_get_owner_document (WEBKIT_DOM_NODE (element)); + view->priv->dom_document = doc; + + el = webkit_dom_document_get_element_by_id (doc, CHECKBOX_RECUR); + if (el) { + webkit_dom_event_target_add_event_listener ( + WEBKIT_DOM_EVENT_TARGET (el), "click", + G_CALLBACK (recur_toggled_cb), FALSE, view); + } + + el = webkit_dom_document_get_element_by_id (doc, CHECKBOX_RSVP); + if (el) { + webkit_dom_event_target_add_event_listener ( + WEBKIT_DOM_EVENT_TARGET (el), "click", + G_CALLBACK (rsvp_toggled_cb), FALSE, view); + } + + el = webkit_dom_document_get_element_by_id (doc, CHECKBOX_INHERIT_ALARM); + if (el) { + webkit_dom_event_target_add_event_listener ( + WEBKIT_DOM_EVENT_TARGET (el), "click", + G_CALLBACK (alarm_check_toggled_cb), FALSE, view); + } + + el = webkit_dom_document_get_element_by_id (doc, CHECKBOX_KEEP_ALARM); + if (el) { + webkit_dom_event_target_add_event_listener ( + WEBKIT_DOM_EVENT_TARGET (el), "click", + G_CALLBACK (alarm_check_toggled_cb), FALSE, view); + } + + el = webkit_dom_document_get_element_by_id (doc, BUTTON_OPEN_CALENDAR); + if (el) { + webkit_dom_event_target_add_event_listener ( + WEBKIT_DOM_EVENT_TARGET (el), "click", + G_CALLBACK (button_clicked_cb), FALSE, view); + } + + el = webkit_dom_document_get_element_by_id (doc, BUTTON_ACCEPT); + if (el) { + webkit_dom_event_target_add_event_listener ( + WEBKIT_DOM_EVENT_TARGET (el), "click", + G_CALLBACK (button_clicked_cb), FALSE, view); + } + + el = webkit_dom_document_get_element_by_id (doc, BUTTON_ACCEPT_ALL); + if (el) { + webkit_dom_event_target_add_event_listener ( + WEBKIT_DOM_EVENT_TARGET (el), "click", + G_CALLBACK (button_clicked_cb), FALSE, view); + } + + el = webkit_dom_document_get_element_by_id (doc, BUTTON_TENTATIVE); + if (el) { + webkit_dom_event_target_add_event_listener ( + WEBKIT_DOM_EVENT_TARGET (el), "click", + G_CALLBACK (button_clicked_cb), FALSE, view); + } + + el = webkit_dom_document_get_element_by_id (doc, BUTTON_TENTATIVE_ALL); + if (el) { + webkit_dom_event_target_add_event_listener ( + WEBKIT_DOM_EVENT_TARGET (el), "click", + G_CALLBACK (button_clicked_cb), FALSE, view); + } + + el = webkit_dom_document_get_element_by_id (doc, BUTTON_DECLINE); + if (el) { + webkit_dom_event_target_add_event_listener ( + WEBKIT_DOM_EVENT_TARGET (el), "click", + G_CALLBACK (button_clicked_cb), FALSE, view); + } + + el = webkit_dom_document_get_element_by_id (doc, BUTTON_DECLINE_ALL); + if (el) { + webkit_dom_event_target_add_event_listener ( + WEBKIT_DOM_EVENT_TARGET (el), "click", + G_CALLBACK (button_clicked_cb), FALSE, view); + } + + el = webkit_dom_document_get_element_by_id (doc, BUTTON_UPDATE); + if (el) { + webkit_dom_event_target_add_event_listener ( + WEBKIT_DOM_EVENT_TARGET (el), "click", + G_CALLBACK (button_clicked_cb), FALSE, view); + } + + el = webkit_dom_document_get_element_by_id (doc, BUTTON_UPDATE_ATTENDEE_STATUS); + if (el) { + webkit_dom_event_target_add_event_listener ( + WEBKIT_DOM_EVENT_TARGET (el), "click", + G_CALLBACK (button_clicked_cb), FALSE, view); + } + + el = webkit_dom_document_get_element_by_id (doc, BUTTON_SEND_INFORMATION); + if (el) { + webkit_dom_event_target_add_event_listener ( + WEBKIT_DOM_EVENT_TARGET (el), "click", + G_CALLBACK (button_clicked_cb), FALSE, view); + } + + el = webkit_dom_document_get_element_by_id (doc, SELECT_ESOURCE); + if (el) { + webkit_dom_event_target_add_event_listener ( + WEBKIT_DOM_EVENT_TARGET (el), "change", + G_CALLBACK (source_changed_cb), FALSE, view); + } +} + +static void +itip_view_init (ItipView *view) +{ + view->priv = ITIP_VIEW_GET_PRIVATE (view); + +} + +ItipView * +itip_view_new (EMailPartItip *puri, + ESourceRegistry *registry) +{ + ItipView *view; + + view = ITIP_VIEW (g_object_new ( + ITIP_TYPE_VIEW, + "registry", registry, + NULL)); + view->priv->itip_part = puri; + + return view; +} + +static void +show_button (ItipView *view, + const gchar *id) +{ + WebKitDOMElement *button; + + button = webkit_dom_document_get_element_by_id ( + view->priv->dom_document, id); + webkit_dom_html_element_set_hidden ( + WEBKIT_DOM_HTML_ELEMENT (button), FALSE); +} + +void +itip_view_set_mode (ItipView *view, + ItipViewMode mode) +{ + WebKitDOMElement *row, *cell; + WebKitDOMElement *button; + + g_return_if_fail (ITIP_IS_VIEW (view)); + + view->priv->mode = mode; + + set_sender_text (view); + + if (!view->priv->dom_document) + return; + + row = webkit_dom_document_get_element_by_id ( + view->priv->dom_document, TABLE_ROW_BUTTONS); + cell = webkit_dom_element_get_first_element_child (row); + do { + button = webkit_dom_element_get_first_element_child (cell); + webkit_dom_html_element_set_hidden ( + WEBKIT_DOM_HTML_ELEMENT (button), TRUE); + } while ((cell = webkit_dom_element_get_next_element_sibling (cell)) != NULL); + + view->priv->is_recur_set = itip_view_get_recur_check_state (view); + + /* Always visible */ + show_button (view, BUTTON_OPEN_CALENDAR); + + switch (mode) { + case ITIP_VIEW_MODE_PUBLISH: + if (view->priv->needs_decline) { + show_button (view, BUTTON_DECLINE); + } + show_button (view, BUTTON_ACCEPT); + break; + case ITIP_VIEW_MODE_REQUEST: + show_button (view, view->priv->is_recur_set ? BUTTON_DECLINE_ALL : BUTTON_DECLINE); + show_button (view, view->priv->is_recur_set ? BUTTON_TENTATIVE_ALL : BUTTON_TENTATIVE); + show_button (view, view->priv->is_recur_set ? BUTTON_ACCEPT_ALL : BUTTON_ACCEPT); + break; + case ITIP_VIEW_MODE_ADD: + if (view->priv->type != E_CAL_CLIENT_SOURCE_TYPE_MEMOS) { + show_button (view, BUTTON_DECLINE); + show_button (view, BUTTON_TENTATIVE); + } + show_button (view, BUTTON_ACCEPT); + break; + case ITIP_VIEW_MODE_REFRESH: + show_button (view, BUTTON_SEND_INFORMATION); + break; + case ITIP_VIEW_MODE_REPLY: + show_button (view, BUTTON_UPDATE_ATTENDEE_STATUS); + break; + case ITIP_VIEW_MODE_CANCEL: + show_button (view, BUTTON_UPDATE); + break; + case ITIP_VIEW_MODE_COUNTER: + case ITIP_VIEW_MODE_DECLINECOUNTER: + show_button (view, BUTTON_DECLINE); + show_button (view, BUTTON_TENTATIVE); + show_button (view, BUTTON_ACCEPT); + break; + default: + break; + } +} + +ItipViewMode +itip_view_get_mode (ItipView *view) +{ + g_return_val_if_fail (ITIP_IS_VIEW (view), ITIP_VIEW_MODE_NONE); + + return view->priv->mode; +} + +void +itip_view_set_item_type (ItipView *view, + ECalClientSourceType type) +{ + WebKitDOMElement *label; + const gchar *header; + gchar *access_key, *html_label; + + g_return_if_fail (ITIP_IS_VIEW (view)); + + view->priv->type = type; + + if (!view->priv->dom_document) + return; + + label = webkit_dom_document_get_element_by_id ( + view->priv->dom_document, TABLE_ROW_ESCB_LABEL); + + switch (view->priv->type) { + case E_CAL_CLIENT_SOURCE_TYPE_EVENTS: + header = _("_Calendar:"); + break; + case E_CAL_CLIENT_SOURCE_TYPE_TASKS: + header = _("_Tasks:"); + break; + case E_CAL_CLIENT_SOURCE_TYPE_MEMOS: + header = _("_Memos:"); + break; + default: + header = NULL; + break; + } + + if (!header) { + set_sender_text (view); + return; + } + + html_label = parse_html_mnemonics (header, &access_key); + + webkit_dom_html_element_set_access_key ( + WEBKIT_DOM_HTML_ELEMENT (label), access_key); + webkit_dom_html_element_set_inner_html ( + WEBKIT_DOM_HTML_ELEMENT (label), html_label, NULL); + + g_free (html_label); + + if (access_key) + g_free (access_key); + + set_sender_text (view); +} + +ECalClientSourceType +itip_view_get_item_type (ItipView *view) +{ + g_return_val_if_fail (ITIP_IS_VIEW (view), ITIP_VIEW_MODE_NONE); + + return view->priv->type; +} + +void +itip_view_set_organizer (ItipView *view, + const gchar *organizer) +{ + g_return_if_fail (ITIP_IS_VIEW (view)); + + if (view->priv->organizer) + g_free (view->priv->organizer); + + view->priv->organizer = e_utf8_ensure_valid (organizer); + + set_sender_text (view); +} + +const gchar * +itip_view_get_organizer (ItipView *view) +{ + g_return_val_if_fail (ITIP_IS_VIEW (view), NULL); + + return view->priv->organizer; +} + +void +itip_view_set_organizer_sentby (ItipView *view, + const gchar *sentby) +{ + g_return_if_fail (ITIP_IS_VIEW (view)); + + if (view->priv->organizer_sentby) + g_free (view->priv->organizer_sentby); + + view->priv->organizer_sentby = e_utf8_ensure_valid (sentby); + + set_sender_text (view); +} + +const gchar * +itip_view_get_organizer_sentby (ItipView *view) +{ + g_return_val_if_fail (ITIP_IS_VIEW (view), NULL); + + return view->priv->organizer_sentby; +} + +void +itip_view_set_attendee (ItipView *view, + const gchar *attendee) +{ + g_return_if_fail (ITIP_IS_VIEW (view)); + + if (view->priv->attendee) + g_free (view->priv->attendee); + + view->priv->attendee = e_utf8_ensure_valid (attendee); + + set_sender_text (view); +} + +const gchar * +itip_view_get_attendee (ItipView *view) +{ + g_return_val_if_fail (ITIP_IS_VIEW (view), NULL); + + return view->priv->attendee; +} + +void +itip_view_set_attendee_sentby (ItipView *view, + const gchar *sentby) +{ + g_return_if_fail (ITIP_IS_VIEW (view)); + + if (view->priv->attendee_sentby) + g_free (view->priv->attendee_sentby); + + view->priv->attendee_sentby = e_utf8_ensure_valid (sentby); + + set_sender_text (view); +} + +const gchar * +itip_view_get_attendee_sentby (ItipView *view) +{ + g_return_val_if_fail (ITIP_IS_VIEW (view), NULL); + + return view->priv->attendee_sentby; +} + +void +itip_view_set_proxy (ItipView *view, + const gchar *proxy) +{ + g_return_if_fail (ITIP_IS_VIEW (view)); + + if (view->priv->proxy) + g_free (view->priv->proxy); + + view->priv->proxy = e_utf8_ensure_valid (proxy); + + set_sender_text (view); +} + +const gchar * +itip_view_get_proxy (ItipView *view) +{ + g_return_val_if_fail (ITIP_IS_VIEW (view), NULL); + + return view->priv->proxy; +} + +void +itip_view_set_delegator (ItipView *view, + const gchar *delegator) +{ + g_return_if_fail (ITIP_IS_VIEW (view)); + + if (view->priv->delegator) + g_free (view->priv->delegator); + + view->priv->delegator = e_utf8_ensure_valid (delegator); + + set_sender_text (view); +} + +const gchar * +itip_view_get_delegator (ItipView *view) +{ + g_return_val_if_fail (ITIP_IS_VIEW (view), NULL); + + return view->priv->delegator; +} + +void +itip_view_set_summary (ItipView *view, + const gchar *summary) +{ + WebKitDOMElement *row, *col; + + g_return_if_fail (ITIP_IS_VIEW (view)); + + if (view->priv->summary) + g_free (view->priv->summary); + + view->priv->summary = summary ? g_strstrip (e_utf8_ensure_valid (summary)) : NULL; + + if (!view->priv->dom_document) + return; + + row = webkit_dom_document_get_element_by_id ( + view->priv->dom_document, TABLE_ROW_SUMMARY); + webkit_dom_html_element_set_hidden ( + WEBKIT_DOM_HTML_ELEMENT (row), (view->priv->summary == NULL)); + + col = webkit_dom_element_get_last_element_child (row); + webkit_dom_html_element_set_inner_html ( + WEBKIT_DOM_HTML_ELEMENT (col), + view->priv->summary ? view->priv->summary : "", + NULL); +} + +const gchar * +itip_view_get_summary (ItipView *view) +{ + g_return_val_if_fail (ITIP_IS_VIEW (view), NULL); + + return view->priv->summary; +} + +void +itip_view_set_location (ItipView *view, + const gchar *location) +{ + WebKitDOMElement *row, *col; + + g_return_if_fail (ITIP_IS_VIEW (view)); + + if (view->priv->location) + g_free (view->priv->location); + + view->priv->location = location ? g_strstrip (e_utf8_ensure_valid (location)) : NULL; + + if (!view->priv->dom_document) + return; + + row = webkit_dom_document_get_element_by_id ( + view->priv->dom_document, TABLE_ROW_LOCATION); + webkit_dom_html_element_set_hidden ( + WEBKIT_DOM_HTML_ELEMENT (row), (view->priv->location == NULL)); + + col = webkit_dom_element_get_last_element_child (row); + webkit_dom_html_element_set_inner_html ( + WEBKIT_DOM_HTML_ELEMENT (col), + view->priv->location ? view->priv->location : "", + NULL); +} + +const gchar * +itip_view_get_location (ItipView *view) +{ + g_return_val_if_fail (ITIP_IS_VIEW (view), NULL); + + return view->priv->location; +} + +void +itip_view_set_status (ItipView *view, + const gchar *status) +{ + WebKitDOMElement *row, *col; + + g_return_if_fail (ITIP_IS_VIEW (view)); + + if (view->priv->status) + g_free (view->priv->status); + + view->priv->status = status ? g_strstrip (e_utf8_ensure_valid (status)) : NULL; + + if (!view->priv->dom_document) + return; + + row = webkit_dom_document_get_element_by_id ( + view->priv->dom_document, TABLE_ROW_STATUS); + webkit_dom_html_element_set_hidden ( + WEBKIT_DOM_HTML_ELEMENT (row), (view->priv->status == NULL)); + + col = webkit_dom_element_get_last_element_child (row); + webkit_dom_html_element_set_inner_html ( + WEBKIT_DOM_HTML_ELEMENT (col), + view->priv->status ? view->priv->status : "", + NULL); +} + +const gchar * +itip_view_get_status (ItipView *view) +{ + g_return_val_if_fail (ITIP_IS_VIEW (view), NULL); + + return view->priv->status; +} + +void +itip_view_set_comment (ItipView *view, + const gchar *comment) +{ + WebKitDOMElement *row, *col; + + g_return_if_fail (ITIP_IS_VIEW (view)); + + if (view->priv->comment) + g_free (view->priv->comment); + + view->priv->comment = comment ? g_strstrip (e_utf8_ensure_valid (comment)) : NULL; + + if (!view->priv->dom_document) + return; + + row = webkit_dom_document_get_element_by_id ( + view->priv->dom_document, TABLE_ROW_COMMENT); + webkit_dom_html_element_set_hidden ( + WEBKIT_DOM_HTML_ELEMENT (row), (view->priv->comment == NULL)); + + col = webkit_dom_element_get_last_element_child (row); + webkit_dom_html_element_set_inner_html ( + WEBKIT_DOM_HTML_ELEMENT (col), + view->priv->comment ? view->priv->comment : "", + NULL); +} + +const gchar * +itip_view_get_comment (ItipView *view) +{ + g_return_val_if_fail (ITIP_IS_VIEW (view), NULL); + + return view->priv->comment; +} + +void +itip_view_set_description (ItipView *view, + const gchar *description) +{ + WebKitDOMElement *div; + + g_return_if_fail (ITIP_IS_VIEW (view)); + + if (view->priv->description) + g_free (view->priv->description); + + view->priv->description = description ? g_strstrip (e_utf8_ensure_valid (description)) : NULL; + + if (!view->priv->dom_document) + return; + + div = webkit_dom_document_get_element_by_id ( + view->priv->dom_document, TABLE_ROW_DESCRIPTION); + webkit_dom_html_element_set_hidden ( + WEBKIT_DOM_HTML_ELEMENT (div), (view->priv->description == NULL)); + + webkit_dom_html_element_set_inner_html ( + WEBKIT_DOM_HTML_ELEMENT (div), + view->priv->description ? view->priv->description : "", + NULL); +} + +const gchar * +itip_view_get_description (ItipView *view) +{ + g_return_val_if_fail (ITIP_IS_VIEW (view), NULL); + + return view->priv->description; +} + +void +itip_view_set_start (ItipView *view, + struct tm *start, + gboolean is_date) +{ + ItipViewPrivate *priv; + + 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; + } + + priv->start_tm_is_date = is_date && start; + + update_start_end_times (view); +} + +const struct tm * +itip_view_get_start (ItipView *view, + gboolean *is_date) +{ + g_return_val_if_fail (ITIP_IS_VIEW (view), NULL); + + if (is_date) + *is_date = view->priv->start_tm_is_date; + + return view->priv->start_tm; +} + +void +itip_view_set_end (ItipView *view, + struct tm *end, + gboolean is_date) +{ + ItipViewPrivate *priv; + + 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; + } + + priv->end_tm_is_date = is_date && end; + + update_start_end_times (view); +} + +const struct tm * +itip_view_get_end (ItipView *view, + gboolean *is_date) +{ + g_return_val_if_fail (ITIP_IS_VIEW (view), NULL); + + if (is_date) + *is_date = view->priv->end_tm_is_date; + + return view->priv->end_tm; +} + +guint +itip_view_add_upper_info_item (ItipView *view, + ItipViewInfoItemType type, + const gchar *message) +{ + ItipViewPrivate *priv; + ItipViewInfoItem *item; + + g_return_val_if_fail (ITIP_IS_VIEW (view), 0); + + priv = view->priv; + + item = g_new0 (ItipViewInfoItem, 1); + + item->type = type; + item->message = e_utf8_ensure_valid (message); + item->id = priv->next_info_item_id++; + + priv->upper_info_items = g_slist_append (priv->upper_info_items, item); + + if (!view->priv->dom_document) + return item->id; + + append_info_item_row (view, TABLE_UPPER_ITIP_INFO, item); + + return item->id; +} + +guint +itip_view_add_upper_info_item_printf (ItipView *view, + ItipViewInfoItemType type, + const gchar *format, + ...) +{ + va_list args; + gchar *message; + guint id; + + g_return_val_if_fail (ITIP_IS_VIEW (view), 0); + + va_start (args, format); + message = g_strdup_vprintf (format, args); + va_end (args); + + id = itip_view_add_upper_info_item (view, type, message); + g_free (message); + + return id; +} + +void +itip_view_remove_upper_info_item (ItipView *view, + guint id) +{ + ItipViewPrivate *priv; + GSList *l; + + g_return_if_fail (ITIP_IS_VIEW (view)); + + priv = view->priv; + + for (l = priv->upper_info_items; l; l = l->next) { + ItipViewInfoItem *item = l->data; + + if (item->id == id) { + priv->upper_info_items = g_slist_remove (priv->upper_info_items, item); + + g_free (item->message); + g_free (item); + + if (!view->priv->dom_document) + remove_info_item_row (view, TABLE_UPPER_ITIP_INFO, id); + + return; + } + } +} + +void +itip_view_clear_upper_info_items (ItipView *view) +{ + ItipViewPrivate *priv; + GSList *l; + + g_return_if_fail (ITIP_IS_VIEW (view)); + + priv = view->priv; + + for (l = priv->upper_info_items; l; l = l->next) { + ItipViewInfoItem *item = l->data; + + if (view->priv->dom_document) + remove_info_item_row (view, TABLE_UPPER_ITIP_INFO, item->id); + + g_free (item->message); + g_free (item); + } + + g_slist_free (priv->upper_info_items); + priv->upper_info_items = NULL; +} + +guint +itip_view_add_lower_info_item (ItipView *view, + ItipViewInfoItemType type, + const gchar *message) +{ + ItipViewPrivate *priv; + ItipViewInfoItem *item; + + g_return_val_if_fail (ITIP_IS_VIEW (view), 0); + + priv = view->priv; + + item = g_new0 (ItipViewInfoItem, 1); + + item->type = type; + item->message = e_utf8_ensure_valid (message); + item->id = priv->next_info_item_id++; + + priv->lower_info_items = g_slist_append (priv->lower_info_items, item); + + if (!view->priv->dom_document) + return item->id; + + append_info_item_row (view, TABLE_LOWER_ITIP_INFO, item); + + return item->id; +} + +guint +itip_view_add_lower_info_item_printf (ItipView *view, + ItipViewInfoItemType type, + const gchar *format, + ...) +{ + va_list args; + gchar *message; + guint id; + + g_return_val_if_fail (ITIP_IS_VIEW (view), 0); + + va_start (args, format); + message = g_strdup_vprintf (format, args); + va_end (args); + + id = itip_view_add_lower_info_item (view, type, message); + g_free (message); + + return id; +} + +void +itip_view_remove_lower_info_item (ItipView *view, + guint id) +{ + ItipViewPrivate *priv; + GSList *l; + + g_return_if_fail (ITIP_IS_VIEW (view)); + + priv = view->priv; + + for (l = priv->lower_info_items; l; l = l->next) { + ItipViewInfoItem *item = l->data; + + if (item->id == id) { + priv->lower_info_items = g_slist_remove (priv->lower_info_items, item); + + g_free (item->message); + g_free (item); + + if (view->priv->dom_document) + remove_info_item_row (view, TABLE_LOWER_ITIP_INFO, id); + + return; + } + } +} + +void +itip_view_clear_lower_info_items (ItipView *view) +{ + ItipViewPrivate *priv; + GSList *l; + + g_return_if_fail (ITIP_IS_VIEW (view)); + + priv = view->priv; + + for (l = priv->lower_info_items; l; l = l->next) { + ItipViewInfoItem *item = l->data; + + if (view->priv->dom_document) + remove_info_item_row (view, TABLE_LOWER_ITIP_INFO, item->id); + + g_free (item->message); + g_free (item); + } + + g_slist_free (priv->lower_info_items); + priv->lower_info_items = NULL; +} + +void +itip_view_set_source (ItipView *view, + ESource *source) +{ + WebKitDOMElement *select; + WebKitDOMElement *row; + ESource *selected_source; + gulong i, len; + + g_return_if_fail (ITIP_IS_VIEW (view)); + + d(printf("Settings default source '%s'\n", e_source_get_display_name (source))); + + if (!view->priv->dom_document) + return; + + row = webkit_dom_document_get_element_by_id ( + view->priv->dom_document, TABLE_ROW_ESCB); + webkit_dom_html_element_set_hidden ( + WEBKIT_DOM_HTML_ELEMENT (row), (source == NULL)); + if (source == NULL) + return; + + select = webkit_dom_document_get_element_by_id ( + view->priv->dom_document, SELECT_ESOURCE); + + /* <select> does not emit 'change' event when already selected + * <option> is re-selected, but we need to notify itip formatter, + * so that it would make all the buttons sensitive */ + selected_source = itip_view_ref_source (view); + if (source == selected_source) + source_changed_cb (select, NULL, view); + + if (selected_source != NULL) + g_object_unref (selected_source); + + if (webkit_dom_html_select_element_get_disabled ( + WEBKIT_DOM_HTML_SELECT_ELEMENT (select))) { + webkit_dom_html_select_element_set_disabled ( + WEBKIT_DOM_HTML_SELECT_ELEMENT (select), FALSE); + } + + len = webkit_dom_html_select_element_get_length ( + WEBKIT_DOM_HTML_SELECT_ELEMENT (select)); + for (i = 0; i < len; i++) { + + WebKitDOMNode *node; + WebKitDOMHTMLOptionElement *option; + gchar *value; + + node = webkit_dom_html_select_element_item ( + WEBKIT_DOM_HTML_SELECT_ELEMENT (select), i); + option = WEBKIT_DOM_HTML_OPTION_ELEMENT (node); + + value = webkit_dom_html_option_element_get_value (option); + if (g_strcmp0 (value, e_source_get_uid (source)) == 0) { + webkit_dom_html_option_element_set_selected ( + option, TRUE); + + g_free (value); + break; + } + + g_free (value); + } +} + +ESource * +itip_view_ref_source (ItipView *view) +{ + ESourceRegistry *registry; + WebKitDOMElement *select; + gchar *uid; + ESource *source; + gboolean disable = FALSE; + + g_return_val_if_fail (ITIP_IS_VIEW (view), NULL); + + if (!view->priv->dom_document) + return NULL; + + select = webkit_dom_document_get_element_by_id ( + view->priv->dom_document, SELECT_ESOURCE); + if (webkit_dom_html_select_element_get_disabled ( + WEBKIT_DOM_HTML_SELECT_ELEMENT (select))) { + webkit_dom_html_select_element_set_disabled ( + WEBKIT_DOM_HTML_SELECT_ELEMENT (select), FALSE); + disable = TRUE; + } + + uid = webkit_dom_html_select_element_get_value ( + WEBKIT_DOM_HTML_SELECT_ELEMENT (select)); + + registry = itip_view_get_registry (view); + source = e_source_registry_ref_source (registry, uid); + + g_free (uid); + + if (disable) { + webkit_dom_html_select_element_set_disabled ( + WEBKIT_DOM_HTML_SELECT_ELEMENT (select), TRUE); + } + + return source; +} + +void +itip_view_set_rsvp (ItipView *view, + gboolean rsvp) +{ + WebKitDOMElement *el; + + g_return_if_fail (ITIP_IS_VIEW (view)); + + if (!view->priv->dom_document) + return; + + el = webkit_dom_document_get_element_by_id ( + view->priv->dom_document, CHECKBOX_RSVP); + webkit_dom_html_input_element_set_checked ( + WEBKIT_DOM_HTML_INPUT_ELEMENT (el), rsvp); + + el = webkit_dom_document_get_element_by_id ( + view->priv->dom_document, TEXTAREA_RSVP_COMMENT); + webkit_dom_html_text_area_element_set_disabled ( + WEBKIT_DOM_HTML_TEXT_AREA_ELEMENT (el), !rsvp); +} + +gboolean +itip_view_get_rsvp (ItipView *view) +{ + WebKitDOMElement *el; + + g_return_val_if_fail (ITIP_IS_VIEW (view), FALSE); + + if (!view->priv->dom_document) + return FALSE; + + el = webkit_dom_document_get_element_by_id ( + view->priv->dom_document, CHECKBOX_UPDATE); + return webkit_dom_html_input_element_get_checked (WEBKIT_DOM_HTML_INPUT_ELEMENT (el)); +} + +void +itip_view_set_show_rsvp_check (ItipView *view, + gboolean show) +{ + WebKitDOMElement *label; + WebKitDOMElement *el; + + g_return_if_fail (ITIP_IS_VIEW (view)); + + if (!view->priv->dom_document) + return; + + el = webkit_dom_document_get_element_by_id ( + view->priv->dom_document, "table_row_" CHECKBOX_RSVP); + webkit_dom_html_element_set_hidden (WEBKIT_DOM_HTML_ELEMENT (el), !show); + + el = webkit_dom_document_get_element_by_id ( + view->priv->dom_document, CHECKBOX_RSVP); + label = webkit_dom_element_get_next_element_sibling (el); + webkit_dom_html_element_set_hidden (WEBKIT_DOM_HTML_ELEMENT (label), !show); + + if (!show) { + webkit_dom_html_input_element_set_checked ( + WEBKIT_DOM_HTML_INPUT_ELEMENT (el), FALSE); + } + + el = webkit_dom_document_get_element_by_id ( + view->priv->dom_document, TABLE_ROW_RSVP_COMMENT); + webkit_dom_html_element_set_hidden (WEBKIT_DOM_HTML_ELEMENT (el), !show); +} + +gboolean +itip_view_get_show_rsvp_check (ItipView *view) +{ + WebKitDOMElement *el; + + g_return_val_if_fail (ITIP_IS_VIEW (view), FALSE); + + if (!view->priv->dom_document) + return FALSE; + + el = webkit_dom_document_get_element_by_id ( + view->priv->dom_document, CHECKBOX_RSVP); + return !webkit_dom_html_element_get_hidden (WEBKIT_DOM_HTML_ELEMENT (el)); +} + +void +itip_view_set_update (ItipView *view, + gboolean update) +{ + WebKitDOMElement *el; + + g_return_if_fail (ITIP_IS_VIEW (view)); + + if (!view->priv->dom_document) + return; + + el = webkit_dom_document_get_element_by_id ( + view->priv->dom_document, CHECKBOX_UPDATE); + + webkit_dom_html_input_element_set_checked ( + WEBKIT_DOM_HTML_INPUT_ELEMENT (el), update); +} + +gboolean +itip_view_get_update (ItipView *view) +{ + WebKitDOMElement *el; + + g_return_val_if_fail (ITIP_IS_VIEW (view), FALSE); + + if (!view->priv->dom_document) + return FALSE; + + el = webkit_dom_document_get_element_by_id ( + view->priv->dom_document, CHECKBOX_UPDATE); + return webkit_dom_html_input_element_get_checked (WEBKIT_DOM_HTML_INPUT_ELEMENT (el)); +} + +void +itip_view_set_show_update_check (ItipView *view, + gboolean show) +{ + WebKitDOMElement *label; + WebKitDOMElement *el; + + g_return_if_fail (ITIP_IS_VIEW (view)); + + if (!view->priv->dom_document) + return; + + el = webkit_dom_document_get_element_by_id ( + view->priv->dom_document, "table_row_" CHECKBOX_UPDATE); + webkit_dom_html_element_set_hidden (WEBKIT_DOM_HTML_ELEMENT (el), !show); + + el = webkit_dom_document_get_element_by_id ( + view->priv->dom_document, CHECKBOX_UPDATE); + label = webkit_dom_element_get_next_element_sibling (el); + webkit_dom_html_element_set_hidden (WEBKIT_DOM_HTML_ELEMENT (label), !show); + + if (!show) { + webkit_dom_html_input_element_set_checked ( + WEBKIT_DOM_HTML_INPUT_ELEMENT (el), FALSE); + } +} + +gboolean +itip_view_get_show_update_check (ItipView *view) +{ + WebKitDOMElement *el; + + g_return_val_if_fail (ITIP_IS_VIEW (view), FALSE); + + if (!view->priv->dom_document) + return FALSE; + + el = webkit_dom_document_get_element_by_id ( + view->priv->dom_document, CHECKBOX_UPDATE); + return !webkit_dom_html_element_get_hidden (WEBKIT_DOM_HTML_ELEMENT (el)); +} + +void +itip_view_set_rsvp_comment (ItipView *view, + const gchar *comment) +{ + WebKitDOMElement *el; + + g_return_if_fail (ITIP_IS_VIEW (view)); + + if (!view->priv->dom_document) + return; + + el = webkit_dom_document_get_element_by_id ( + view->priv->dom_document, TEXTAREA_RSVP_COMMENT); + webkit_dom_html_element_set_hidden ( + WEBKIT_DOM_HTML_ELEMENT (el), (comment == NULL)); + + if (comment) { + webkit_dom_html_text_area_element_set_value ( + WEBKIT_DOM_HTML_TEXT_AREA_ELEMENT (el), comment); + } +} + +gchar * +itip_view_get_rsvp_comment (ItipView *view) +{ + WebKitDOMElement *el; + + g_return_val_if_fail (ITIP_IS_VIEW (view), NULL); + + if (!view->priv->dom_document) + return NULL; + + el = webkit_dom_document_get_element_by_id ( + view->priv->dom_document, TEXTAREA_RSVP_COMMENT); + + if (webkit_dom_html_element_get_hidden (WEBKIT_DOM_HTML_ELEMENT (el))) { + return NULL; + } + + return webkit_dom_html_text_area_element_get_value ( + WEBKIT_DOM_HTML_TEXT_AREA_ELEMENT (el)); +} + +void +itip_view_set_needs_decline (ItipView *view, + gboolean needs_decline) +{ + g_return_if_fail (ITIP_IS_VIEW (view)); + + view->priv->needs_decline = needs_decline; +} + +void +itip_view_set_buttons_sensitive (ItipView *view, + gboolean sensitive) +{ + WebKitDOMElement *el, *cell; + + g_return_if_fail (ITIP_IS_VIEW (view)); + + d(printf("Settings buttons %s\n", sensitive ? "sensitive" : "insensitive")); + + view->priv->buttons_sensitive = sensitive; + + if (!view->priv->dom_document) + return; + + el = webkit_dom_document_get_element_by_id ( + view->priv->dom_document, CHECKBOX_UPDATE); + webkit_dom_html_input_element_set_disabled ( + WEBKIT_DOM_HTML_INPUT_ELEMENT (el), !sensitive); + + el = webkit_dom_document_get_element_by_id ( + view->priv->dom_document, CHECKBOX_RECUR); + webkit_dom_html_input_element_set_disabled ( + WEBKIT_DOM_HTML_INPUT_ELEMENT (el), !sensitive); + + el = webkit_dom_document_get_element_by_id ( + view->priv->dom_document, CHECKBOX_FREE_TIME); + webkit_dom_html_input_element_set_disabled ( + WEBKIT_DOM_HTML_INPUT_ELEMENT (el), !sensitive); + + el = webkit_dom_document_get_element_by_id ( + view->priv->dom_document, CHECKBOX_KEEP_ALARM); + webkit_dom_html_input_element_set_disabled ( + WEBKIT_DOM_HTML_INPUT_ELEMENT (el), !sensitive); + + el = webkit_dom_document_get_element_by_id ( + view->priv->dom_document, CHECKBOX_INHERIT_ALARM); + webkit_dom_html_input_element_set_disabled ( + WEBKIT_DOM_HTML_INPUT_ELEMENT (el), !sensitive); + + el = webkit_dom_document_get_element_by_id ( + view->priv->dom_document, CHECKBOX_RSVP); + webkit_dom_html_input_element_set_disabled ( + WEBKIT_DOM_HTML_INPUT_ELEMENT (el), !sensitive); + + el = webkit_dom_document_get_element_by_id ( + view->priv->dom_document, TEXTAREA_RSVP_COMMENT); + webkit_dom_html_text_area_element_set_disabled ( + WEBKIT_DOM_HTML_TEXT_AREA_ELEMENT (el), !sensitive); + + el = webkit_dom_document_get_element_by_id ( + view->priv->dom_document, SELECT_ESOURCE); + webkit_dom_html_select_element_set_disabled ( + WEBKIT_DOM_HTML_SELECT_ELEMENT (el), !sensitive); + + el = webkit_dom_document_get_element_by_id ( + view->priv->dom_document, TABLE_ROW_BUTTONS); + cell = webkit_dom_element_get_first_element_child (el); + do { + WebKitDOMElement *btn; + btn = webkit_dom_element_get_first_element_child (cell); + if (!webkit_dom_html_element_get_hidden ( + WEBKIT_DOM_HTML_ELEMENT (btn))) { + webkit_dom_html_button_element_set_disabled ( + WEBKIT_DOM_HTML_BUTTON_ELEMENT (btn), !sensitive); + } + } while ((cell = webkit_dom_element_get_next_element_sibling (cell)) != NULL); +} + +gboolean +itip_view_get_buttons_sensitive (ItipView *view) +{ + g_return_val_if_fail (ITIP_IS_VIEW (view), FALSE); + + return view->priv->buttons_sensitive; +} + +gboolean +itip_view_get_recur_check_state (ItipView *view) +{ + WebKitDOMElement *el; + + g_return_val_if_fail (ITIP_IS_VIEW (view), FALSE); + + if (!view->priv->dom_document) + return FALSE; + + el = webkit_dom_document_get_element_by_id ( + view->priv->dom_document, CHECKBOX_RECUR); + return webkit_dom_html_input_element_get_checked ( + WEBKIT_DOM_HTML_INPUT_ELEMENT (el)); +} + +void +itip_view_set_show_recur_check (ItipView *view, + gboolean show) +{ + WebKitDOMElement *label; + WebKitDOMElement *el; + + g_return_if_fail (ITIP_IS_VIEW (view)); + + if (!view->priv->dom_document) + return; + + el = webkit_dom_document_get_element_by_id ( + view->priv->dom_document, "table_row_" CHECKBOX_RECUR); + webkit_dom_html_element_set_hidden (WEBKIT_DOM_HTML_ELEMENT (el), !show); + + el = webkit_dom_document_get_element_by_id ( + view->priv->dom_document, CHECKBOX_RECUR); + label = webkit_dom_element_get_next_element_sibling (el); + webkit_dom_html_element_set_hidden (WEBKIT_DOM_HTML_ELEMENT (label), !show); + + if (!show) { + webkit_dom_html_input_element_set_checked ( + WEBKIT_DOM_HTML_INPUT_ELEMENT (el), FALSE); + } + + /* and update state of the second check */ + alarm_check_toggled_cb ( + WEBKIT_DOM_HTML_INPUT_ELEMENT (el), + NULL, view); +} + +void +itip_view_set_show_free_time_check (ItipView *view, + gboolean show) +{ + WebKitDOMElement *label; + WebKitDOMElement *el; + + g_return_if_fail (ITIP_IS_VIEW (view)); + + if (!view->priv->dom_document) + return; + + el = webkit_dom_document_get_element_by_id ( + view->priv->dom_document, "table_row_" CHECKBOX_FREE_TIME); + webkit_dom_html_element_set_hidden (WEBKIT_DOM_HTML_ELEMENT (el), !show); + + el = webkit_dom_document_get_element_by_id ( + view->priv->dom_document, CHECKBOX_FREE_TIME); + label = webkit_dom_element_get_next_element_sibling (el); + webkit_dom_html_element_set_hidden (WEBKIT_DOM_HTML_ELEMENT (label), !show); + + if (!show) { + webkit_dom_html_input_element_set_checked ( + WEBKIT_DOM_HTML_INPUT_ELEMENT (el), FALSE); + } + + /* and update state of the second check */ + alarm_check_toggled_cb ( + WEBKIT_DOM_HTML_INPUT_ELEMENT (el), + NULL, view); +} + +gboolean +itip_view_get_free_time_check_state (ItipView *view) +{ + WebKitDOMElement *el; + + g_return_val_if_fail (ITIP_IS_VIEW (view), FALSE); + + if (!view->priv->dom_document) + return FALSE; + + el = webkit_dom_document_get_element_by_id ( + view->priv->dom_document, CHECKBOX_FREE_TIME); + return webkit_dom_html_input_element_get_checked ( + WEBKIT_DOM_HTML_INPUT_ELEMENT (el)); +} + +void +itip_view_set_show_keep_alarm_check (ItipView *view, + gboolean show) +{ + WebKitDOMElement *label; + WebKitDOMElement *el; + + g_return_if_fail (ITIP_IS_VIEW (view)); + + if (!view->priv->dom_document) + return; + + el = webkit_dom_document_get_element_by_id ( + view->priv->dom_document, "table_row_" CHECKBOX_KEEP_ALARM); + webkit_dom_html_element_set_hidden (WEBKIT_DOM_HTML_ELEMENT (el), !show); + + el = webkit_dom_document_get_element_by_id ( + view->priv->dom_document, CHECKBOX_KEEP_ALARM); + label = webkit_dom_element_get_next_element_sibling (el); + webkit_dom_html_element_set_hidden (WEBKIT_DOM_HTML_ELEMENT (label), !show); + + if (!show) { + webkit_dom_html_input_element_set_checked ( + WEBKIT_DOM_HTML_INPUT_ELEMENT (el), FALSE); + } + + /* and update state of the second check */ + alarm_check_toggled_cb ( + WEBKIT_DOM_HTML_INPUT_ELEMENT (el), + NULL, view); +} + +gboolean +itip_view_get_keep_alarm_check_state (ItipView *view) +{ + WebKitDOMElement *el; + + g_return_val_if_fail (ITIP_IS_VIEW (view), FALSE); + + if (!view->priv->dom_document) + return FALSE; + + el = webkit_dom_document_get_element_by_id ( + view->priv->dom_document, CHECKBOX_KEEP_ALARM); + return webkit_dom_html_input_element_get_checked ( + WEBKIT_DOM_HTML_INPUT_ELEMENT (el)); +} + +void +itip_view_set_show_inherit_alarm_check (ItipView *view, + gboolean show) +{ + WebKitDOMElement *label; + WebKitDOMElement *el; + + g_return_if_fail (ITIP_IS_VIEW (view)); + + if (!view->priv->dom_document) + return; + + el = webkit_dom_document_get_element_by_id ( + view->priv->dom_document, "table_row_" CHECKBOX_INHERIT_ALARM); + webkit_dom_html_element_set_hidden (WEBKIT_DOM_HTML_ELEMENT (el), !show); + + el = webkit_dom_document_get_element_by_id ( + view->priv->dom_document, CHECKBOX_INHERIT_ALARM); + label = webkit_dom_element_get_next_element_sibling (el); + webkit_dom_html_element_set_hidden (WEBKIT_DOM_HTML_ELEMENT (label), !show); + + if (!show) { + webkit_dom_html_input_element_set_checked ( + WEBKIT_DOM_HTML_INPUT_ELEMENT (el), FALSE); + } + + /* and update state of the second check */ + alarm_check_toggled_cb ( + WEBKIT_DOM_HTML_INPUT_ELEMENT (el), + NULL, view); +} + +gboolean +itip_view_get_inherit_alarm_check_state (ItipView *view) +{ + WebKitDOMElement *el; + + g_return_val_if_fail (ITIP_IS_VIEW (view), FALSE); + + if (!view->priv->dom_document) + return FALSE; + + el = webkit_dom_document_get_element_by_id ( + view->priv->dom_document, CHECKBOX_INHERIT_ALARM); + return webkit_dom_html_input_element_get_checked ( + WEBKIT_DOM_HTML_INPUT_ELEMENT (el)); +} + +void +itip_view_set_error (ItipView *view, + const gchar *error_html, + gboolean show_save_btn) +{ + WebKitDOMElement *content, *error; + GString *str; + + g_return_if_fail (ITIP_IS_VIEW (view)); + g_return_if_fail (error_html); + + str = g_string_new (error_html); + + if (show_save_btn) { + g_string_append (str, + "<table border=\"0\" width=\"100%\">" + "<tr width=\"100%\" id=\"" TABLE_ROW_BUTTONS "\">"); + + buttons_table_write_button ( + str, BUTTON_SAVE, _("_Save"), + GTK_STOCK_SAVE, ITIP_VIEW_RESPONSE_SAVE); + + g_string_append (str, "</tr></table>"); + } + + view->priv->error = str->str; + g_string_free (str, FALSE); + + if (!view->priv->dom_document) + return; + + content = webkit_dom_document_get_element_by_id ( + view->priv->dom_document, DIV_ITIP_CONTENT); + webkit_dom_html_element_set_hidden ( + WEBKIT_DOM_HTML_ELEMENT (content), TRUE); + + error = webkit_dom_document_get_element_by_id ( + view->priv->dom_document, DIV_ITIP_ERROR); + webkit_dom_html_element_set_hidden ( + WEBKIT_DOM_HTML_ELEMENT (error), FALSE); + + webkit_dom_html_element_set_inner_html ( + WEBKIT_DOM_HTML_ELEMENT (error), view->priv->error, NULL); + + if (show_save_btn) { + WebKitDOMElement *el; + + show_button (view, BUTTON_SAVE); + + el = webkit_dom_document_get_element_by_id ( + view->priv->dom_document, BUTTON_SAVE); + webkit_dom_event_target_add_event_listener ( + WEBKIT_DOM_EVENT_TARGET (el), "click", + G_CALLBACK (button_clicked_cb), FALSE, view); + } +} + +/******************************************************************************/ typedef struct { - ItipPURI *puri; + EMailPartItip *puri; ItipView *view; GCancellable *cancellable; gboolean keep_alarm_check; @@ -160,13 +3114,6 @@ typedef struct { static gboolean check_is_instance (icalcomponent *icalcomp); -gint -e_plugin_lib_enable (EPlugin *ep, - gint enable) -{ - return 0; -} - static icalproperty * find_attendee (icalcomponent *ical_comp, const gchar *address) @@ -239,7 +3186,7 @@ find_attendee_if_sentby (icalcomponent *ical_comp, } static void -find_to_address (ItipPURI *pitip, +find_to_address (EMailPartItip *itip_part, icalcomponent *ical_comp, icalparameter_partstat *status) { @@ -248,32 +3195,31 @@ find_to_address (ItipPURI *pitip, GList *list, *link; const gchar *extension_name; - registry = pitip->registry; + registry = itip_part->registry; extension_name = E_SOURCE_EXTENSION_MAIL_IDENTITY; - if (pitip->to_address != NULL) + if (itip_part->to_address != NULL) return; - if (pitip->msg != NULL && pitip->folder != NULL) { + if (itip_part->msg != NULL && itip_part->folder != NULL) { ESource *source; source = em_utils_guess_mail_identity ( - registry, pitip->msg, pitip->folder); + registry, itip_part->msg, itip_part->folder); if (source != NULL) { extension = e_source_get_extension (source, extension_name); - pitip->to_address = e_source_mail_identity_dup_address (extension); + itip_part->to_address = e_source_mail_identity_dup_address (extension); g_object_unref (source); } } - if (pitip->to_address != NULL) + if (itip_part->to_address != NULL) return; /* Look through the list of attendees to find the user's address */ - list = e_source_registry_list_sources (registry, extension_name); for (link = list; link != NULL; link = g_list_next (link)) { @@ -295,20 +3241,20 @@ find_to_address (ItipPURI *pitip, param = icalproperty_get_first_parameter (prop, ICAL_CN_PARAMETER); if (param != NULL) - pitip->to_name = g_strdup (icalparameter_get_cn (param)); + itip_part->to_name = g_strdup (icalparameter_get_cn (param)); text = icalproperty_get_value_as_string_r (prop); - pitip->to_address = g_strdup (itip_strip_mailto (text)); + itip_part->to_address = g_strdup (itip_strip_mailto (text)); g_free (text); - g_strstrip (pitip->to_address); + g_strstrip (itip_part->to_address); - pitip->my_address = g_strdup (address); + itip_part->my_address = g_strdup (address); param = icalproperty_get_first_parameter (prop, ICAL_RSVP_PARAMETER); if (param != NULL && icalparameter_get_rsvp (param) == ICAL_RSVP_FALSE) - pitip->no_reply_wanted = TRUE; + itip_part->no_reply_wanted = TRUE; if (status) { param = icalproperty_get_first_parameter (prop, ICAL_PARTSTAT_PARAMETER); @@ -320,19 +3266,20 @@ find_to_address (ItipPURI *pitip, g_list_free_full (list, (GDestroyNotify) g_object_unref); - if (pitip->to_address != NULL) + if (itip_part->to_address != NULL) return; /* If the user's address was not found in the attendee's list, * then the user might be responding on behalf of his/her delegator. * In this case, we would want to go through the SENT-BY fields of * the attendees to find the user's address. - * + * + * * Note: This functionality could have been (easily) implemented * in the previous loop, but it would hurt the performance for all * providers in general. Hence, we choose to iterate through the * accounts list again. - */ + */ list = e_source_registry_list_sources (registry, extension_name); @@ -343,7 +3290,6 @@ find_to_address (ItipPURI *pitip, const gchar *address; gchar *text; - if (!e_source_get_enabled (source)) continue; @@ -356,20 +3302,20 @@ find_to_address (ItipPURI *pitip, param = icalproperty_get_first_parameter (prop, ICAL_CN_PARAMETER); if (param != NULL) - pitip->to_name = g_strdup (icalparameter_get_cn (param)); + itip_part->to_name = g_strdup (icalparameter_get_cn (param)); text = icalproperty_get_value_as_string_r (prop); - pitip->to_address = g_strdup (itip_strip_mailto (text)); + itip_part->to_address = g_strdup (itip_strip_mailto (text)); g_free (text); - g_strstrip (pitip->to_address); + g_strstrip (itip_part->to_address); - pitip->my_address = g_strdup (address); + itip_part->my_address = g_strdup (address); param = icalproperty_get_first_parameter (prop, ICAL_RSVP_PARAMETER); if (param != NULL && ICAL_RSVP_FALSE == icalparameter_get_rsvp (param)) - pitip->no_reply_wanted = TRUE; + itip_part->no_reply_wanted = TRUE; if (status) { param = icalproperty_get_first_parameter (prop, ICAL_PARTSTAT_PARAMETER); @@ -383,7 +3329,7 @@ find_to_address (ItipPURI *pitip, } static void -find_from_address (ItipPURI *pitip, +find_from_address (EMailPartItip *pitip, icalcomponent *ical_comp) { GList *list, *link; @@ -457,7 +3403,7 @@ find_from_address (ItipPURI *pitip, } static ECalComponent * -get_real_item (ItipPURI *pitip) +get_real_item (EMailPartItip *pitip) { ECalComponent *comp = NULL; ESource *source; @@ -474,7 +3420,7 @@ get_real_item (ItipPURI *pitip) } static void -adjust_item (ItipPURI *pitip, +adjust_item (EMailPartItip *pitip, ECalComponent *comp) { ECalComponent *real_comp; @@ -502,7 +3448,7 @@ adjust_item (ItipPURI *pitip, } static void -set_buttons_sensitive (ItipPURI *pitip, +set_buttons_sensitive (EMailPartItip *pitip, ItipView *view) { gboolean read_only = TRUE; @@ -540,7 +3486,7 @@ cal_opened_cb (GObject *source_object, { ESource *source = E_SOURCE (source_object); ItipView *view = user_data; - ItipPURI *pitip = itip_view_get_puri (view); + EMailPartItip *pitip = itip_view_get_mail_part (view); ECalClientSourceType source_type; EClient *client = NULL; ECalClient *cal_client; @@ -599,7 +3545,7 @@ cal_opened_cb (GObject *source_object, } static void -start_calendar_server (ItipPURI *pitip, +start_calendar_server (EMailPartItip *pitip, ItipView *view, ESource *source, ECalClientSourceType type, @@ -631,7 +3577,7 @@ start_calendar_server (ItipPURI *pitip, } static void -start_calendar_server_by_uid (ItipPURI *pitip, +start_calendar_server_by_uid (EMailPartItip *pitip, ItipView *view, const gchar *uid, ECalClientSourceType type) @@ -653,7 +3599,7 @@ source_selected_cb (ItipView *view, ESource *source, gpointer data) { - ItipPURI *pitip = data; + EMailPartItip *pitip = data; itip_view_set_buttons_sensitive (view, FALSE); @@ -666,7 +3612,7 @@ static void find_cal_update_ui (FormatItipFindData *fd, ECalClient *cal_client) { - ItipPURI *pitip; + EMailPartItip *pitip; ItipView *view; ESource *source; @@ -745,7 +3691,7 @@ decrease_find_data (FormatItipFindData *fd) if (fd->count == 0 && !g_cancellable_is_cancelled (fd->cancellable)) { gboolean rsvp_enabled = FALSE; - ItipPURI *pitip = fd->puri; + EMailPartItip *pitip = fd->puri; ItipView *view = fd->view; itip_view_remove_lower_info_item (view, pitip->progress_info_id); @@ -793,14 +3739,14 @@ decrease_find_data (FormatItipFindData *fd) itip_view_set_extension_name (view, extension_name); g_signal_connect ( - view, "source_selected", + view, "source_selected", G_CALLBACK (source_selected_cb), pitip); if (source != NULL) { itip_view_set_source (view, source); g_object_unref (source); - /* FIXME Shouldn't the buttons be sensitized here? */ + /* FIXME Shouldn't the buttons be sensitized here? */ } else { itip_view_add_lower_info_item (view, ITIP_VIEW_INFO_ITEM_TYPE_ERROR, _("Unable to find any calendars")); itip_view_set_buttons_sensitive (view, FALSE); @@ -990,7 +3936,7 @@ find_cal_opened_cb (GObject *source_object, { ESource *source = E_SOURCE (source_object); FormatItipFindData *fd = user_data; - ItipPURI *pitip = fd->puri; + EMailPartItip *pitip = fd->puri; ItipView *view = fd->view; ECalClientSourceType source_type; EClient *client = NULL; @@ -1054,9 +4000,9 @@ find_cal_opened_cb (GObject *source_object, e_source_conflict_search_get_include_me (extension); } - /* Check for conflicts */ - /* If the query fails, we'll just ignore it */ - /* FIXME What happens for recurring conflicts? */ + /* Check for conflicts */ + /* If the query fails, we'll just ignore it */ + /* FIXME What happens for recurring conflicts? */ if (search_for_conflicts) { e_cal_client_get_object_list ( cal_client, fd->sexp, @@ -1077,7 +4023,7 @@ find_cal_opened_cb (GObject *source_object, } static void -find_server (ItipPURI *pitip, +find_server (EMailPartItip *pitip, ItipView *view, ECalComponent *comp) { @@ -1118,6 +4064,7 @@ find_server (ItipPURI *pitip, * but it propbably doesn't work anymore. * Some comments would have been helpful. */ parent_store = camel_folder_get_parent_store (pitip->folder); + store_uid = camel_service_get_uid (CAMEL_SERVICE (parent_store)); itip_view_set_buttons_sensitive (view, FALSE); @@ -1159,12 +4106,12 @@ find_server (ItipPURI *pitip, pitip->progress_info_id = itip_view_add_lower_info_item ( view, ITIP_VIEW_INFO_ITEM_TYPE_PROGRESS, - _("Opening the calendar. Please wait...")); + _("Opening the calendar. Please wait...")); } else { link = list; pitip->progress_info_id = itip_view_add_lower_info_item ( view, ITIP_VIEW_INFO_ITEM_TYPE_PROGRESS, - _("Searching for an existing version of this appointment")); + _("Searching for an existing version of this appointment")); } for (; link != NULL; link = g_list_next (link)) { @@ -1402,7 +4349,7 @@ get_uri_for_part (CamelMimePart *mime_part) } static void -update_item_progress_info (ItipPURI *pitip, +update_item_progress_info (EMailPartItip *pitip, ItipView *view, const gchar *message) { @@ -1430,7 +4377,7 @@ update_item_progress_info (ItipPURI *pitip, } static void -finish_message_delete_with_rsvp (ItipPURI *pitip, +finish_message_delete_with_rsvp (EMailPartItip *pitip, ItipView *view, ECalClient *client) { @@ -1514,7 +4461,7 @@ finish_message_delete_with_rsvp (ItipPURI *pitip, E_CAL_COMPONENT_METHOD_REPLY, comp, pitip->current_client, pitip->top_level, NULL, NULL, TRUE, FALSE) && - pitip->folder != NULL) { + pitip->folder) { camel_folder_set_message_flags ( pitip->folder, pitip->uid, CAMEL_MESSAGE_ANSWERED, @@ -1535,7 +4482,7 @@ receive_objects_ready_cb (GObject *ecalclient, ECalClient *client = E_CAL_CLIENT (ecalclient); ESource *source = e_client_get_source (E_CLIENT (client)); ItipView *view = user_data; - ItipPURI *pitip = itip_view_get_puri (view); + EMailPartItip *pitip = itip_view_get_mail_part (view); gboolean save_schedules; GError *error = NULL; @@ -1638,7 +4585,7 @@ receive_objects_ready_cb (GObject *ecalclient, } static void -update_item (ItipPURI *pitip, +update_item (EMailPartItip *pitip, ItipView *view, ItipViewResponse response) { @@ -1869,7 +4816,7 @@ send_comp_to_attendee (ESourceRegistry *registry, } static void -remove_delegate (ItipPURI *pitip, +remove_delegate (EMailPartItip *pitip, ItipView *view, const gchar *delegate, const gchar *delegator, @@ -1929,7 +4876,7 @@ modify_object_cb (GObject *ecalclient, { ECalClient *client = E_CAL_CLIENT (ecalclient); ItipView *view = user_data; - ItipPURI *pitip = itip_view_get_puri (view); + EMailPartItip *pitip = itip_view_get_mail_part (view); GError *error = NULL; if (!e_cal_client_modify_object_finish (client, result, &error)) { @@ -1956,7 +4903,7 @@ modify_object_cb (GObject *ecalclient, } static void -update_attendee_status_icalcomp (ItipPURI *pitip, +update_attendee_status_icalcomp (EMailPartItip *pitip, ItipView *view, icalcomponent *icalcomp) { @@ -2059,11 +5006,12 @@ update_attendee_status_icalcomp (ItipPURI *pitip, new_prop = find_attendee (org_icalcomp, itip_strip_mailto (a->value)); icalcomponent_add_property (icalcomp, icalproperty_new_clone (new_prop)); - } else + } else { change_status ( pitip->registry, icalcomp, itip_strip_mailto (a->value), a->status); + } e_cal_component_rescan (comp); } @@ -2101,7 +5049,7 @@ update_attendee_status_get_object_without_rid_cb (GObject *ecalclient, { ECalClient *client = E_CAL_CLIENT (ecalclient); ItipView *view = user_data; - ItipPURI *pitip = itip_view_get_puri (view); + EMailPartItip *pitip = itip_view_get_mail_part (view); icalcomponent *icalcomp = NULL; GError *error = NULL; @@ -2132,7 +5080,7 @@ update_attendee_status_get_object_with_rid_cb (GObject *ecalclient, { ECalClient *client = E_CAL_CLIENT (ecalclient); ItipView *view = user_data; - ItipPURI *pitip = itip_view_get_puri (view); + EMailPartItip *pitip = itip_view_get_mail_part (view); icalcomponent *icalcomp = NULL; GError *error = NULL; @@ -2178,7 +5126,7 @@ update_attendee_status_get_object_with_rid_cb (GObject *ecalclient, } static void -update_attendee_status (ItipPURI *pitip, +update_attendee_status (EMailPartItip *pitip, ItipView *view) { const gchar *uid = NULL; @@ -2202,7 +5150,7 @@ update_attendee_status (ItipPURI *pitip, } static void -send_item (ItipPURI *pitip, +send_item (EMailPartItip *pitip, ItipView *view) { ECalComponent *comp; @@ -2303,7 +5251,7 @@ attachment_load_finish (EAttachment *attachment, } static void -save_vcalendar_cb (ItipPURI *pitip) +save_vcalendar_cb (EMailPartItip *pitip) { EAttachment *attachment; EShell *shell; @@ -2354,7 +5302,7 @@ set_itip_error (ItipView *view, } static gboolean -extract_itip_data (ItipPURI *pitip, +extract_itip_data (EMailPartItip *pitip, ItipView *view, gboolean *have_alarms) { @@ -2654,7 +5602,7 @@ static MailMsgInfo open_calendar_info = { static gboolean idle_open_cb (gpointer data) { - ItipPURI *pitip = data; + EMailPartItip *pitip = data; struct _opencal_msg *m; gchar *start, *end; @@ -2675,7 +5623,7 @@ view_response_cb (ItipView *view, ItipViewResponse response, gpointer data) { - ItipPURI *pitip = data; + EMailPartItip *pitip = data; gboolean status = FALSE; icalproperty *prop; ECalComponentTransparency trans; @@ -2727,10 +5675,10 @@ view_response_cb (ItipView *view, break; case ITIP_VIEW_RESPONSE_TENTATIVE: status = change_status ( - pitip->registry, - pitip->ical_comp, - pitip->to_address, - ICAL_PARTSTAT_TENTATIVE); + pitip->registry, + pitip->ical_comp, + pitip->to_address, + ICAL_PARTSTAT_TENTATIVE); if (status) { e_cal_component_rescan (pitip->comp); pitip->can_delete_invitation_from_cache = TRUE; @@ -2839,9 +5787,8 @@ in_proper_folder (ESourceRegistry *registry, return res; } -static void -init_itip_view (ItipPURI *info, - ItipView *view) +void +itip_view_init_view (ItipView *view) { EShell *shell; EShellSettings *shell_settings; @@ -2857,7 +5804,10 @@ init_itip_view (ItipPURI *info, gint i; gboolean response_enabled; gboolean have_alarms = FALSE; - EMFormat *emf = info->puri.emf; + EMailPartItip *info; + + info = view->priv->itip_part; + g_return_if_fail (info != NULL); shell = e_shell_get_default (); registry = e_shell_get_registry (shell); @@ -2880,7 +5830,7 @@ init_itip_view (ItipPURI *info, if (!extract_itip_data (info, view, &have_alarms)) return; - response_enabled = in_proper_folder (registry, emf->folder); + response_enabled = in_proper_folder (registry, info->folder); if (!response_enabled) { itip_view_set_mode (view, ITIP_VIEW_MODE_HIDE_ALL); @@ -3185,321 +6135,3 @@ init_itip_view (ItipPURI *info, } } } - -static void -puri_free (EMFormatPURI *puri) -{ - ItipPURI *pitip = (ItipPURI *) puri; - gint i; - - g_cancellable_cancel (pitip->cancellable); - g_object_unref (pitip->cancellable); - - if (pitip->registry != NULL) { - g_object_unref (pitip->registry); - pitip->registry = NULL; - } - - for (i = 0; i < E_CAL_CLIENT_SOURCE_TYPE_LAST; i++) { - g_hash_table_destroy (pitip->clients[i]); - pitip->clients[i] = NULL; - } - - g_free (pitip->vcalendar); - pitip->vcalendar = NULL; - - if (pitip->comp) { - g_object_unref (pitip->comp); - pitip->comp = NULL; - } - - if (pitip->top_level) { - icalcomponent_free (pitip->top_level); - pitip->top_level = NULL; - } - - if (pitip->main_comp) { - icalcomponent_free (pitip->main_comp); - pitip->main_comp = NULL; - } - pitip->ical_comp = NULL; - - g_free (pitip->calendar_uid); - pitip->calendar_uid = NULL; - - g_free (pitip->from_address); - pitip->from_address = NULL; - g_free (pitip->from_name); - pitip->from_name = NULL; - g_free (pitip->to_address); - pitip->to_address = NULL; - g_free (pitip->to_name); - pitip->to_name = NULL; - g_free (pitip->delegator_address); - pitip->delegator_address = NULL; - g_free (pitip->delegator_name); - pitip->delegator_name = NULL; - g_free (pitip->my_address); - pitip->my_address = NULL; - g_free (pitip->uid); - g_hash_table_destroy (pitip->real_comps); -} - -static void -write_itip_view (EMFormat *emf, - EMFormatPURI *puri, - CamelStream *stream, - EMFormatWriterInfo *info, - GCancellable *cancellable) -{ - GString *buffer; - - if (info->mode == EM_FORMAT_WRITE_MODE_PRINTING) { - ItipView *view; - ItipPURI *pitip; - - buffer = g_string_sized_new (1024); - - pitip = (ItipPURI *) puri; - view = itip_view_new (pitip, pitip->registry); - - init_itip_view (pitip, view); - itip_view_write_for_printing (view, buffer); - - /* Destroy the view when the formatter is destroyed */ - g_object_weak_ref ( - G_OBJECT (emf), (GWeakNotify) g_object_unref, view); - - } else if (info->mode == EM_FORMAT_WRITE_MODE_RAW) { - buffer = g_string_sized_new (2048); - - itip_view_write (buffer); - - } else { - gchar *uri; - - uri = em_format_build_mail_uri ( - emf->folder, emf->message_uid, - "part_id", G_TYPE_STRING, puri->uri, - "mode", G_TYPE_INT, EM_FORMAT_WRITE_MODE_RAW, - NULL); - - buffer = g_string_sized_new (256); - g_string_append_printf (buffer, - "<div class=\"part-container\" " - "style=\"border: none; background: none;\">" - "<iframe width=\"100%%\" height=\"auto\"" - " frameborder=\"0\" src=\"%s\" name=\"%s\" id=\"%s\"></iframe>" - "</div>", - uri, puri->uri, puri->uri); - - g_free (uri); - } - - camel_stream_write_string (stream, buffer->str, cancellable, NULL); - - g_string_free (buffer, TRUE); -} - -static void -bind_itip_view (WebKitDOMElement *element, - EMFormatPURI *puri) -{ - if (WEBKIT_DOM_IS_HTML_IFRAME_ELEMENT (element)) { - ItipPURI *pitip = (ItipPURI *) puri; - GString *buffer = g_string_new (""); - WebKitDOMDocument *document; - ItipView *view; - - document = webkit_dom_html_iframe_element_get_content_document ( - WEBKIT_DOM_HTML_IFRAME_ELEMENT (element)); - - view = itip_view_new (pitip, pitip->registry); - - g_object_set_data_full ( - G_OBJECT (element), "view", view, - (GDestroyNotify) g_object_unref); - - itip_view_create_dom_bindings (view, - webkit_dom_document_get_document_element (document)); - - init_itip_view (pitip, view); - g_string_free (buffer, TRUE); - } -} - -void -format_itip (EPlugin *ep, - EMFormatHookTarget *target) -{ - GSettings *settings; - ItipPURI *puri; - CamelDataWrapper *content; - CamelStream *stream; - GByteArray *byte_array; - gint len; - - len = target->part_id->len; - g_string_append_printf (target->part_id, ".itip"); - - /* mark message as containing calendar, thus it will show the icon in message list now on */ - if (target->format->message_uid && target->format->folder && - !camel_folder_get_message_user_flag (target->format->folder, target->format->message_uid, "$has_cal")) - camel_folder_set_message_user_flag (target->format->folder, target->format->message_uid, "$has_cal", TRUE); - - settings = g_settings_new ("org.gnome.evolution.plugin.itip"); - - puri = (ItipPURI *) em_format_puri_new ( - target->format, sizeof (ItipPURI), - target->part, target->part_id->str); - puri->puri.write_func = write_itip_view; - puri->puri.bind_func = bind_itip_view; - puri->puri.free = puri_free; - puri->puri.is_attachment = target->info->is_attachment; - puri->puri.mime_type = g_strdup ("text/html"); - puri->delete_message = g_settings_get_boolean (settings, CONF_KEY_DELETE); - puri->has_organizer = FALSE; - puri->no_reply_wanted = FALSE; - puri->folder = ((EMFormat *) target->format)->folder; - puri->uid = g_strdup (((EMFormat *) target->format)->message_uid); - puri->msg = ((EMFormat *) target->format)->message; - puri->part = target->part; - puri->cancellable = g_cancellable_new (); - puri->real_comps = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); - - em_format_add_puri (target->format, (EMFormatPURI *) puri); - - g_object_unref (settings); - - /* This is non-gui thread. Download the part for using in the main thread */ - content = camel_medium_get_content ((CamelMedium *) target->part); - - byte_array = g_byte_array_new (); - stream = camel_stream_mem_new_with_byte_array (byte_array); - camel_data_wrapper_decode_to_stream_sync (content, stream, NULL, NULL); - - if (byte_array->len == 0) - puri->vcalendar = NULL; - else - puri->vcalendar = g_strndup ( - (gchar *) byte_array->data, byte_array->len); - - g_object_unref (stream); - g_string_truncate (target->part_id, len); -} - -static void -delete_toggled_cb (GtkWidget *widget) -{ - GSettings *settings; - gboolean active; - - settings = g_settings_new ("org.gnome.evolution.plugin.itip"); - active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)); - g_settings_set_boolean (settings, CONF_KEY_DELETE, active); - g_object_unref (settings); -} - -GtkWidget * -itip_formatter_page_factory (EPlugin *ep, - EConfigHookItemFactoryData *hook_data) -{ - EShell *shell; - ESourceRegistry *registry; - GtkWidget *page; - GtkWidget *tab_label; - GtkWidget *frame; - GtkWidget *frame_label; - GtkWidget *padding_label; - GtkWidget *hbox; - GtkWidget *inner_vbox; - GtkWidget *check; - GtkWidget *label; - GtkWidget *ess; - GtkWidget *scrolledwin; - gchar *str; - GSettings *settings; - - shell = e_shell_get_default (); - registry = e_shell_get_registry (shell); - - /* Create a new notebook page */ - page = gtk_vbox_new (FALSE, 0); - gtk_container_set_border_width (GTK_CONTAINER (page), 12); - tab_label = gtk_label_new (_("Meeting Invitations")); - gtk_notebook_append_page (GTK_NOTEBOOK (hook_data->parent), page, tab_label); - - /* Frame */ - frame = gtk_vbox_new (FALSE, 6); - gtk_box_pack_start (GTK_BOX (page), frame, FALSE, FALSE, 0); - - /* "General" */ - frame_label = gtk_label_new (""); - str = g_strdup_printf ("<span weight=\"bold\">%s</span>", _("General")); - gtk_label_set_markup (GTK_LABEL (frame_label), str); - g_free (str); - gtk_misc_set_alignment (GTK_MISC (frame_label), 0.0, 0.5); - gtk_box_pack_start (GTK_BOX (frame), frame_label, FALSE, FALSE, 0); - - /* Indent/padding */ - hbox = gtk_hbox_new (FALSE, 12); - gtk_box_pack_start (GTK_BOX (frame), hbox, FALSE, TRUE, 0); - padding_label = gtk_label_new (""); - gtk_box_pack_start (GTK_BOX (hbox), padding_label, FALSE, FALSE, 0); - inner_vbox = gtk_vbox_new (FALSE, 6); - gtk_box_pack_start (GTK_BOX (hbox), inner_vbox, FALSE, FALSE, 0); - - /* Delete message after acting */ - settings = g_settings_new ("org.gnome.evolution.plugin.itip"); - - check = gtk_check_button_new_with_mnemonic (_("_Delete message after acting")); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check), g_settings_get_boolean (settings, CONF_KEY_DELETE)); - g_signal_connect ( - check, "toggled", - G_CALLBACK (delete_toggled_cb), NULL); - gtk_box_pack_start (GTK_BOX (inner_vbox), check, FALSE, FALSE, 0); - - g_object_unref (settings); - - /* "Conflict searching" */ - frame = gtk_vbox_new (FALSE, 6); - gtk_box_pack_start (GTK_BOX (page), frame, TRUE, TRUE, 24); - - frame_label = gtk_label_new (""); - str = g_strdup_printf ("<span weight=\"bold\">%s</span>", _("Conflict Search")); - gtk_label_set_markup (GTK_LABEL (frame_label), str); - g_free (str); - gtk_misc_set_alignment (GTK_MISC (frame_label), 0.0, 0.5); - gtk_box_pack_start (GTK_BOX (frame), frame_label, FALSE, FALSE, 0); - - /* Indent/padding */ - hbox = gtk_hbox_new (FALSE, 12); - gtk_box_pack_start (GTK_BOX (frame), hbox, TRUE, TRUE, 0); - padding_label = gtk_label_new (""); - gtk_box_pack_start (GTK_BOX (hbox), padding_label, FALSE, FALSE, 0); - inner_vbox = gtk_vbox_new (FALSE, 6); - gtk_box_pack_start (GTK_BOX (hbox), inner_vbox, TRUE, TRUE, 0); - - /* Source selector */ - label = gtk_label_new (_("Select the calendars to search for meeting conflicts")); - gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); - gtk_box_pack_start (GTK_BOX (inner_vbox), label, FALSE, FALSE, 0); - - scrolledwin = gtk_scrolled_window_new (NULL, NULL); - - gtk_scrolled_window_set_policy ( - GTK_SCROLLED_WINDOW (scrolledwin), - GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - gtk_scrolled_window_set_shadow_type ( - GTK_SCROLLED_WINDOW (scrolledwin), GTK_SHADOW_IN); - gtk_box_pack_start (GTK_BOX (inner_vbox), scrolledwin, TRUE, TRUE, 0); - - ess = e_conflict_search_selector_new (registry); - atk_object_set_name (gtk_widget_get_accessible (ess), _("Conflict Search")); - gtk_container_add (GTK_CONTAINER (scrolledwin), ess); - - gtk_widget_show_all (page); - - return page; -} - diff --git a/modules/itip-formatter/itip-view.h b/modules/itip-formatter/itip-view.h new file mode 100644 index 0000000000..60b8b1d4ba --- /dev/null +++ b/modules/itip-formatter/itip-view.h @@ -0,0 +1,270 @@ +/* + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see <http://www.gnu.org/licenses/> + * + * + * Authors: + * JP Rosevear <jpr@novell.com> + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifndef _ITIP_VIEW_H_ +#define _ITIP_VIEW_H_ + +#include <stdarg.h> +#include <unistd.h> +#include <gtk/gtk.h> +#include <webkit/webkitdom.h> +#include <libecal/libecal.h> +#include <libedataserver/libedataserver.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 struct _EMailPartItip EMailPartItip; + +typedef enum { + ITIP_VIEW_MODE_NONE, + ITIP_VIEW_MODE_PUBLISH, + ITIP_VIEW_MODE_REQUEST, + ITIP_VIEW_MODE_COUNTER, + ITIP_VIEW_MODE_DECLINECOUNTER, + ITIP_VIEW_MODE_ADD, + ITIP_VIEW_MODE_REPLY, + ITIP_VIEW_MODE_REFRESH, + ITIP_VIEW_MODE_CANCEL, + ITIP_VIEW_MODE_HIDE_ALL +} 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_CANCEL, + ITIP_VIEW_RESPONSE_REFRESH, + ITIP_VIEW_RESPONSE_OPEN, + ITIP_VIEW_RESPONSE_SAVE +} ItipViewResponse; + +typedef enum { + ITIP_VIEW_INFO_ITEM_TYPE_NONE, + ITIP_VIEW_INFO_ITEM_TYPE_INFO, + ITIP_VIEW_INFO_ITEM_TYPE_WARNING, + ITIP_VIEW_INFO_ITEM_TYPE_ERROR, + ITIP_VIEW_INFO_ITEM_TYPE_PROGRESS +} ItipViewInfoItemType; + +struct _ItipView { + GObject parent_instance; + + ItipViewPrivate *priv; +}; + +struct _ItipViewClass { + GObjectClass parent_class; + + void (* source_selected) (ItipView *view, + ESource *selected_source); + + void (* response) (ItipView *view, + gint response); +}; + +GType itip_view_get_type (void); + +ItipView * itip_view_new (EMailPartItip *puri, + ESourceRegistry *registry); +void itip_view_init_view (ItipView *view); + +void itip_view_write (GString *buffer); + +void itip_view_write_for_printing (ItipView *view, + GString *buffer); + +void itip_view_create_dom_bindings (ItipView *view, + WebKitDOMElement *element); + +EMailPartItip * itip_view_get_mail_part (ItipView *view); +ESourceRegistry * + itip_view_get_registry (ItipView *view); +const gchar * itip_view_get_extension_name (ItipView *view); +void itip_view_set_extension_name (ItipView *view, + const gchar *extension_name); + +void itip_view_set_mode (ItipView *view, + ItipViewMode mode); +ItipViewMode itip_view_get_mode (ItipView *view); + +void itip_view_set_item_type (ItipView *view, + ECalClientSourceType type); +ECalClientSourceType + itip_view_get_item_type (ItipView *view); + +void itip_view_set_organizer (ItipView *view, + const gchar *organizer); +const gchar * itip_view_get_organizer (ItipView *view); + +void itip_view_set_organizer_sentby (ItipView *view, + const gchar *sentby); +const gchar * itip_view_get_organizer_sentby (ItipView *view); + +void itip_view_set_attendee (ItipView *view, + const gchar *attendee); +const gchar * itip_view_get_attendee (ItipView *view); + +void itip_view_set_attendee_sentby (ItipView *view, + const gchar *sentby); +const gchar * itip_view_get_attendee_sentby (ItipView *view); + +void itip_view_set_delegator (ItipView *view, + const gchar *delegator); +const gchar * itip_view_get_delegator (ItipView *view); + +void itip_view_set_proxy (ItipView *view, + const gchar *proxy); +const gchar * itip_view_get_proxy (ItipView *view); + +void itip_view_set_summary (ItipView *view, + const gchar *summary); +const gchar * itip_view_get_summary (ItipView *view); + +void itip_view_set_location (ItipView *view, + const gchar *location); +const gchar * itip_view_get_location (ItipView *view); + +void itip_view_set_status (ItipView *view, + const gchar *status); +const gchar * itip_view_get_status (ItipView *view); + +void itip_view_set_comment (ItipView *view, + const gchar *comment); +const gchar * itip_view_get_comment (ItipView *view); + +void itip_view_set_description (ItipView *view, + const gchar *description); +const gchar * itip_view_get_description (ItipView *view); + +void itip_view_set_start (ItipView *view, + struct tm *start, + gboolean is_date); +const struct tm * + itip_view_get_start (ItipView *view, + gboolean *is_date); + +void itip_view_set_end (ItipView *view, + struct tm *end, + gboolean is_date); +const struct tm * + itip_view_get_end (ItipView *view, + gboolean *is_date); + +guint itip_view_add_upper_info_item (ItipView *view, + ItipViewInfoItemType type, + const gchar *message); +guint itip_view_add_upper_info_item_printf + (ItipView *view, + ItipViewInfoItemType, + const gchar *format, ...) G_GNUC_PRINTF (3, 4); +void itip_view_remove_upper_info_item + (ItipView *view, + guint id); +void itip_view_clear_upper_info_items + (ItipView *view); + +guint itip_view_add_lower_info_item (ItipView *view, + ItipViewInfoItemType type, + const gchar *message); +guint itip_view_add_lower_info_item_printf + (ItipView *view, + ItipViewInfoItemType type, + const gchar *format, ...) G_GNUC_PRINTF (3, 4); +void itip_view_remove_lower_info_item + (ItipView *view, + guint id); +void itip_view_clear_lower_info_items + (ItipView *view); + +void itip_view_set_source (ItipView *view, + ESource *source); +ESource * itip_view_ref_source (ItipView *view); + +void itip_view_set_rsvp (ItipView *view, + gboolean rsvp); +gboolean itip_view_get_rsvp (ItipView *view); + +void itip_view_set_show_rsvp_check (ItipView *view, + gboolean show); +gboolean itip_view_get_show_rsvp_check (ItipView *view); + +void itip_view_set_update (ItipView *view, + gboolean update); +gboolean itip_view_get_update (ItipView *view); + +void itip_view_set_show_update_check (ItipView *view, + gboolean show); +gboolean itip_view_get_show_update_check (ItipView *view); + +void itip_view_set_rsvp_comment (ItipView *view, + const gchar *comment); +gchar * itip_view_get_rsvp_comment (ItipView *view); + +void itip_view_set_buttons_sensitive (ItipView *view, + gboolean sensitive); +gboolean itip_view_get_buttons_sensitive (ItipView *view); + +void itip_view_set_show_recur_check (ItipView *view, + gboolean show); +gboolean itip_view_get_recur_check_state (ItipView *view); + +void itip_view_set_needs_decline (ItipView *view, + gboolean needs_decline); + +void itip_view_set_show_free_time_check + (ItipView *view, + gboolean show); +gboolean itip_view_get_free_time_check_state + (ItipView *view); + +void itip_view_set_show_keep_alarm_check + (ItipView *view, + gboolean show); +gboolean itip_view_get_keep_alarm_check_state + (ItipView *view); + +void itip_view_set_show_inherit_alarm_check + (ItipView *view, + gboolean show); +gboolean itip_view_get_inherit_alarm_check_state + (ItipView *view); + +void itip_view_set_error (ItipView *view, + const gchar *error_html, + gboolean show_save_btn); + +G_END_DECLS + +#endif diff --git a/plugins/itip-formatter/org-gnome-itip-formatter.error.xml b/modules/itip-formatter/org-gnome-itip-formatter.error.xml index e5d84c67af..e5d84c67af 100644 --- a/plugins/itip-formatter/org-gnome-itip-formatter.error.xml +++ b/modules/itip-formatter/org-gnome-itip-formatter.error.xml diff --git a/modules/itip-formatter/plugin/Makefile.am b/modules/itip-formatter/plugin/Makefile.am new file mode 100644 index 0000000000..b84059c2b4 --- /dev/null +++ b/modules/itip-formatter/plugin/Makefile.am @@ -0,0 +1,36 @@ +@EVO_PLUGIN_RULE@ + +plugin_DATA = org-gnome-itip-formatter.eplug +plugin_LTLIBRARIES = liborg-gnome-itip-formatter.la + +liborg_gnome_itip_formatter_la_CPPFLAGS = \ + $(AM_CPPFLAGS) \ + -I$(top_srcdir) \ + -I$(top_srcdir)/widgets \ + -I$(top_srcdir)/modules/itip-formatter \ + -DEVOLUTION_PRIVDATADIR=\""$(privdatadir)"\" \ + $(EVOLUTION_DATA_SERVER_CFLAGS) \ + $(GNOME_PLATFORM_CFLAGS) + +liborg_gnome_itip_formatter_la_SOURCES = \ + config-ui.c + +liborg_gnome_itip_formatter_la_LDFLAGS = -module -avoid-version $(NO_UNDEFINED) + +liborg_gnome_itip_formatter_la_LIBADD = \ + $(top_builddir)/e-util/libeutil.la \ + $(top_builddir)/calendar/gui/libevolution-calendar.la \ + $(top_builddir)/mail/libevolution-mail.la \ + $(top_builddir)/shell/libeshell.la \ + $(top_builddir)/em-format/libemformat.la \ + $(top_builddir)/widgets/misc/libemiscwidgets.la \ + $(top_builddir)/modules/itip-formatter/module-itip-formatter.la \ + $(EVOLUTION_DATA_SERVER_LIBS) \ + $(GNOME_PLATFORM_LIBS) + +BUILT_SOURCES = $(plugin_DATA) + +CLEANFILES = $(BUILT_SOURCES) + +EXTRA_DIST = \ + org-gnome-itip-formatter.eplug.xml diff --git a/modules/itip-formatter/plugin/config-ui.c b/modules/itip-formatter/plugin/config-ui.c new file mode 100644 index 0000000000..9ba6f05b0e --- /dev/null +++ b/modules/itip-formatter/plugin/config-ui.c @@ -0,0 +1,159 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see <http://www.gnu.org/licenses/> + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <gtk/gtk.h> +#include <glib/gi18n.h> + +#include <mail/em-config.h> + +#include <shell/e-shell.h> +#include <libedataserver/libedataserver.h> +#include <libecal/libecal.h> +#include <modules/itip-formatter/e-conflict-search-selector.h> +#include <modules/itip-formatter/e-source-conflict-search.h> + +#define CONF_KEY_DELETE "delete-processed" + +GtkWidget *itip_formatter_page_factory (EPlugin *ep, EConfigHookItemFactoryData *hook_data); +gint e_plugin_lib_enable (EPlugin *ep, gint enable); + +gint +e_plugin_lib_enable (EPlugin *ep, + gint enable) +{ + return 0; +} + +static void +delete_toggled_cb (GtkWidget *widget) +{ + GSettings *settings; + gboolean active; + + settings = g_settings_new ("org.gnome.evolution.plugin.itip"); + active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)); + g_settings_set_boolean (settings, CONF_KEY_DELETE, active); + g_object_unref (settings); +} + +GtkWidget * +itip_formatter_page_factory (EPlugin *ep, + EConfigHookItemFactoryData *hook_data) +{ + EShell *shell; + ESourceRegistry *registry; + GtkWidget *page; + GtkWidget *tab_label; + GtkWidget *frame; + GtkWidget *frame_label; + GtkWidget *padding_label; + GtkWidget *hbox; + GtkWidget *inner_vbox; + GtkWidget *check; + GtkWidget *label; + GtkWidget *ess; + GtkWidget *scrolledwin; + gchar *str; + GSettings *settings; + + shell = e_shell_get_default (); + registry = e_shell_get_registry (shell); + + /* Create a new notebook page */ + page = gtk_vbox_new (FALSE, 0); + gtk_container_set_border_width (GTK_CONTAINER (page), 12); + tab_label = gtk_label_new (_("Meeting Invitations")); + gtk_notebook_append_page (GTK_NOTEBOOK (hook_data->parent), page, tab_label); + + /* Frame */ + frame = gtk_vbox_new (FALSE, 6); + gtk_box_pack_start (GTK_BOX (page), frame, FALSE, FALSE, 0); + + /* "General" */ + frame_label = gtk_label_new (""); + str = g_strdup_printf ("<span weight=\"bold\">%s</span>", _("General")); + gtk_label_set_markup (GTK_LABEL (frame_label), str); + g_free (str); + gtk_misc_set_alignment (GTK_MISC (frame_label), 0.0, 0.5); + gtk_box_pack_start (GTK_BOX (frame), frame_label, FALSE, FALSE, 0); + + /* Indent/padding */ + hbox = gtk_hbox_new (FALSE, 12); + gtk_box_pack_start (GTK_BOX (frame), hbox, FALSE, TRUE, 0); + padding_label = gtk_label_new (""); + gtk_box_pack_start (GTK_BOX (hbox), padding_label, FALSE, FALSE, 0); + inner_vbox = gtk_vbox_new (FALSE, 6); + gtk_box_pack_start (GTK_BOX (hbox), inner_vbox, FALSE, FALSE, 0); + + /* Delete message after acting */ + settings = g_settings_new ("org.gnome.evolution.plugin.itip"); + + check = gtk_check_button_new_with_mnemonic (_("_Delete message after acting")); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check), g_settings_get_boolean (settings, CONF_KEY_DELETE)); + g_signal_connect ( + check, "toggled", + G_CALLBACK (delete_toggled_cb), NULL); + gtk_box_pack_start (GTK_BOX (inner_vbox), check, FALSE, FALSE, 0); + + g_object_unref (settings); + + /* "Conflict searching" */ + frame = gtk_vbox_new (FALSE, 6); + gtk_box_pack_start (GTK_BOX (page), frame, TRUE, TRUE, 24); + + frame_label = gtk_label_new (""); + str = g_strdup_printf ("<span weight=\"bold\">%s</span>", _("Conflict Search")); + gtk_label_set_markup (GTK_LABEL (frame_label), str); + g_free (str); + gtk_misc_set_alignment (GTK_MISC (frame_label), 0.0, 0.5); + gtk_box_pack_start (GTK_BOX (frame), frame_label, FALSE, FALSE, 0); + + /* Indent/padding */ + hbox = gtk_hbox_new (FALSE, 12); + gtk_box_pack_start (GTK_BOX (frame), hbox, TRUE, TRUE, 0); + padding_label = gtk_label_new (""); + gtk_box_pack_start (GTK_BOX (hbox), padding_label, FALSE, FALSE, 0); + inner_vbox = gtk_vbox_new (FALSE, 6); + gtk_box_pack_start (GTK_BOX (hbox), inner_vbox, TRUE, TRUE, 0); + + /* Source selector */ + label = gtk_label_new (_("Select the calendars to search for meeting conflicts")); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + gtk_box_pack_start (GTK_BOX (inner_vbox), label, FALSE, FALSE, 0); + + scrolledwin = gtk_scrolled_window_new (NULL, NULL); + + gtk_scrolled_window_set_policy ( + GTK_SCROLLED_WINDOW (scrolledwin), + GTK_POLICY_AUTOMATIC, + GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type ( + GTK_SCROLLED_WINDOW (scrolledwin), + GTK_SHADOW_IN); + gtk_box_pack_start (GTK_BOX (inner_vbox), scrolledwin, TRUE, TRUE, 0); + + ess = e_conflict_search_selector_new (registry); + atk_object_set_name (gtk_widget_get_accessible (ess), _("Conflict Search")); + gtk_container_add (GTK_CONTAINER (scrolledwin), ess); + + gtk_widget_show_all (page); + + return page; +} diff --git a/plugins/itip-formatter/org-gnome-itip-formatter.eplug.xml b/modules/itip-formatter/plugin/org-gnome-itip-formatter.eplug.xml index 1cc441a37d..b60b0e129f 100644 --- a/plugins/itip-formatter/org-gnome-itip-formatter.eplug.xml +++ b/modules/itip-formatter/plugin/org-gnome-itip-formatter.eplug.xml @@ -1,19 +1,10 @@ <?xml version="1.0"?> <e-plugin-list> - <e-plugin id="org.gnome.evolution.itip_formatter" + <e-plugin id="org.gnome.evolution.itip_formatter" type="shlib" _name="Itip Formatter" location="@PLUGINDIR@/liborg-gnome-itip-formatter@SOEXT@"> <_description>Display "text/calendar" MIME parts in mail messages.</_description> <author name="JP Rosevear" email="jpr@novell.com"/> - - <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> <hook class="org.gnome.evolution.calendar.config:1.0"> <group id="org.gnome.evolution.calendar.prefs" target="prefs"> @@ -21,4 +12,4 @@ </group> </hook> </e-plugin> -</e-plugin-list> +</e-plugin-list>
\ No newline at end of file diff --git a/modules/prefer-plain/Makefile.am b/modules/prefer-plain/Makefile.am new file mode 100644 index 0000000000..e4e6b56d02 --- /dev/null +++ b/modules/prefer-plain/Makefile.am @@ -0,0 +1,28 @@ +SUBDIRS=plugin + +module_LTLIBRARIES = module-prefer-plain.la + +module_prefer_plain_la_CPPFLAGS = \ + $(AM_CPPFLAGS) \ + -I$(top_srcdir) \ + -I$(top_srcdir)/widgets \ + -DEVOLUTION_PRIVDATADIR=\""$(privdatadir)"\" \ + -DG_LOG_DOMAIN=\"evolution-module-prefer-plain\" \ + $(EVOLUTION_DATA_SERVER_CFLAGS) \ + $(GNOME_PLATFORM_CFLAGS) + +module_prefer_plain_la_SOURCES = \ + e-mail-parser-prefer-plain.c \ + e-mail-parser-prefer-plain.h \ + evolution-module-prefer-plain.c + +module_prefer_plain_la_LIBADD = \ + $(top_builddir)/mail/libevolution-mail.la \ + $(top_builddir)/em-format/libemformat.la \ + $(EVOLUTION_DATA_SERVER_LIBS) \ + $(GNOME_PLATFORM_LIBS) + +module_prefer_plain_la_LDFLAGS = \ + -avoid-version -module $(NO_UNDEFINED) + +-include $(top_srcdir)/git.mk diff --git a/modules/prefer-plain/e-mail-parser-prefer-plain.c b/modules/prefer-plain/e-mail-parser-prefer-plain.c new file mode 100644 index 0000000000..37da8d3a43 --- /dev/null +++ b/modules/prefer-plain/e-mail-parser-prefer-plain.c @@ -0,0 +1,553 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see <http://www.gnu.org/licenses/> + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <string.h> +#include <gtk/gtk.h> +#include <glib/gi18n.h> + +#include "e-mail-parser-prefer-plain.h" + +#include <em-format/e-mail-extension-registry.h> +#include <em-format/e-mail-parser-extension.h> +#include <em-format/e-mail-part.h> +#include <em-format/e-mail-part-utils.h> + +#include <libebackend/libebackend.h> + +#define d(x) + +typedef struct _EMailParserPreferPlain { + EExtension parent; + + GSettings *settings; + gint mode; + gboolean show_suppressed; +} EMailParserPreferPlain; + +typedef struct _EMailParserPreferPlainClass { + EExtensionClass parent_class; +} EMailParserPreferPlainClass; + +GType e_mail_parser_prefer_plain_get_type (void); +static void e_mail_parser_mail_extension_interface_init (EMailExtensionInterface *iface); +static void e_mail_parser_parser_extension_interface_init (EMailParserExtensionInterface *iface); + +enum { + EPP_NORMAL, + EPP_PREFER, + EPP_TEXT +}; + +G_DEFINE_DYNAMIC_TYPE_EXTENDED ( + EMailParserPreferPlain, + e_mail_parser_prefer_plain, + E_TYPE_EXTENSION, + 0, + G_IMPLEMENT_INTERFACE_DYNAMIC ( + E_TYPE_MAIL_EXTENSION, + e_mail_parser_mail_extension_interface_init) + G_IMPLEMENT_INTERFACE_DYNAMIC ( + E_TYPE_MAIL_PARSER_EXTENSION, + e_mail_parser_parser_extension_interface_init)); + +static const gchar* parser_mime_types[] = { "multipart/alternative", + "text/html", + NULL }; + +static struct { + const gchar *key; + const gchar *label; + const gchar *description; +} epp_options[] = { + { "normal", + N_("Show HTML if present"), + N_("Let Evolution choose the best part to show.") }, + + { "prefer_plain", + N_("Show plain text if present"), + N_("Show plain text part, if present, otherwise " + "let Evolution choose the best part to show.") }, + + { "only_plain", + N_("Only ever show plain text"), + N_("Always show plain text part and make attachments " + "from other parts, if requested.") }, +}; + +enum { + PROP_0, + PROP_MODE, + PROP_SHOW_SUPPRESSED +}; + +static GSList * +make_part_attachment (EMailParser *parser, + CamelMimePart *part, + GString *part_id, + gboolean force_html, + GCancellable *cancellable) +{ + GSList *parts; + + if (camel_content_type_is (camel_mime_part_get_content_type (part), "text", "html")) { + EMailPart *mail_part; + gint len; + /* always show HTML as attachments and not inline */ + camel_mime_part_set_disposition (part, "attachment"); + + if (!camel_mime_part_get_filename (part)) { + gchar *str = g_strdup_printf ("%s.html", _("attachment")); + camel_mime_part_set_filename (part, str); + g_free (str); + } + + len = part_id->len; + g_string_append (part_id, ".text_html"); + mail_part = e_mail_part_new (part, part_id->str); + mail_part->mime_type = g_strdup ("text/html"); + g_string_truncate (part_id, len); + + parts = e_mail_parser_wrap_as_attachment ( + parser, part, g_slist_append (NULL, mail_part), + part_id, cancellable); + + } else if (force_html && CAMEL_IS_MIME_MESSAGE (part)) { + /* message was asked to be formatted as text/html; + * might be for cases where message itself is a text/html part */ + CamelMimePart *new_part; + CamelDataWrapper *content; + + content = camel_medium_get_content (CAMEL_MEDIUM (part)); + g_return_val_if_fail (content != NULL, NULL); + + new_part = camel_mime_part_new (); + camel_medium_set_content (CAMEL_MEDIUM (new_part), content); + + parts = e_mail_parser_parse_part ( + parser, new_part, part_id, cancellable); + + g_object_unref (new_part); + } else { + parts = e_mail_parser_parse_part ( + parser, part, part_id, cancellable); + } + + return parts; +} + +static GSList * +export_as_attachments (CamelMultipart *mp, + EMailParser *parser, + CamelMimePart *except, + GString *part_id, + GCancellable *cancellable) +{ + gint i, nparts; + CamelMimePart *part; + gint len; + GSList *parts; + + if (!mp || !CAMEL_IS_MULTIPART (mp)) + return NULL; + + len = part_id->len; + nparts = camel_multipart_get_number (mp); + parts = NULL; + for (i = 0; i < nparts; i++) { + part = camel_multipart_get_part (mp, i); + + if (part != except) { + CamelMultipart *multipart = (CamelMultipart *) camel_medium_get_content ((CamelMedium *) part); + + g_string_append_printf (part_id, ".aleternative-prefer-plain.%d", i); + if (CAMEL_IS_MULTIPART (multipart)) { + parts = g_slist_concat (parts, + export_as_attachments ( + multipart, parser, + except, part_id, + cancellable)); + } else { + parts = g_slist_concat (parts, + make_part_attachment ( + parser, part, part_id, + FALSE, cancellable)); + } + g_string_truncate (part_id, len); + } + } + + return parts; +} + +static GSList * +empe_prefer_plain_parse (EMailParserExtension *extension, + EMailParser *parser, + CamelMimePart *part, + GString *part_id, + GCancellable *cancellable) +{ + EMailParserPreferPlain *emp_pp; + CamelMultipart *mp; + CamelMimePart *display_part = NULL, *calendar_part = NULL; + gint i, nparts, partidlen, displayid = 0, calendarid = 0; + GSList *parts; + + emp_pp = (EMailParserPreferPlain *) extension; + + /* We 'can' parse HTML as well! + * The reason simply is to convert the HTML part to attachment in some + * cases, otherwise we will return NULL and fallback to "normal" parser. */ + if (camel_content_type_is (camel_mime_part_get_content_type (part), "text", "html")) { + GQueue *extensions; + EMailExtensionRegistry *reg; + + reg = e_mail_parser_get_extension_registry (parser); + extensions = e_mail_extension_registry_get_for_mime_type ( + reg, "text/html"); + + if (emp_pp->mode != EPP_TEXT + || strstr (part_id->str, ".alternative-prefer-plain.") != NULL + || e_mail_part_is_inline (part, extensions)) { + + return NULL; + + } else if (emp_pp->show_suppressed) { + return make_part_attachment ( + parser, part, part_id, + TRUE, cancellable); + } + + /* Return an empty item. We MUST return something, otherwise + * the parser would think we have failed to parse the part + * and would let a fallback extension to parse it and we don't + * want that... */ + /* FIXME: In theory we could parse it anyway and just set + * is_hidden to TRUE....? */ + return g_slist_alloc (); + } + + mp = (CamelMultipart *) camel_medium_get_content ((CamelMedium *) part); + partidlen = part_id->len; + + parts = NULL; + if (emp_pp->mode == EPP_NORMAL) { + gboolean have_plain = FALSE; + + /* Try to find text/html part even when not as last and force + * to show it. Old handler will show the last part of + * multipart/alternate, but if we can offer HTML, then + * offer it, regardless of position in multipart. But do + * this when have only text/plain and text/html parts, + * not more. */ + nparts = camel_multipart_get_number (mp); + for (i = 0; i < nparts; i++) { + CamelContentType *content_type; + + part = camel_multipart_get_part (mp, i); + + if (!part) + continue; + + content_type = camel_mime_part_get_content_type (part); + + if (camel_content_type_is (content_type, "text", "html")) { + displayid = i; + display_part = part; + + if (have_plain) + break; + } else if (camel_content_type_is (content_type, "text", "plain")) { + have_plain = TRUE; + + if (display_part) + break; + } + } + + if (display_part && have_plain && nparts == 2) { + g_string_append_printf (part_id, ".alternative-prefer-plain.%d", displayid); + /* FIXME Not passing a GCancellable here. */ + parts = e_mail_parser_parse_part_as ( + parser, display_part, part_id, + "text/html", cancellable); + + g_string_truncate (part_id, partidlen); + } else { + /* Parser will automatically fallback to next extension */ + return NULL; + + } + + return parts; + + } else if (!CAMEL_IS_MULTIPART (mp)) { + return e_mail_parser_parse_part_as ( + parser, part, part_id, + "application/vnd.evolution.source", cancellable); + } + + nparts = camel_multipart_get_number (mp); + for (i = 0; i < nparts; i++) { + CamelContentType *ct; + + part = camel_multipart_get_part (mp, i); + + if (!part) + continue; + + ct = camel_mime_part_get_content_type (part); + if (!display_part && camel_content_type_is (ct, "text", "plain")) { + displayid = i; + display_part = part; + } else if (!calendar_part && (camel_content_type_is (ct, "text", "calendar") || camel_content_type_is (ct, "text", "x-calendar"))) { + calendarid = i; + calendar_part = part; + } + } + + /* if we found a text part, show it */ + if (display_part) { + g_string_append_printf(part_id, ".alternative-prefer-plain.%d", displayid); + parts = g_slist_concat (parts, + e_mail_parser_parse_part_as ( + parser, display_part, part_id, + "text/plain", cancellable)); + + g_string_truncate (part_id, partidlen); + } + + /* all other parts are attachments */ + if (emp_pp->show_suppressed) { + parts = g_slist_concat (parts, + export_as_attachments ( + mp, parser, display_part, part_id, + cancellable)); + } else if (calendar_part) { + g_string_append_printf(part_id, ".alternative-prefer-plain.%d", calendarid); + parts = g_slist_concat (parts, + make_part_attachment ( + parser, calendar_part, part_id, + FALSE, NULL)); + } + + g_string_truncate (part_id, partidlen); + + return parts; +} + +static const gchar ** +empe_mime_types (EMailExtension *extension) +{ + return parser_mime_types; +} + +void +e_mail_parser_prefer_plain_type_register (GTypeModule *type_module) +{ + e_mail_parser_prefer_plain_register_type (type_module); +} + +static void +e_mail_parser_mail_extension_interface_init (EMailExtensionInterface *iface) +{ + iface->mime_types = empe_mime_types; +} + +static void +e_mail_parser_parser_extension_interface_init (EMailParserExtensionInterface *iface) +{ + iface->parse = empe_prefer_plain_parse; +} + +static void +e_mail_parser_prefer_plain_constructed (GObject *object) +{ + EExtensible *extensible; + EMailExtensionRegistry *reg; + + extensible = e_extension_get_extensible (E_EXTENSION (object)); + reg = E_MAIL_EXTENSION_REGISTRY (extensible); + + e_mail_extension_registry_add_extension (reg, E_MAIL_EXTENSION (object)); +} + +static void +e_mail_parser_prefer_plain_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + EMailParserPreferPlain *parser; + + parser = (EMailParserPreferPlain *) object; + + switch (property_id) { + case PROP_MODE: + g_value_set_int (value, parser->mode); + return; + case PROP_SHOW_SUPPRESSED: + g_value_set_boolean (value, parser->show_suppressed); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +e_mail_parser_prefer_plain_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + EMailParserPreferPlain *parser; + + parser = (EMailParserPreferPlain *) object; + + switch (property_id) { + case PROP_MODE: + parser->mode = g_value_get_int (value); + return; + case PROP_SHOW_SUPPRESSED: + parser->show_suppressed = g_value_get_boolean (value); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +e_mail_parser_prefer_plain_finalize (GObject *object) +{ + EMailParserPreferPlain *parser; + + parser = (EMailParserPreferPlain *) object; + + g_clear_object (&parser->settings); + + G_OBJECT_CLASS (e_mail_parser_prefer_plain_parent_class)->finalize (object); +} + +static void +e_mail_parser_prefer_plain_class_init (EMailParserPreferPlainClass *klass) +{ + GObjectClass *object_class; + EExtensionClass *extension_class; + + e_mail_parser_prefer_plain_parent_class = g_type_class_peek_parent (klass); + + object_class = G_OBJECT_CLASS (klass); + object_class->constructed = e_mail_parser_prefer_plain_constructed; + object_class->get_property = e_mail_parser_prefer_plain_get_property; + object_class->set_property = e_mail_parser_prefer_plain_set_property; + object_class->finalize = e_mail_parser_prefer_plain_finalize; + + extension_class = E_EXTENSION_CLASS (klass); + extension_class->extensible_type = E_TYPE_MAIL_PARSER_EXTENSION_REGISTRY; + + g_object_class_install_property ( + object_class, + PROP_MODE, + g_param_spec_int ( + "mode", + "Mode", + NULL, + EPP_NORMAL, + EPP_TEXT, + EPP_NORMAL, + G_PARAM_READABLE | G_PARAM_WRITABLE)); + + g_object_class_install_property ( + object_class, + PROP_SHOW_SUPPRESSED, + g_param_spec_boolean ( + "show-suppressed", + "Show Suppressed", + NULL, + FALSE, + G_PARAM_READABLE | G_PARAM_WRITABLE)); +} + +void +e_mail_parser_prefer_plain_class_finalize (EMailParserPreferPlainClass *klass) +{ +} + +static gboolean +parser_mode_get_mapping (GValue *value, + GVariant *variant, + gpointer user_data) +{ + gint i; + + const gchar *key = g_variant_get_string (variant, NULL); + if (key) { + for (i = 0; i < G_N_ELEMENTS (epp_options); i++) { + if (!strcmp (epp_options[i].key, key)) { + g_value_set_int (value, i); + return TRUE; + } + } + } else { + g_value_set_int (value, 0); + } + + return TRUE; +} + +static GVariant * +parser_mode_set_mapping (const GValue *value, + const GVariantType *expected_type, + gpointer user_data) +{ + return g_variant_new_string (epp_options[g_value_get_int (value)].key); +} + +static void +e_mail_parser_prefer_plain_init (EMailParserPreferPlain *parser) +{ + gchar *key; + gint i; + + parser->settings = g_settings_new ("org.gnome.evolution.plugin.prefer-plain"); + g_settings_bind_with_mapping ( + parser->settings, "mode", + parser, "mode", G_SETTINGS_BIND_DEFAULT, + parser_mode_get_mapping, + parser_mode_set_mapping, + NULL, NULL); + g_settings_bind ( + parser->settings, "show-suppressed", + parser, "show-suppressed", G_SETTINGS_BIND_DEFAULT); + + /* Initialize the settings */ + key = g_settings_get_string (parser->settings, "mode"); + if (key) { + for (i = 0; i < G_N_ELEMENTS (epp_options); i++) { + if (!strcmp (epp_options[i].key, key)) { + parser->mode = i; + break; + } + } + g_free (key); + } else { + parser->mode = 0; + } + + parser->show_suppressed = g_settings_get_boolean (parser->settings, "show-suppressed"); +} diff --git a/modules/prefer-plain/e-mail-parser-prefer-plain.h b/modules/prefer-plain/e-mail-parser-prefer-plain.h new file mode 100644 index 0000000000..4cfb8226f9 --- /dev/null +++ b/modules/prefer-plain/e-mail-parser-prefer-plain.h @@ -0,0 +1,30 @@ +/* + * e-mail-parser-prefer-plain.h + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see <http://www.gnu.org/licenses/> + * + */ + +#ifndef E_MAIL_PARSER_PREFER_PLAIN_H +#define E_MAIL_PARSER_PREFER_PLAIN_H + +#include <glib-object.h> + +G_BEGIN_DECLS + +void e_mail_parser_prefer_plain_type_register (GTypeModule *type_module); + +G_END_DECLS + +#endif /* E_MAIL_PARSER_PREFER_PLAIN_H */ diff --git a/modules/prefer-plain/evolution-module-prefer-plain.c b/modules/prefer-plain/evolution-module-prefer-plain.c new file mode 100644 index 0000000000..cb81932594 --- /dev/null +++ b/modules/prefer-plain/evolution-module-prefer-plain.c @@ -0,0 +1,73 @@ +/* + * evolution-module-prefer-plain.c + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see <http://www.gnu.org/licenses/> + * + */ + +#include "e-mail-parser-prefer-plain.h" + +#include <gmodule.h> +#include <gio/gio.h> + +void e_module_load (GTypeModule *type_module); +void e_module_unload (GTypeModule *type_module); +const gchar * g_module_check_init (GModule *module); + +G_MODULE_EXPORT void +e_module_load (GTypeModule *type_module) +{ + GSettings *settings; + gchar **disabled_plugins; + gint i = 0; + + settings = g_settings_new ("org.gnome.evolution"); + disabled_plugins = g_settings_get_strv (settings, "disabled-eplugins"); + + for (i = 0; disabled_plugins && disabled_plugins[i] != NULL; i++) { + + if (g_strcmp0 ( + disabled_plugins[i], + "org.gnome.evolution.plugin.preferPlain") == 0) { + + g_strfreev (disabled_plugins); + g_object_unref (settings); + return; + } + + } + + e_mail_parser_prefer_plain_type_register (type_module); + + g_strfreev (disabled_plugins); + g_object_unref (settings); +} + +G_MODULE_EXPORT void +e_module_unload (GTypeModule *type_module) +{ +} + +G_MODULE_EXPORT const gchar * +g_module_check_init (GModule *module) +{ + /* FIXME Until mail is split into a module library and a + * reusable shared library, prevent the module from + * being unloaded. Unloading the module resets all + * static variables, which screws up foo_get_type() + * functions among other things. */ + g_module_make_resident (module); + + return NULL; +} diff --git a/plugins/prefer-plain/Makefile.am b/modules/prefer-plain/plugin/Makefile.am index 5375da81fd..3a0e16d29a 100644 --- a/plugins/prefer-plain/Makefile.am +++ b/modules/prefer-plain/plugin/Makefile.am @@ -1,28 +1,28 @@ @EVO_PLUGIN_RULE@ plugin_DATA = org-gnome-prefer-plain.eplug - plugin_LTLIBRARIES = liborg-gnome-prefer-plain.la -liborg_gnome_prefer_plain_la_CPPFLAGS = \ +liborg_gnome_prefer_plain_la_CPPFLAGS = \ $(AM_CPPFLAGS) \ -I$(top_srcdir) \ + -I$(top_srcdir)/widgets \ + -DEVOLUTION_PRIVDATADIR=\""$(privdatadir)"\" \ $(EVOLUTION_DATA_SERVER_CFLAGS) \ $(GNOME_PLATFORM_CFLAGS) -liborg_gnome_prefer_plain_la_SOURCES = prefer-plain.c +liborg_gnome_prefer_plain_la_SOURCES = \ + config-ui.c liborg_gnome_prefer_plain_la_LDFLAGS = -module -avoid-version $(NO_UNDEFINED) -liborg_gnome_prefer_plain_la_LIBADD = \ - $(top_builddir)/mail/libevolution-mail.la \ - $(top_builddir)/em-format/libemformat.la \ - $(EVOLUTION_DATA_SERVER_LIBS) \ +liborg_gnome_prefer_plain_la_LIBADD = \ + $(EVOLUTION_DATA_SERVER_LIBS) \ $(GNOME_PLATFORM_LIBS) -EXTRA_DIST = org-gnome-prefer-plain.eplug.xml - BUILT_SOURCES = $(plugin_DATA) + CLEANFILES = $(BUILT_SOURCES) --include $(top_srcdir)/git.mk +EXTRA_DIST = \ + org-gnome-prefer-plain.eplug.xml diff --git a/modules/prefer-plain/plugin/config-ui.c b/modules/prefer-plain/plugin/config-ui.c new file mode 100644 index 0000000000..29b81a60fe --- /dev/null +++ b/modules/prefer-plain/plugin/config-ui.c @@ -0,0 +1,192 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see <http://www.gnu.org/licenses/> + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <gtk/gtk.h> +#include <glib/gi18n.h> + +#include <mail/em-config.h> + +#include <libedataserverui/libedataserverui.h> + +GtkWidget *prefer_plain_page_factory (EPlugin *ep, EConfigHookItemFactoryData *hook_data); + +enum { + EPP_NORMAL, + EPP_PREFER, + EPP_TEXT +}; + +static GSettings *epp_settings = NULL; +static gint epp_mode = -1; +static gboolean epp_show_suppressed = TRUE; + +static struct { + const gchar *key; + const gchar *label; + const gchar *description; +} epp_options[] = { + { "normal", + N_("Show HTML if present"), + N_("Let Evolution choose the best part to show.") }, + + { "prefer_plain", + N_("Show plain text if present"), + N_("Show plain text part, if present, otherwise " + "let Evolution choose the best part to show.") }, + + { "only_plain", + N_("Only ever show plain text"), + N_("Always show plain text part and make attachments " + "from other parts, if requested.") }, +}; + +static void +update_info_label (GtkWidget *info_label, + guint mode) +{ + gchar *str = g_strconcat ("<i>", _(epp_options[mode > 2 ? 0 : mode].description), "</i>", NULL); + + gtk_label_set_markup (GTK_LABEL (info_label), str); + + g_free (str); +} + +static void +epp_mode_changed (GtkComboBox *dropdown, + GtkWidget *info_label) +{ + epp_mode = gtk_combo_box_get_active (dropdown); + if (epp_mode > 2) + epp_mode = 0; + + g_settings_set_string (epp_settings, "mode", epp_options[epp_mode].key); + update_info_label (info_label, epp_mode); +} + +static void +epp_show_suppressed_toggled (GtkToggleButton *check, + gpointer data) +{ + g_return_if_fail (check != NULL); + + epp_show_suppressed = gtk_toggle_button_get_active (check); + g_settings_set_boolean (epp_settings, "show-suppressed", epp_show_suppressed); +} + +GtkWidget * +prefer_plain_page_factory (EPlugin *epl, + struct _EConfigHookItemFactoryData *data) +{ + GtkComboBox *dropdown; + GtkCellRenderer *cell; + GtkListStore *store; + GtkWidget *dropdown_label, *info, *check; + guint i; + GtkTreeIter iter; + + if (data->old) + return data->old; + + check = gtk_check_button_new_with_mnemonic (_("Show s_uppressed HTML parts as attachments")); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check), epp_show_suppressed); + gtk_widget_show (check); + g_signal_connect ( + check, "toggled", + G_CALLBACK (epp_show_suppressed_toggled), NULL); + + dropdown = (GtkComboBox *) gtk_combo_box_new (); + cell = gtk_cell_renderer_text_new (); + store = gtk_list_store_new (1, G_TYPE_STRING); + for (i = 0; i < G_N_ELEMENTS (epp_options); i++) { + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, 0, _(epp_options[i].label), -1); + } + + gtk_cell_layout_pack_start ((GtkCellLayout *) dropdown, cell, TRUE); + gtk_cell_layout_set_attributes((GtkCellLayout *)dropdown, cell, "text", 0, NULL); + gtk_combo_box_set_model (dropdown, (GtkTreeModel *) store); + /*gtk_combo_box_set_active(dropdown, -1);*/ + gtk_combo_box_set_active (dropdown, epp_mode); + gtk_widget_show ((GtkWidget *) dropdown); + + dropdown_label = gtk_label_new_with_mnemonic (_("HTML _Mode")); + gtk_widget_show (dropdown_label); + gtk_label_set_mnemonic_widget (GTK_LABEL (dropdown_label), (GtkWidget *) dropdown); + + info = gtk_label_new (NULL); + gtk_misc_set_alignment (GTK_MISC (info), 0.0, 0.5); + gtk_label_set_line_wrap (GTK_LABEL (info), TRUE); + + gtk_widget_show (info); + update_info_label (info, epp_mode); + + g_signal_connect ( + dropdown, "changed", + G_CALLBACK (epp_mode_changed), info); + + g_object_get (data->parent, "n-rows", &i, NULL); + gtk_table_attach ((GtkTable *) data->parent, check, 0, 2, i, i + 1, GTK_FILL | GTK_EXPAND, 0, 0, 0); + gtk_table_attach ((GtkTable *) data->parent, dropdown_label, 0, 1, i + 1, i + 2, 0, 0, 0, 0); + gtk_table_attach ((GtkTable *) data->parent, (GtkWidget *) dropdown, 1, 2, i + 1, i + 2, GTK_FILL | GTK_EXPAND, 0, 0, 0); + gtk_table_attach ((GtkTable *) data->parent, info, 1, 2, i + 2, i + 3, GTK_FILL | GTK_EXPAND, 0, 0, 0); + + /* since this isnt dynamic, we don't need to track each item */ + + return (GtkWidget *) dropdown; +} + +gint e_plugin_lib_enable (EPlugin *ep, gint enable); + +gint +e_plugin_lib_enable (EPlugin *ep, + gint enable) +{ + gchar *key; + gint i; + + if (epp_settings || epp_mode != -1) + return 0; + + if (enable) { + + epp_settings = g_settings_new ("org.gnome.evolution.plugin.prefer-plain"); + key = g_settings_get_string (epp_settings, "mode"); + if (key) { + for (i = 0; i < G_N_ELEMENTS (epp_options); i++) { + if (!strcmp (epp_options[i].key, key)) { + epp_mode = i; + break; + } + } + g_free (key); + } else { + epp_mode = 0; + } + + epp_show_suppressed = g_settings_get_boolean (epp_settings, "show-suppressed"); + } else { + if (epp_settings) { + g_object_unref (epp_settings); + epp_settings = NULL; + } + } + + return 0; +} diff --git a/plugins/prefer-plain/org-gnome-prefer-plain.eplug.xml b/modules/prefer-plain/plugin/org-gnome-prefer-plain.eplug.xml index 6d0c3ae6ac..43948e3a69 100644 --- a/plugins/prefer-plain/org-gnome-prefer-plain.eplug.xml +++ b/modules/prefer-plain/plugin/org-gnome-prefer-plain.eplug.xml @@ -17,21 +17,9 @@ <!-- we could also just insert our own items from a section factory, --> <!-- but then we also need to create our own section frame --> <item type="section_table" path="10.html/80.mode" _label="Plain Text Mode"/> - <item type="item_table" path="10.html/80.mode/00.mode" factory="org_gnome_prefer_plain_config_mode"/> - </group> - </hook> - - <hook class="org.gnome.evolution.mail.format:1.0"> - <!-- need to override all formatters that override this type --> - <group id="EMFormatHTMLDisplay"> - <item mime_type="multipart/alternative" format="org_gnome_prefer_plain_multipart_alternative"/> - <item mime_type="text/html" format="org_gnome_prefer_plain_text_html"/> - </group> - <group id="EMFormat"> - <item mime_type="multipart/alternative" format="org_gnome_prefer_plain_multipart_alternative"/> - <item mime_type="text/html" format="org_gnome_prefer_plain_text_html"/> + <item type="item_table" path="10.html/80.mode/00.mode" factory="prefer_plain_page_factory"/> </group> </hook> </e-plugin> -</e-plugin-list> +</e-plugin-list>
\ No newline at end of file diff --git a/modules/text-highlight/Makefile.am b/modules/text-highlight/Makefile.am new file mode 100644 index 0000000000..9b27298474 --- /dev/null +++ b/modules/text-highlight/Makefile.am @@ -0,0 +1,27 @@ +module_LTLIBRARIES = module-text-highlight.la + +module_text_highlight_la_CPPFLAGS = \ + $(AM_CPPFLAGS) \ + -I$(top_srcdir) \ + -I$(top_srcdir)/widgets \ + -DEVOLUTION_PRIVDATADIR=\""$(privdatadir)"\" \ + -DG_LOG_DOMAIN=\"evolution-module-text-highlight\" \ + $(EVOLUTION_DATA_SERVER_CFLAGS) \ + $(GNOME_PLATFORM_CFLAGS) + +module_text_highlight_la_SOURCES = \ + text-highlight.c \ + text-highlight.h \ + evolution-module-text-highlight.c + +module_text_highlight_la_LIBADD = \ + $(top_builddir)/e-util/libeutil.la \ + $(top_builddir)/mail/libevolution-mail.la \ + $(top_builddir)/em-format/libemformat.la \ + $(EVOLUTION_DATA_SERVER_LIBS) \ + $(GNOME_PLATFORM_LIBS) + +module_text_highlight_la_LDFLAGS = \ + -avoid-version -module $(NO_UNDEFINED) + +-include $(top_srcdir)/git.mk diff --git a/modules/text-highlight/evolution-module-text-highlight.c b/modules/text-highlight/evolution-module-text-highlight.c new file mode 100644 index 0000000000..de6e469bde --- /dev/null +++ b/modules/text-highlight/evolution-module-text-highlight.c @@ -0,0 +1,51 @@ +/* + * evolution-module-text-highlight.c + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see <http://www.gnu.org/licenses/> + * + */ + +#include "text-highlight.h" + +#include <gmodule.h> + +void e_module_load (GTypeModule *type_module); +void e_module_unload (GTypeModule *type_module); +const gchar * g_module_check_init (GModule *module); + +G_MODULE_EXPORT void +e_module_load (GTypeModule *type_module) +{ + /* Register dynamically loaded types. */ + + e_mail_formatter_text_highlight_type_register (type_module); +} + +G_MODULE_EXPORT void +e_module_unload (GTypeModule *type_module) +{ +} + +G_MODULE_EXPORT const gchar * +g_module_check_init (GModule *module) +{ + /* FIXME Until mail is split into a module library and a + * reusable shared library, prevent the module from + * being unloaded. Unloading the module resets all + * static variables, which screws up foo_get_type() + * functions among other things. */ + g_module_make_resident (module); + + return NULL; +} diff --git a/modules/text-highlight/text-highlight.c b/modules/text-highlight/text-highlight.c new file mode 100644 index 0000000000..462e5f0dc3 --- /dev/null +++ b/modules/text-highlight/text-highlight.c @@ -0,0 +1,314 @@ +/* + * text-highlight.c + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see <http://www.gnu.org/licenses/> + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "text-highlight.h" + +#include <em-format/e-mail-formatter-extension.h> +#include <em-format/e-mail-formatter.h> +#include <em-format/e-mail-part-utils.h> +#include <e-util/e-util.h> + +#include <libebackend/libebackend.h> +#include <libedataserver/libedataserver.h> + +#include <glib/gi18n-lib.h> +#include <X11/Xlib.h> +#include <camel/camel.h> + +typedef struct _EMailFormatterTextHighlight EMailFormatterTextHighlight; +typedef struct _EMailFormatterTextHighlightClass EMailFormatterTextHighlightClass; + +struct _EMailFormatterTextHighlight { + EExtension parent; +}; + +struct _EMailFormatterTextHighlightClass { + EExtensionClass parent_class; +}; + +GType e_mail_formatter_text_highlight_get_type (void); +static void e_mail_formatter_formatter_extension_interface_init (EMailFormatterExtensionInterface *iface); +static void e_mail_formatter_mail_extension_interface_init (EMailExtensionInterface *iface); + +G_DEFINE_DYNAMIC_TYPE_EXTENDED ( + EMailFormatterTextHighlight, + e_mail_formatter_text_highlight, + E_TYPE_EXTENSION, + 0, + G_IMPLEMENT_INTERFACE_DYNAMIC ( + E_TYPE_MAIL_EXTENSION, + e_mail_formatter_mail_extension_interface_init) + G_IMPLEMENT_INTERFACE_DYNAMIC ( + E_TYPE_MAIL_FORMATTER_EXTENSION, + e_mail_formatter_formatter_extension_interface_init)); + +static gpointer emfe_parent_class = 0; + +static const gchar *formatter_mime_types[] = { "text/x-diff", + "text/x-patch", + NULL }; + +static gchar * get_default_font (void) +{ + gchar *font; + GSettings *settings; + + settings = g_settings_new ("org.gnome.desktop.interface"); + + font = g_settings_get_string (settings, "monospace-font-name"); + + return font ? font : g_strdup ("monospace 10"); +} + +static gboolean +emfe_text_highlight_format (EMailFormatterExtension *extension, + EMailFormatter *formatter, + EMailFormatterContext *context, + EMailPart *part, + CamelStream *stream, + GCancellable *cancellable) +{ + if (context->mode == E_MAIL_FORMATTER_MODE_PRINTING) { + + CamelDataWrapper *dw; + CamelStream *filter_stream; + CamelMimeFilter *mime_filter; + + dw = camel_medium_get_content (CAMEL_MEDIUM (part->part)); + if (!dw) { + return FALSE; + } + + camel_stream_write_string ( + stream, "<pre><div class=\"pre\">", cancellable, NULL); + + filter_stream = camel_stream_filter_new (stream); + mime_filter = camel_mime_filter_tohtml_new ( + CAMEL_MIME_FILTER_TOHTML_PRE | + CAMEL_MIME_FILTER_TOHTML_CONVERT_SPACES, + 0x7a7a7a); + camel_stream_filter_add ( + CAMEL_STREAM_FILTER (filter_stream), mime_filter); + g_object_unref (mime_filter); + + e_mail_formatter_format_text ( + formatter, part, filter_stream, cancellable); + + camel_stream_flush (filter_stream, cancellable, NULL); + g_object_unref (filter_stream); + + camel_stream_write_string ( + stream, "</div></pre>", cancellable, NULL); + + return TRUE; + + } else if (context->mode == E_MAIL_FORMATTER_MODE_RAW) { + gint stdin, stdout; + GPid pid; + CamelStream *read, *write; + CamelDataWrapper *dw; + gchar *font_family, *font_size; + gboolean use_custom_font; + GSettings *settings; + PangoFontDescription *fd; + const gchar *argv[] = { "highlight", + NULL, /* don't move these! */ + NULL, + "--out-format=html", + "--include-style", + "--inline-css", + "--style=bclear", + "--syntax=diff", + "--failsafe", + NULL }; + + dw = camel_medium_get_content (CAMEL_MEDIUM (part->part)); + if (!dw) { + return FALSE; + } + + fd = NULL; + settings = g_settings_new ("org.gnome.evolution.mail"); + use_custom_font = g_settings_get_boolean (settings, "use-custom-font"); + if (!use_custom_font) { + gchar *font; + + font = get_default_font (); + fd = pango_font_description_from_string (font); + g_free (font); + + g_object_unref (settings); + + } else { + gchar *font; + + font = g_settings_get_string (settings, "monospace-font"); + if (!font) + font = get_default_font (); + + fd = pango_font_description_from_string (font); + + g_free (font); + } + + font_family = g_strdup_printf ("--font='%s'", + pango_font_description_get_family (fd)); + font_size = g_strdup_printf ("--font-size=%d", + pango_font_description_get_size (fd) / PANGO_SCALE); + + argv[1] = font_family; + argv[2] = font_size; + + if (!g_spawn_async_with_pipes ( + NULL, (gchar **) argv, NULL, + G_SPAWN_SEARCH_PATH | + G_SPAWN_DO_NOT_REAP_CHILD, + NULL, NULL, &pid, &stdin, &stdout, NULL, NULL)) { + return FALSE; + } + + write = camel_stream_fs_new_with_fd (stdin); + read = camel_stream_fs_new_with_fd (stdout); + + camel_data_wrapper_decode_to_stream_sync ( + dw, write, cancellable, NULL); + g_object_unref (write); + + g_spawn_close_pid (pid); + + g_seekable_seek (G_SEEKABLE (read), 0, G_SEEK_SET, cancellable, NULL); + camel_stream_write_to_stream (read, stream, cancellable, NULL); + camel_stream_flush (read, cancellable, NULL); + g_object_unref (read); + + g_free (font_family); + g_free (font_size); + pango_font_description_free (fd); + + } else { + gchar *uri, *str; + + uri = e_mail_part_build_uri ( + context->folder, context->message_uid, + "part_id", G_TYPE_STRING, part->id, + "mode", G_TYPE_INT, E_MAIL_FORMATTER_MODE_RAW, + NULL); + + str = g_strdup_printf ( + "<div class=\"part-container\" style=\"border-color: #%06x; " + "background-color: #%06x;\">" + "<div class=\"part-container-inner-margin\">\n" + "<iframe width=\"100%%\" height=\"10\"" + " name=\"%s\" frameborder=\"0\" src=\"%s\"></iframe>" + "</div></div>", + e_color_to_value ((GdkColor *) + e_mail_formatter_get_color ( + formatter, E_MAIL_FORMATTER_COLOR_FRAME)), + e_color_to_value ((GdkColor *) + e_mail_formatter_get_color ( + formatter, E_MAIL_FORMATTER_COLOR_CONTENT)), + part->id, uri); + + camel_stream_write_string (stream, str, cancellable, NULL); + + g_free (str); + g_free (uri); + + } + + return TRUE; +} + +static const gchar * +emfe_text_highlight_get_display_name (EMailFormatterExtension *extension) +{ + return _("Patch"); +} + +static const gchar * +emfe_text_highlight_get_description (EMailFormatterExtension *extension) +{ + return _("Format part as a patch"); +} + +static const gchar ** +emfe_text_highlight_mime_types (EMailExtension *extension) +{ + return formatter_mime_types; +} + +static void +emfe_text_highlight_constructed (GObject *object) +{ + EExtensible *extensible; + EMailExtensionRegistry *reg; + + extensible = e_extension_get_extensible (E_EXTENSION (object)); + reg = E_MAIL_EXTENSION_REGISTRY (extensible); + + e_mail_extension_registry_add_extension (reg, E_MAIL_EXTENSION (object)); +} + +static void +e_mail_formatter_text_highlight_init (EMailFormatterTextHighlight *object) +{ +} + +static void +e_mail_formatter_text_highlight_class_init (EMailFormatterTextHighlightClass *klass) +{ + GObjectClass *object_class; + EExtensionClass *extension_class; + + emfe_parent_class = g_type_class_peek_parent (klass); + + object_class = G_OBJECT_CLASS (klass); + object_class->constructed = emfe_text_highlight_constructed; + + extension_class = E_EXTENSION_CLASS (klass); + extension_class->extensible_type = E_TYPE_MAIL_FORMATTER_EXTENSION_REGISTRY; +} + +static void +e_mail_formatter_text_highlight_class_finalize (EMailFormatterTextHighlightClass *klass) +{ +} + +void +e_mail_formatter_text_highlight_type_register (GTypeModule *type_module) +{ + e_mail_formatter_text_highlight_register_type (type_module); +} + +static void +e_mail_formatter_formatter_extension_interface_init (EMailFormatterExtensionInterface *iface) +{ + iface->format = emfe_text_highlight_format; + iface->get_display_name = emfe_text_highlight_get_display_name; + iface->get_description = emfe_text_highlight_get_description; +} + +static void +e_mail_formatter_mail_extension_interface_init (EMailExtensionInterface *iface) +{ + iface->mime_types = emfe_text_highlight_mime_types; +} diff --git a/modules/text-highlight/text-highlight.h b/modules/text-highlight/text-highlight.h new file mode 100644 index 0000000000..af10da4c84 --- /dev/null +++ b/modules/text-highlight/text-highlight.h @@ -0,0 +1,30 @@ +/* + * text-highlight.h + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see <http://www.gnu.org/licenses/> + * + */ + +#ifndef TEXT_HIGHLIGHT_H +#define TEXT_HIGHLIGHT_H + +#include <glib-object.h> + +G_BEGIN_DECLS + +void e_mail_formatter_text_highlight_type_register (GTypeModule *type_module); + +G_END_DECLS + +#endif /* TEXT_HIGHLIGHT_H */ diff --git a/modules/tnef-attachment/Makefile.am b/modules/tnef-attachment/Makefile.am new file mode 100644 index 0000000000..ff5b412275 --- /dev/null +++ b/modules/tnef-attachment/Makefile.am @@ -0,0 +1,34 @@ +if OS_WIN32 +NO_UNDEFINED_REQUIRED_LIBS = \ + $(top_builddir)/e-util/libeutil.la \ + $(top_builddir)/mail/libevolution-mail.la +endif + +module_LTLIBRARIES = module-tnef-attachment.la + +module_tnef_attachment_la_CPPFLAGS = \ + $(AM_CPPFLAGS) \ + -I$(top_srcdir) \ + -I$(top_srcdir)/widgets \ + -DEVOLUTION_PRIVDATADIR=\""$(privdatadir)"\" \ + -DG_LOG_DOMAIN=\"evolution-module-tnef-attachment\" \ + $(EVOLUTION_DATA_SERVER_CFLAGS) \ + $(GNOME_PLATFORM_CFLAGS) \ + $(TNEF_CFLAGS) + +module_tnef_attachment_la_SOURCES = \ + e-mail-parser-tnef-attachment.c \ + e-mail-parser-tnef-attachment.h \ + evolution-module-tnef-attachment.c + +module_tnef_attachment_la_LIBADD = \ + $(top_builddir)/e-util/libeutil.la \ + $(top_builddir)/em-format/libemformat.la \ + $(EVOLUTION_DATA_SERVER_LIBS) \ + $(GNOME_PLATFORM_LIBS) \ + -lytnef + +module_tnef_attachment_la_LDFLAGS = \ + -avoid-version -module $(NO_UNDEFINED) + +-include $(top_srcdir)/git.mk diff --git a/plugins/tnef-attachments/tnef-plugin.c b/modules/tnef-attachment/e-mail-parser-tnef-attachment.c index 52cd68664f..854a17765a 100644 --- a/plugins/tnef-attachments/tnef-plugin.c +++ b/modules/tnef-attachment/e-mail-parser-tnef-attachment.c @@ -1,5 +1,4 @@ /* - * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either @@ -12,23 +11,25 @@ * * You should have received a copy of the GNU Lesser General Public * License along with the program; if not, see <http://www.gnu.org/licenses/> - * - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * Copyright (C) Randall Hand <randall.hand@gmail.com> - * */ #ifdef HAVE_CONFIG_H #include <config.h> #endif -/* We include gi18n-lib.h so that we have strings translated directly for this package */ -#include <glib/gi18n-lib.h> -#include <glib/gprintf.h> #include <string.h> +#include <gtk/gtk.h> +#include <glib/gi18n.h> +#include <glib/gprintf.h> #include <stdio.h> +#include "e-mail-parser-tnef-attachment.h" + +#include <em-format/e-mail-extension-registry.h> +#include <em-format/e-mail-parser-extension.h> +#include <em-format/e-mail-part.h> +#include <em-format/e-mail-part-utils.h> + #include <sys/types.h> #include <dirent.h> #include <sys/stat.h> @@ -41,11 +42,45 @@ #include <libytnef/ytnef.h> #endif -#include <em-format/em-format.h> -#include <mail/em-format-hook.h> #include <mail/em-utils.h> #include <e-util/e-mktemp.h> +#include <libebackend/libebackend.h> + +#define d(x) + +typedef struct _EMailParserTnefAttachment { + EExtension parent; + + GSettings *settings; + gint mode; + gboolean show_suppressed; +} EMailParserTnefAttachment; + +typedef struct _EMailParserTnefAttachmentClass { + EExtensionClass parent_class; +} EMailParserTnefAttachmentClass; + +GType e_mail_parser_tnef_attachment_get_type (void); +static void e_mail_parser_mail_extension_interface_init (EMailExtensionInterface *iface); +static void e_mail_parser_parser_extension_interface_init (EMailParserExtensionInterface *iface); + +G_DEFINE_DYNAMIC_TYPE_EXTENDED ( + EMailParserTnefAttachment, + e_mail_parser_tnef_attachment, + E_TYPE_EXTENSION, + 0, + G_IMPLEMENT_INTERFACE_DYNAMIC ( + E_TYPE_MAIL_EXTENSION, + e_mail_parser_mail_extension_interface_init) + G_IMPLEMENT_INTERFACE_DYNAMIC ( + E_TYPE_MAIL_PARSER_EXTENSION, + e_mail_parser_parser_extension_interface_init)); + +static const gchar* parser_mime_types[] = { "application/vnd.ms-tnef", + "application/ms-tnefl", + NULL }; + gint verbose = 0; gint saveRTF = 0; gint saveintermediate = 0; @@ -55,8 +90,6 @@ void saveVCalendar (TNEFStruct *tnef, const gchar *tmpdir); void saveVCard (TNEFStruct *tnef, const gchar *tmpdir); void saveVTask (TNEFStruct *tnef, const gchar *tmpdir); -void org_gnome_format_tnef (gpointer ep, EMFormatHookTarget *t); - /* Other Prototypes */ void fprintProperty (TNEFStruct *tnef, FILE *fptr, DWORD proptype, DWORD propid, const gchar text[]); void fprintUserProp (TNEFStruct *tnef, FILE *fptr, DWORD proptype, DWORD propid, const gchar text[]); @@ -81,9 +114,12 @@ sanitize_filename (const gchar *filename) } } -void -org_gnome_format_tnef (gpointer ep, - EMFormatHookTarget *t) +static GSList * +empe_tnef_attachment_parse (EMailParserExtension *extension, + EMailParser *parser, + CamelMimePart *part, + GString *part_id, + GCancellable *cancellable) { gchar *tmpdir, *name; CamelStream *out; @@ -92,32 +128,32 @@ org_gnome_format_tnef (gpointer ep, CamelMultipart *mp; CamelMimePart *mainpart; CamelDataWrapper *content; - const EMFormatHandler *handler; gint len; TNEFStruct tnef; + GSList *parts; tmpdir = e_mkdtemp("tnef-attachment-XXXXXX"); if (tmpdir == NULL) - return; + return NULL; name = g_build_filename(tmpdir, ".evo-attachment.tnef", NULL); out = camel_stream_fs_new_with_name (name, O_RDWR | O_CREAT, 0666, NULL); if (out == NULL) { g_free (name); - return; + return NULL; } - content = camel_medium_get_content ((CamelMedium *) t->part); + content = camel_medium_get_content ((CamelMedium *) part); if (content == NULL) { g_free (name); g_object_unref (out); - return; + return NULL; } if (camel_data_wrapper_decode_to_stream_sync (content, out, NULL, NULL) == -1 || camel_stream_close (out, NULL, NULL) == -1) { g_object_unref (out); g_free (name); - return; + return NULL; } g_object_unref (out); @@ -136,7 +172,7 @@ org_gnome_format_tnef (gpointer ep, if (dir == NULL) { g_object_unref (out); g_free (name); - return; + return NULL; } mainpart = camel_mime_part_new (); @@ -173,7 +209,7 @@ org_gnome_format_tnef (gpointer ep, camel_medium_set_content ((CamelMedium *) part, content); g_object_unref (content); - type = em_format_snoop_type (part); + type = e_mail_part_snoop_type (part); if (type) camel_data_wrapper_set_mime_type ((CamelDataWrapper *) part, type); @@ -187,42 +223,98 @@ org_gnome_format_tnef (gpointer ep, closedir (dir); - len = t->part_id->len; - g_string_append_printf(t->part_id, ".tnef"); + len = part_id->len; + g_string_append_printf(part_id, ".tnef"); + parts = NULL; if (camel_multipart_get_number (mp) > 0) { - handler = em_format_find_handler (t->format, "multiplart/mixed"); - /* FIXME Not passing a GCancellable here. */ - if (handler && handler->parse_func) { - CamelMimePart *part = camel_mime_part_new (); - camel_medium_set_content ((CamelMedium *) part, - CAMEL_DATA_WRAPPER (mp)); - handler->parse_func (t->format, part, t->part_id, t->info, NULL); - g_object_unref (part); - } + + CamelMimePart *part = camel_mime_part_new (); + + camel_medium_set_content ((CamelMedium *) part, + CAMEL_DATA_WRAPPER (mp)); + + parts = e_mail_parser_parse_part_as (parser, part, + part_id, "multipart/mixed", cancellable); + + g_object_unref (part); } - g_string_truncate (t->part_id, len); + g_string_truncate (part_id, len); + + if (parts) { + parts = e_mail_parser_wrap_as_attachment (parser, + part, parts, part_id, cancellable); + } g_object_unref (mp); g_object_unref (mainpart); g_free (name); g_free (tmpdir); + + return parts; +} + +static const gchar ** +empe_mime_types (EMailExtension *extension) +{ + return parser_mime_types; +} + +void +e_mail_parser_tnef_attachment_type_register (GTypeModule *type_module) +{ + e_mail_parser_tnef_attachment_register_type (type_module); +} + +static void +e_mail_parser_mail_extension_interface_init (EMailExtensionInterface *iface) +{ + iface->mime_types = empe_mime_types; +} + +static void +e_mail_parser_parser_extension_interface_init (EMailParserExtensionInterface *iface) +{ + iface->parse = empe_tnef_attachment_parse; } -gint e_plugin_lib_enable (EPlugin *ep, gint enable); +static void +e_mail_parser_tnef_attachment_constructed (GObject *object) +{ + EExtensible *extensible; + EMailExtensionRegistry *reg; + + extensible = e_extension_get_extensible (E_EXTENSION (object)); + reg = E_MAIL_EXTENSION_REGISTRY (extensible); -gint -e_plugin_lib_enable (EPlugin *ep, - gint enable) + e_mail_extension_registry_add_extension (reg, E_MAIL_EXTENSION (object)); +} + +static void +e_mail_parser_tnef_attachment_class_init (EMailParserTnefAttachmentClass *klass) { - if (loaded) - return 0; + GObjectClass *object_class; + EExtensionClass *extension_class; - loaded = TRUE; + e_mail_parser_tnef_attachment_parent_class = g_type_class_peek_parent (klass); - return 0; + object_class = G_OBJECT_CLASS (klass); + object_class->constructed = e_mail_parser_tnef_attachment_constructed; + + extension_class = E_EXTENSION_CLASS (klass); + extension_class->extensible_type = E_TYPE_MAIL_PARSER_EXTENSION_REGISTRY; +} + +void +e_mail_parser_tnef_attachment_class_finalize (EMailParserTnefAttachmentClass *klass) +{ +} + +static void +e_mail_parser_tnef_attachment_init (EMailParserTnefAttachment *parser) +{ } void @@ -421,7 +513,7 @@ saveVCard (TNEFStruct *tnef, return; absfilename = g_strconcat (file, ".vcard", NULL); } else - absfilename = g_strdup ("unknown.vcard"); + absfilename = g_strdup ("unknown.vcard"); } else { file = sanitize_filename (vl->data); if (!file) @@ -1352,4 +1444,3 @@ void printRtf (FILE *fptr, variableLength *vl) { } fprintf(fptr, "\n"); } - diff --git a/modules/tnef-attachment/e-mail-parser-tnef-attachment.h b/modules/tnef-attachment/e-mail-parser-tnef-attachment.h new file mode 100644 index 0000000000..360c66ad9a --- /dev/null +++ b/modules/tnef-attachment/e-mail-parser-tnef-attachment.h @@ -0,0 +1,30 @@ +/* + * e-mail-parser-tnef-attachment.h + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see <http://www.gnu.org/licenses/> + * + */ + +#ifndef E_MAIL_PARSER_TNEF_ATTACHMENT_H +#define E_MAIL_PARSER_TNEF_ATTACHMENT_H + +#include <glib-object.h> + +G_BEGIN_DECLS + +void e_mail_parser_tnef_attachment_type_register (GTypeModule *type_module); + +G_END_DECLS + +#endif /* E_MAIL_PARSER_TNEF_ATTACHMENT_H */ diff --git a/modules/tnef-attachment/evolution-module-tnef-attachment.c b/modules/tnef-attachment/evolution-module-tnef-attachment.c new file mode 100644 index 0000000000..df31b97a13 --- /dev/null +++ b/modules/tnef-attachment/evolution-module-tnef-attachment.c @@ -0,0 +1,51 @@ +/* + * evolution-module-tnef-attachment.c + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see <http://www.gnu.org/licenses/> + * + */ + +#include "e-mail-parser-tnef-attachment.h" + +#include <gmodule.h> + +void e_module_load (GTypeModule *type_module); +void e_module_unload (GTypeModule *type_module); +const gchar * g_module_check_init (GModule *module); + +G_MODULE_EXPORT void +e_module_load (GTypeModule *type_module) +{ + /* Register dynamically loaded types. */ + + e_mail_parser_tnef_attachment_type_register (type_module); +} + +G_MODULE_EXPORT void +e_module_unload (GTypeModule *type_module) +{ +} + +G_MODULE_EXPORT const gchar * +g_module_check_init (GModule *module) +{ + /* FIXME Until mail is split into a module library and a + * reusable shared library, prevent the module from + * being unloaded. Unloading the module resets all + * static variables, which screws up foo_get_type() + * functions among other things. */ + g_module_make_resident (module); + + return NULL; +} diff --git a/modules/vcard-inline/Makefile.am b/modules/vcard-inline/Makefile.am new file mode 100644 index 0000000000..fc0b610000 --- /dev/null +++ b/modules/vcard-inline/Makefile.am @@ -0,0 +1,32 @@ +module_LTLIBRARIES = module-vcard-inline.la + +module_vcard_inline_la_CPPFLAGS = \ + $(AM_CPPFLAGS) \ + -I$(top_srcdir) \ + -I$(top_srcdir)/widgets \ + -DEVOLUTION_PRIVDATADIR=\""$(privdatadir)"\" \ + -DG_LOG_DOMAIN=\"evolution-module-vcard-inline\" \ + $(EVOLUTION_DATA_SERVER_CFLAGS) \ + $(GNOME_PLATFORM_CFLAGS) + +module_vcard_inline_la_SOURCES = \ + e-mail-formatter-vcard-inline.c \ + e-mail-formatter-vcard-inline.h \ + e-mail-parser-vcard-inline.c \ + e-mail-parser-vcard-inline.h \ + evolution-module-vcard-inline.c + +module_vcard_inline_la_LIBADD = \ + $(top_builddir)/mail/libevolution-mail.la \ + $(top_builddir)/em-format/libemformat.la \ + $(top_builddir)/addressbook/util/libeabutil.la \ + $(top_builddir)/addressbook/gui/widgets/libeabwidgets.la \ + $(top_builddir)/addressbook/gui/merging/libeabbookmerging.la \ + $(top_builddir)/addressbook/printing/libecontactprint.la \ + $(EVOLUTION_DATA_SERVER_LIBS) \ + $(GNOME_PLATFORM_LIBS) + +module_vcard_inline_la_LDFLAGS = \ + -avoid-version -module $(NO_UNDEFINED) + +-include $(top_srcdir)/git.mk diff --git a/modules/vcard-inline/e-mail-formatter-vcard-inline.c b/modules/vcard-inline/e-mail-formatter-vcard-inline.c new file mode 100644 index 0000000000..25cdacb116 --- /dev/null +++ b/modules/vcard-inline/e-mail-formatter-vcard-inline.c @@ -0,0 +1,249 @@ +/* + * e-mail-formatter-vcard-inline.c + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see <http://www.gnu.org/licenses/> + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "e-mail-formatter-vcard-inline.h" +#include "e-mail-part-vcard-inline.h" + +#include <glib/gi18n-lib.h> + +#include <libebackend/libebackend.h> + +#include <em-format/e-mail-formatter-extension.h> +#include <em-format/e-mail-formatter.h> +#include <em-format/e-mail-part-utils.h> + +#include <camel/camel.h> + +#define d(x) + +typedef struct _EMailFormatterVCardInline { + EExtension parent; +} EMailFormatterVCardInline; + +typedef struct _EMailFormatterVCardInlineClass { + EExtensionClass parent_class; +} EMailFormatterVCardInlineClass; + +GType e_mail_formatter_vcard_inline_get_type (void); +static void e_mail_formatter_formatter_extension_interface_init (EMailFormatterExtensionInterface *iface); +static void e_mail_formatter_mail_extension_interface_init (EMailExtensionInterface *iface); + +G_DEFINE_DYNAMIC_TYPE_EXTENDED ( + EMailFormatterVCardInline, + e_mail_formatter_vcard_inline, + E_TYPE_EXTENSION, + 0, + G_IMPLEMENT_INTERFACE_DYNAMIC ( + E_TYPE_MAIL_EXTENSION, + e_mail_formatter_mail_extension_interface_init) + G_IMPLEMENT_INTERFACE_DYNAMIC ( + E_TYPE_MAIL_FORMATTER_EXTENSION, + e_mail_formatter_formatter_extension_interface_init)); + +static const gchar* formatter_mime_types[] = { "text/vcard", "text/x-vcard", + "text/directory", NULL }; + +static gboolean +emfe_vcard_inline_format (EMailFormatterExtension *extension, + EMailFormatter *formatter, + EMailFormatterContext *context, + EMailPart *part, + CamelStream *stream, + GCancellable *cancellable) +{ + EMailPartVCardInline *vcard_part; + + g_return_val_if_fail (E_MAIL_PART_IS (part, EMailPartVCardInline), FALSE); + vcard_part = (EMailPartVCardInline *) part; + + if (context->mode == E_MAIL_FORMATTER_MODE_RAW) { + + EContact *contact; + + if (vcard_part->contact_list != NULL) + contact = E_CONTACT (vcard_part->contact_list->data); + else + contact = NULL; + + eab_contact_formatter_format_contact_sync ( + vcard_part->formatter, contact, stream, cancellable); + + } else { + gchar *str, *uri; + gint length; + const gchar *label = NULL; + EABContactDisplayMode mode; + const gchar *info = NULL; + + length = g_slist_length (vcard_part->contact_list); + if (length < 1) + return FALSE; + + if (!vcard_part->message_uid && context->message_uid) + vcard_part->message_uid = g_strdup (context->message_uid); + + if (!vcard_part->folder && context->folder) + vcard_part->folder = g_object_ref (context->folder); + + uri = e_mail_part_build_uri ( + context->folder, context->message_uid, + "part_id", G_TYPE_STRING, part->id, + "mode", G_TYPE_INT, E_MAIL_FORMATTER_MODE_RAW, + NULL); + + mode = eab_contact_formatter_get_display_mode (vcard_part->formatter); + if (mode == EAB_CONTACT_DISPLAY_RENDER_COMPACT) { + mode = EAB_CONTACT_DISPLAY_RENDER_NORMAL; + label =_("Show Full vCard"); + } else { + mode = EAB_CONTACT_DISPLAY_RENDER_COMPACT; + label = _("Show Compact vCard"); + } + + str = g_strdup_printf ( + "<div id=\"%s\">" + "<button type=\"button\" " + "name=\"set-display-mode\" " + "class=\"org-gnome-vcard-inline-display-mode-button\" " + "value=\"%d\">%s</button>" + "<button type=\"button\" " + "name=\"save-to-addressbook\" " + "class=\"org-gnome-vcard-inline-save-button\" " + "value=\"%s\">%s</button><br/>" + "<iframe width=\"100%%\" height=\"auto\" frameborder=\"0\"" + "src=\"%s\" name=\"%s\"></iframe>" + "</div>", + part->id, + mode, label, + part->id, _("Save To Addressbook"), + uri, part->id); + + camel_stream_write_string (stream, str, cancellable, NULL); + + g_free (str); + + if (length == 2) { + + info = _("There is one other contact."); + + } else if (length > 2) { + + /* Translators: This will always be two or more. */ + info = g_strdup_printf (ngettext ( + "There is %d other contact.", + "There are %d other contacts.", + length - 1), length - 1); + } + + if (info) { + + str = g_strdup_printf ( + "<div class=\"attachment-info\">%s</div>", + info); + + camel_stream_write_string (stream, str, cancellable, NULL); + + g_free (str); + } + + g_free (uri); + } + + return TRUE; +} + +static const gchar * +emfe_vcard_inline_get_display_name (EMailFormatterExtension *extension) +{ + return _("Addressbok Contact"); +} + +static const gchar * +emfe_vcard_inline_get_description (EMailFormatterExtension *extension) +{ + return _("Display the part as an addressbook contact"); +} + +static const gchar ** +emfe_vcard_inline_mime_types (EMailExtension *extension) +{ + return formatter_mime_types; +} + +static void +e_mail_formatter_vcard_inline_constructed (GObject *object) +{ + EExtensible *extensible; + EMailExtensionRegistry *reg; + + extensible = e_extension_get_extensible (E_EXTENSION (object)); + reg = E_MAIL_EXTENSION_REGISTRY (extensible); + + e_mail_extension_registry_add_extension (reg, E_MAIL_EXTENSION (object)); +} + +static void +e_mail_formatter_vcard_inline_class_init (EMailFormatterVCardInlineClass *klass) +{ + GObjectClass *object_class; + EExtensionClass *extension_class; + + e_mail_formatter_vcard_inline_parent_class = g_type_class_peek_parent (klass); + + object_class = G_OBJECT_CLASS (klass); + object_class->constructed = e_mail_formatter_vcard_inline_constructed; + + extension_class = E_EXTENSION_CLASS (klass); + extension_class->extensible_type = E_TYPE_MAIL_FORMATTER_EXTENSION_REGISTRY; +} + +static void +e_mail_formatter_formatter_extension_interface_init (EMailFormatterExtensionInterface *iface) +{ + iface->format = emfe_vcard_inline_format; + iface->get_display_name = emfe_vcard_inline_get_display_name; + iface->get_description = emfe_vcard_inline_get_description; +} + +static void +e_mail_formatter_mail_extension_interface_init (EMailExtensionInterface *iface) +{ + iface->mime_types = emfe_vcard_inline_mime_types; +} + +static void +e_mail_formatter_vcard_inline_init (EMailFormatterVCardInline *formatter) +{ + +} + +void +e_mail_formatter_vcard_inline_type_register (GTypeModule *type_module) +{ + e_mail_formatter_vcard_inline_register_type (type_module); +} + +static void +e_mail_formatter_vcard_inline_class_finalize (EMailFormatterVCardInlineClass *klass) +{ + +} diff --git a/modules/vcard-inline/e-mail-formatter-vcard-inline.h b/modules/vcard-inline/e-mail-formatter-vcard-inline.h new file mode 100644 index 0000000000..1dcec839f3 --- /dev/null +++ b/modules/vcard-inline/e-mail-formatter-vcard-inline.h @@ -0,0 +1,30 @@ +/* + * e-mail-formatter-vcard-inline.h + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see <http://www.gnu.org/licenses/> + * + */ + +#ifndef E_MAIL_FORMATTER_VCARD_INLINE_H +#define E_MAIL_FORMATTER_VCARD_INLINE_H + +#include <glib-object.h> + +G_BEGIN_DECLS + +void e_mail_formatter_vcard_inline_type_register (GTypeModule *type_module); + +G_END_DECLS + +#endif /* E_MAIL_FORMATTER_VCARD_INLINE_H */ diff --git a/modules/vcard-inline/e-mail-parser-vcard-inline.c b/modules/vcard-inline/e-mail-parser-vcard-inline.c new file mode 100644 index 0000000000..562ca75c72 --- /dev/null +++ b/modules/vcard-inline/e-mail-parser-vcard-inline.c @@ -0,0 +1,410 @@ +/* + * e-mail-parser-vcard-inline.c + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see <http://www.gnu.org/licenses/> + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <string.h> +#include <gtk/gtk.h> +#include <glib.h> +#include <glib/gi18n.h> +#include <glib/gstdio.h> + +#include "e-mail-parser-vcard-inline.h" +#include "e-mail-part-vcard-inline.h" + +#include <camel/camel.h> + +#include <em-format/e-mail-extension-registry.h> +#include <em-format/e-mail-parser-extension.h> +#include <em-format/e-mail-part.h> +#include <em-format/e-mail-part-utils.h> +#include <em-format/e-mail-formatter.h> + +#include <libebook/libebook.h> +#include <libedataserver/libedataserver.h> +#include <libedataserverui/libedataserverui.h> + +#include <shell/e-shell.h> +#include <addressbook/gui/merging/eab-contact-merging.h> +#include <addressbook/util/eab-book-util.h> + +#include <libebackend/libebackend.h> + +#define d(x) + +typedef struct _EMailParserVCardInline { + EExtension parent; +} EMailParserVCardInline; + +typedef struct _EMailParserVCardInlineClass { + EExtensionClass parent_class; +} EMailParserVCardInlineClass; + +GType e_mail_parser_vcard_inline_get_type (void); +static void e_mail_parser_mail_extension_interface_init (EMailExtensionInterface *iface); +static void e_mail_parser_parser_extension_interface_init (EMailParserExtensionInterface *iface); + +G_DEFINE_DYNAMIC_TYPE_EXTENDED ( + EMailParserVCardInline, + e_mail_parser_vcard_inline, + E_TYPE_EXTENSION, + 0, + G_IMPLEMENT_INTERFACE_DYNAMIC ( + E_TYPE_MAIL_EXTENSION, + e_mail_parser_mail_extension_interface_init) + G_IMPLEMENT_INTERFACE_DYNAMIC ( + E_TYPE_MAIL_PARSER_EXTENSION, + e_mail_parser_parser_extension_interface_init)); + +static const gchar* parser_mime_types[] = { "text/vcard", "text/x-vcard", + "text/directory", NULL }; + +static void +mail_part_vcard_inline_free (EMailPart *mail_part) +{ + EMailPartVCardInline *vi_part = (EMailPartVCardInline *) mail_part; + + g_clear_object (&vi_part->contact_display); + g_clear_object (&vi_part->message_label); + g_clear_object (&vi_part->formatter); + g_clear_object (&vi_part->iframe); + g_clear_object (&vi_part->save_button); + g_clear_object (&vi_part->toggle_button); + g_clear_object (&vi_part->folder); + + if (vi_part->message_uid) { + g_free (vi_part->message_uid); + vi_part->message_uid = NULL; + } +} + +static void +client_loaded_cb (ESource *source, + GAsyncResult *result, + GSList *contact_list) +{ + EShell *shell; + EClient *client = NULL; + EBookClient *book_client; + ESourceRegistry *registry; + GSList *iter; + GError *error = NULL; + + e_client_utils_open_new_finish (source, result, &client, &error); + + if (error != NULL) { + g_warn_if_fail (client == NULL); + g_warning ( + "%s: Failed to open book client: %s", + G_STRFUNC, error->message); + g_error_free (error); + goto exit; + } + + g_return_if_fail (E_IS_BOOK_CLIENT (client)); + + book_client = E_BOOK_CLIENT (client); + + shell = e_shell_get_default (); + registry = e_shell_get_registry (shell); + + for (iter = contact_list; iter != NULL; iter = iter->next) { + EContact *contact; + + contact = E_CONTACT (iter->data); + eab_merging_book_add_contact ( + registry, book_client, contact, NULL, NULL); + } + + g_object_unref (client); + + exit: + e_client_util_free_object_slist (contact_list); +} + +static void +save_vcard_cb (WebKitDOMEventTarget *button, + WebKitDOMEvent *event, + EMailPartVCardInline *vcard_part) +{ + EShell *shell; + ESource *source; + ESourceRegistry *registry; + ESourceSelector *selector; + GSList *contact_list; + const gchar *extension_name; + GtkWidget *dialog; + + shell = e_shell_get_default (); + registry = e_shell_get_registry (shell); + extension_name = E_SOURCE_EXTENSION_ADDRESS_BOOK; + + dialog = e_source_selector_dialog_new (NULL, registry, extension_name); + + selector = e_source_selector_dialog_get_selector ( + E_SOURCE_SELECTOR_DIALOG (dialog)); + + source = e_source_registry_ref_default_address_book (registry); + e_source_selector_set_primary_selection (selector, source); + g_object_unref (source); + + if (gtk_dialog_run (GTK_DIALOG (dialog)) != GTK_RESPONSE_OK) { + gtk_widget_destroy (dialog); + return; + } + + source = e_source_selector_dialog_peek_primary_selection ( + E_SOURCE_SELECTOR_DIALOG (dialog)); + + gtk_widget_destroy (dialog); + + g_return_if_fail (source != NULL); + + contact_list = e_client_util_copy_object_slist (NULL, vcard_part->contact_list); + + e_client_utils_open_new ( + source, E_CLIENT_SOURCE_TYPE_CONTACTS, + FALSE, NULL, (GAsyncReadyCallback) client_loaded_cb, + contact_list); +} + +static void +display_mode_toggle_cb (WebKitDOMEventTarget *button, + WebKitDOMEvent *event, + EMailPartVCardInline *vcard_part) +{ + EABContactDisplayMode mode; + gchar *uri; + + mode = eab_contact_formatter_get_display_mode (vcard_part->formatter); + if (mode == EAB_CONTACT_DISPLAY_RENDER_NORMAL) { + mode = EAB_CONTACT_DISPLAY_RENDER_COMPACT; + + webkit_dom_html_element_set_inner_text ( + WEBKIT_DOM_HTML_ELEMENT (button), + _("Show Full vCard"), NULL); + + } else { + mode = EAB_CONTACT_DISPLAY_RENDER_NORMAL; + + webkit_dom_html_element_set_inner_text ( + WEBKIT_DOM_HTML_ELEMENT (button), + _("Show Compact vCard"), NULL); + } + + eab_contact_formatter_set_display_mode (vcard_part->formatter, mode); + + uri = e_mail_part_build_uri ( + vcard_part->folder, vcard_part->message_uid, + "part_id", G_TYPE_STRING, vcard_part->parent.id, + "mode", G_TYPE_INT, E_MAIL_FORMATTER_MODE_RAW, NULL); + + webkit_dom_html_iframe_element_set_src ( + WEBKIT_DOM_HTML_IFRAME_ELEMENT (vcard_part->iframe), uri); + + g_free (uri); +} + +static void +bind_dom (EMailPartVCardInline *vcard_part, + WebKitDOMElement *attachment) +{ + WebKitDOMNodeList *list; + WebKitDOMElement *iframe, *toggle_button, *save_button; + + /* IFRAME */ + list = webkit_dom_element_get_elements_by_tag_name (attachment, "iframe"); + if (webkit_dom_node_list_get_length (list) != 1) + return; + iframe = WEBKIT_DOM_ELEMENT (webkit_dom_node_list_item (list, 0)); + if (vcard_part->iframe) + g_object_unref (vcard_part->iframe); + vcard_part->iframe = g_object_ref (iframe); + + /* TOGGLE DISPLAY MODE BUTTON */ + list = webkit_dom_element_get_elements_by_class_name ( + attachment, "org-gnome-vcard-inline-display-mode-button"); + if (webkit_dom_node_list_get_length (list) != 1) + return; + toggle_button = WEBKIT_DOM_ELEMENT (webkit_dom_node_list_item (list, 0)); + if (vcard_part->toggle_button) + g_object_unref (vcard_part->toggle_button); + vcard_part->toggle_button = g_object_ref (toggle_button); + + /* SAVE TO ADDRESSBOOK BUTTON */ + list = webkit_dom_element_get_elements_by_class_name ( + attachment, "org-gnome-vcard-inline-save-button"); + if (webkit_dom_node_list_get_length (list) != 1) + return; + save_button = WEBKIT_DOM_ELEMENT (webkit_dom_node_list_item (list, 0)); + if (vcard_part->save_button) + g_object_unref (vcard_part->save_button); + vcard_part->save_button = g_object_ref (save_button); + + webkit_dom_event_target_add_event_listener ( + WEBKIT_DOM_EVENT_TARGET (toggle_button), + "click", G_CALLBACK (display_mode_toggle_cb), + FALSE, vcard_part); + + webkit_dom_event_target_add_event_listener ( + WEBKIT_DOM_EVENT_TARGET (save_button), + "click", G_CALLBACK (save_vcard_cb), + FALSE, vcard_part); + + /* Bind collapse buttons for contact lists. */ + eab_contact_formatter_bind_dom ( + webkit_dom_html_iframe_element_get_content_document ( + WEBKIT_DOM_HTML_IFRAME_ELEMENT (iframe))); +} + +static void +decode_vcard (EMailPartVCardInline *vcard_part, + CamelMimePart *mime_part) +{ + CamelDataWrapper *data_wrapper; + CamelMedium *medium; + CamelStream *stream; + GSList *contact_list; + GByteArray *array; + const gchar *string; + const guint8 padding[2] = {0}; + + array = g_byte_array_new (); + medium = CAMEL_MEDIUM (mime_part); + + /* Stream takes ownership of the byte array. */ + stream = camel_stream_mem_new_with_byte_array (array); + data_wrapper = camel_medium_get_content (medium); + camel_data_wrapper_decode_to_stream_sync ( + data_wrapper, stream, NULL, NULL); + + /* because the result is not NULL-terminated */ + g_byte_array_append (array, padding, 2); + + string = (gchar *) array->data; + contact_list = eab_contact_list_from_string (string); + vcard_part->contact_list = contact_list; + + g_object_unref (mime_part); + g_object_unref (stream); +} + +static GSList * +empe_vcard_inline_parse (EMailParserExtension *extension, + EMailParser *parser, + CamelMimePart *part, + GString *part_id, + GCancellable *cancellable) +{ + EMailPartVCardInline *vcard_part; + gint len; + + len = part_id->len; + g_string_append (part_id, ".org-gnome-vcard-inline-display"); + + vcard_part = (EMailPartVCardInline *) e_mail_part_subclass_new ( + part, part_id->str, sizeof (EMailPartVCardInline), + (GFreeFunc) mail_part_vcard_inline_free); + vcard_part->parent.mime_type = camel_content_type_simple ( + camel_mime_part_get_content_type (part)); + vcard_part->parent.bind_func = (EMailPartDOMBindFunc) bind_dom; + vcard_part->parent.is_attachment = TRUE; + vcard_part->formatter = g_object_new ( + EAB_TYPE_CONTACT_FORMATTER, + "display-mode", EAB_CONTACT_DISPLAY_RENDER_COMPACT, + "render-maps", FALSE, NULL); + g_object_ref (part); + + decode_vcard (vcard_part, part); + + g_string_truncate (part_id, len); + + return e_mail_parser_wrap_as_attachment ( + parser, part, g_slist_append (NULL, vcard_part), + part_id, cancellable); +} + +static guint32 +empe_vcard_inline_get_flags (EMailParserExtension *extension) +{ + return E_MAIL_PARSER_EXTENSION_INLINE_DISPOSITION; +} + +static const gchar ** +empe_mime_types (EMailExtension *extension) +{ + return parser_mime_types; +} + +void +e_mail_parser_vcard_inline_type_register (GTypeModule *type_module) +{ + e_mail_parser_vcard_inline_register_type (type_module); +} + +static void +e_mail_parser_mail_extension_interface_init (EMailExtensionInterface *iface) +{ + iface->mime_types = empe_mime_types; +} + +static void +e_mail_parser_parser_extension_interface_init (EMailParserExtensionInterface *iface) +{ + iface->parse = empe_vcard_inline_parse; + iface->get_flags = empe_vcard_inline_get_flags; +} + +static void +e_mail_parser_vcard_inline_constructed (GObject *object) +{ + EExtensible *extensible; + EMailExtensionRegistry *reg; + + extensible = e_extension_get_extensible (E_EXTENSION (object)); + reg = E_MAIL_EXTENSION_REGISTRY (extensible); + + e_mail_extension_registry_add_extension (reg, E_MAIL_EXTENSION (object)); +} + +static void +e_mail_parser_vcard_inline_class_init (EMailParserVCardInlineClass *klass) +{ + GObjectClass *object_class; + EExtensionClass *extension_class; + + e_mail_parser_vcard_inline_parent_class = g_type_class_peek_parent (klass); + + object_class = G_OBJECT_CLASS (klass); + object_class->constructed = e_mail_parser_vcard_inline_constructed; + + extension_class = E_EXTENSION_CLASS (klass); + extension_class->extensible_type = E_TYPE_MAIL_PARSER_EXTENSION_REGISTRY; +} + +static void +e_mail_parser_vcard_inline_class_finalize (EMailParserVCardInlineClass *klass) +{ + +} + +static void +e_mail_parser_vcard_inline_init (EMailParserVCardInline *self) +{ +} diff --git a/modules/vcard-inline/e-mail-parser-vcard-inline.h b/modules/vcard-inline/e-mail-parser-vcard-inline.h new file mode 100644 index 0000000000..76ec5fe206 --- /dev/null +++ b/modules/vcard-inline/e-mail-parser-vcard-inline.h @@ -0,0 +1,30 @@ +/* + * e-mail-parser-vcard-inline.h + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see <http://www.gnu.org/licenses/> + * + */ + +#ifndef E_MAIL_PARSER_VCARD_INLINE_H +#define E_MAIL_PARSER_VCARD_INLINE_H + +#include <glib-object.h> + +G_BEGIN_DECLS + +void e_mail_parser_vcard_inline_type_register (GTypeModule *type_module); + +G_END_DECLS + +#endif /* E_MAIL_PARSER_VCARD_INLINE_H */ diff --git a/modules/vcard-inline/e-mail-part-vcard-inline.h b/modules/vcard-inline/e-mail-part-vcard-inline.h new file mode 100644 index 0000000000..8272d2f672 --- /dev/null +++ b/modules/vcard-inline/e-mail-part-vcard-inline.h @@ -0,0 +1,50 @@ +/* + * e-mail-part-vcard-inline.h + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see <http://www.gnu.org/licenses/> + * + */ + +#ifndef E_MAIL_PART_VCARD_INLINE_H +#define E_MAIL_PART_VCARD_INLINE_H + +#include <em-format/e-mail-part.h> + +#include <addressbook/gui/widgets/eab-contact-formatter.h> +#include <webkit/webkitdom.h> + +G_BEGIN_DECLS + +typedef struct _EMailPartVCardInline EMailPartVCardInline; + +struct _EMailPartVCardInline { + EMailPart parent; + + GSList *contact_list; + GtkWidget *contact_display; + GtkWidget *message_label; + + EABContactFormatter *formatter; + WebKitDOMElement *iframe; + WebKitDOMElement *toggle_button; + WebKitDOMElement *save_button; + + CamelFolder *folder; + gchar *message_uid; +}; + +G_END_DECLS + +#endif /* E_MAIL_PART_VCARD_INLINE_H */ + diff --git a/modules/vcard-inline/evolution-module-vcard-inline.c b/modules/vcard-inline/evolution-module-vcard-inline.c new file mode 100644 index 0000000000..4e95aba312 --- /dev/null +++ b/modules/vcard-inline/evolution-module-vcard-inline.c @@ -0,0 +1,53 @@ +/* + * evolution-module-vcard-inline.c + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see <http://www.gnu.org/licenses/> + * + */ + +#include "e-mail-formatter-vcard-inline.h" +#include "e-mail-parser-vcard-inline.h" + +#include <gmodule.h> + +void e_module_load (GTypeModule *type_module); +void e_module_unload (GTypeModule *type_module); +const gchar * g_module_check_init (GModule *module); + +G_MODULE_EXPORT void +e_module_load (GTypeModule *type_module) +{ + /* Register dynamically loaded types. */ + + e_mail_formatter_vcard_inline_type_register (type_module); + e_mail_parser_vcard_inline_type_register (type_module); +} + +G_MODULE_EXPORT void +e_module_unload (GTypeModule *type_module) +{ +} + +G_MODULE_EXPORT const gchar * +g_module_check_init (GModule *module) +{ + /* FIXME Until mail is split into a module library and a + * reusable shared library, prevent the module from + * being unloaded. Unloading the module resets all + * static variables, which screws up foo_get_type() + * functions among other things. */ + g_module_make_resident (module); + + return NULL; +} diff --git a/plugins/audio-inline/Makefile.am b/plugins/audio-inline/Makefile.am deleted file mode 100644 index 7afdceec97..0000000000 --- a/plugins/audio-inline/Makefile.am +++ /dev/null @@ -1,39 +0,0 @@ -if OS_WIN32 -NO_UNDEFINED_REQUIRED_LIBS = \ - $(top_builddir)/mail/libevolution-mail.la \ - $(top_builddir)/e-util/libeutil.la \ - $(GNOME_PLATFORM_LIBS) -endif - -@EVO_PLUGIN_RULE@ - -plugin_DATA = org-gnome-audio-inline.eplug - -plugin_LTLIBRARIES = liborg-gnome-audio-inline.la - -liborg_gnome_audio_inline_la_CPPFLAGS = \ - $(AM_CPPFLAGS) \ - -I$(top_srcdir) \ - -I$(top_srcdir)/widgets \ - $(EVOLUTION_DATA_SERVER_CFLAGS) \ - $(GNOME_PLATFORM_CFLAGS) \ - $(GSTREAMER_CFLAGS) - -liborg_gnome_audio_inline_la_SOURCES = audio-inline.c - -liborg_gnome_audio_inline_la_LDFLAGS = -module -avoid-version $(NO_UNDEFINED) - -liborg_gnome_audio_inline_la_LIBADD = \ - $(top_builddir)/mail/libevolution-mail.la \ - $(top_builddir)/e-util/libeutil.la \ - $(top_builddir)/em-format/libemformat.la \ - $(EVOLUTION_DATA_SERVER_LIBS) \ - $(GNOME_PLATFORM_LIBS) \ - $(GSTREAMER_LIBS) - -EXTRA_DIST = org-gnome-audio-inline.eplug.xml - -BUILT_SOURCES = $(plugin_DATA) -CLEANFILES = $(BUILT_SOURCES) - --include $(top_srcdir)/git.mk diff --git a/plugins/audio-inline/audio-inline.c b/plugins/audio-inline/audio-inline.c deleted file mode 100644 index 45238db2eb..0000000000 --- a/plugins/audio-inline/audio-inline.c +++ /dev/null @@ -1,347 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) version 3. - * - * 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with the program; if not, see <http://www.gnu.org/licenses/> - * - * - * Authors: - * Radek Doulik <rodo@ximian.com> - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <gtk/gtk.h> -#include <glib/gstdio.h> -#include "e-util/e-mktemp.h" -#include "mail/em-format-hook.h" -#include "mail/em-format-html.h" -#include "gst/gst.h" - -#define d(x) - -gint e_plugin_lib_enable (EPlugin *ep, gint enable); - -gint -e_plugin_lib_enable (EPlugin *ep, - gint enable) -{ - return 0; -} - -void org_gnome_audio_inline_format (gpointer ep, EMFormatHookTarget *t); - -typedef struct _EMFormatInlineAudioPURI EMFormatInlineAudioPURI; - -struct _EMFormatInlineAudioPURI { - EMFormatPURI puri; - - gchar *filename; - GstElement *playbin; - gulong bus_id; - GstState target_state; - GtkWidget *play_button; - GtkWidget *pause_button; - GtkWidget *stop_button; -}; - -static void -org_gnome_audio_inline_pobject_free (EMFormatPURI *o) -{ - EMFormatInlineAudioPURI *po = (EMFormatInlineAudioPURI *) o; - - d(printf ("audio inline formatter: pobject free\n")); - - if (po->play_button) { - g_object_unref (po->play_button); - po->play_button = NULL; - } - - if (po->pause_button) { - g_object_unref (po->pause_button); - po->pause_button = NULL; - } - - if (po->stop_button) { - g_object_unref (po->stop_button); - po->stop_button = NULL; - } - - if (po->filename) { - g_unlink (po->filename); - g_free (po->filename); - po->filename = NULL; - } - - if (po->bus_id) { - g_source_remove (po->bus_id); - po->bus_id = 0; - } - - if (po->playbin) { - gst_element_set_state (po->playbin, GST_STATE_NULL); - gst_object_unref (po->playbin); - po->playbin = NULL; - } -} - -static void -org_gnome_audio_inline_pause_clicked (GtkWidget *button, - EMFormatPURI *puri) -{ - EMFormatInlineAudioPURI *po = (EMFormatInlineAudioPURI *) puri; - - if (po->playbin) { - /* pause playing */ - gst_element_set_state (po->playbin, GST_STATE_PAUSED); - } -} - -static void -org_gnome_audio_inline_stop_clicked (GtkWidget *button, - EMFormatPURI *puri) -{ - EMFormatInlineAudioPURI *po = (EMFormatInlineAudioPURI *) puri; - - if (po->playbin) { - /* ready to play */ - gst_element_set_state (po->playbin, GST_STATE_READY); - po->target_state = GST_STATE_READY; - } -} - -static void -org_gnome_audio_inline_set_audiosink (GstElement *playbin) -{ - GstElement *audiosink; - - /* now it's time to get the audio sink */ - audiosink = gst_element_factory_make ("gconfaudiosink", "play_audio"); - if (audiosink == NULL) { - audiosink = gst_element_factory_make ("autoaudiosink", "play_audio"); - } - - if (audiosink) { - g_object_set (playbin, "audio-sink", audiosink, NULL); - } -} - -static gboolean -org_gnome_audio_inline_gst_callback (GstBus *bus, - GstMessage *message, - gpointer data) -{ - EMFormatInlineAudioPURI *po = (EMFormatInlineAudioPURI *) data; - GstMessageType msg_type; - - g_return_val_if_fail (po != NULL, TRUE); - g_return_val_if_fail (po->playbin != NULL, TRUE); - - msg_type = GST_MESSAGE_TYPE (message); - - switch (msg_type) { - case GST_MESSAGE_ERROR: - gst_element_set_state (po->playbin, GST_STATE_NULL); - break; - case GST_MESSAGE_EOS: - gst_element_set_state (po->playbin, GST_STATE_READY); - break; - case GST_MESSAGE_STATE_CHANGED: - { - GstState old_state, new_state; - - if (GST_MESSAGE_SRC (message) != GST_OBJECT (po->playbin)) - break; - - gst_message_parse_state_changed (message, &old_state, &new_state, NULL); - - if (old_state == new_state) - break; - - if (po->play_button) - gtk_widget_set_sensitive (po->play_button, new_state <= GST_STATE_PAUSED); - if (po->pause_button) - gtk_widget_set_sensitive (po->pause_button, new_state > GST_STATE_PAUSED); - if (po->stop_button) - gtk_widget_set_sensitive (po->stop_button, new_state >= GST_STATE_PAUSED); - } - - break; - default: - break; - } - - return TRUE; -} - -static void -org_gnome_audio_inline_play_clicked (GtkWidget *button, - EMFormatPURI *puri) -{ - EMFormatInlineAudioPURI *po = (EMFormatInlineAudioPURI *) puri; - GstState cur_state; - - d(printf ("audio inline formatter: play\n")); - - if (!po->filename) { - CamelStream *stream; - CamelDataWrapper *data; - GError *error = NULL; - gint argc = 1; - const gchar *argv [] = { "org_gnome_audio_inline", NULL }; - - /* FIXME this is ugly, we should stream this directly to gstreamer */ - po->filename = e_mktemp ("org-gnome-audio-inline-file-XXXXXX"); - - d(printf ("audio inline formatter: write to temp file %s\n", po->filename)); - - stream = camel_stream_fs_new_with_name (po->filename, O_RDWR | O_CREAT | O_TRUNC, 0600, NULL); - data = camel_medium_get_content (CAMEL_MEDIUM (po->puri.part)); - camel_data_wrapper_decode_to_stream_sync ( - data, stream, NULL, NULL); - camel_stream_flush (stream, NULL, NULL); - g_object_unref (stream); - - d(printf ("audio inline formatter: init gst playbin\n")); - - if (gst_init_check (&argc, (gchar ***) &argv, &error)) { - gchar *uri; - GstBus *bus; - - /* create a disk reader */ - po->playbin = gst_element_factory_make ("playbin", "playbin"); - if (po->playbin == NULL) { - g_printerr ("Failed to create gst_element_factory playbin; check your installation\n"); - return; - - } - - uri = g_filename_to_uri (po->filename, NULL, NULL); - g_object_set (po->playbin, "uri", uri, NULL); - g_free (uri); - org_gnome_audio_inline_set_audiosink (po->playbin); - - bus = gst_element_get_bus (po->playbin); - po->bus_id = gst_bus_add_watch (bus, org_gnome_audio_inline_gst_callback, po); - gst_object_unref (bus); - - } else { - g_printerr ("GStreamer failed to initialize: %s",error ? error->message : ""); - g_error_free (error); - } - } - - gst_element_get_state (po->playbin, &cur_state, NULL, 0); - - if (cur_state >= GST_STATE_PAUSED) { - gst_element_set_state (po->playbin, GST_STATE_READY); - } - - if (po->playbin) { - /* start playing */ - gst_element_set_state (po->playbin, GST_STATE_PLAYING); - } -} - -static GtkWidget * -org_gnome_audio_inline_add_button (GtkWidget *box, - const gchar *stock_icon, - GCallback cb, - gpointer data, - gboolean sensitive) -{ - GtkWidget *button; - - button = gtk_button_new_from_stock (stock_icon); - gtk_widget_set_sensitive (button, sensitive); - g_signal_connect (button, "clicked", cb, data); - - gtk_widget_show (button); - gtk_box_pack_end (GTK_BOX (box), button, TRUE, TRUE, 0); - - return button; -} - -static void -write_button_panel (EMFormat *emf, - EMFormatPURI *puri, - CamelStream *stream, - EMFormatWriterInfo *info, - GCancellable *cancellable) -{ - gchar *str; - - str = g_strdup_printf ( - "<object type=\"application/x-org-gnome-audio-inline-button-panel\" " - "width=\"100%%\" height=\"auto\" data=\"%s\" id=\"%s\"></object>", - puri->uri, puri->uri); - camel_stream_write_string (stream, str, cancellable, NULL); - - g_free (str); -} - -static GtkWidget * -org_gnome_audio_inline_button_panel (EMFormat *emf, - EMFormatPURI *puri, - GCancellable *cancellable) -{ - GtkWidget *box; - EMFormatInlineAudioPURI *po = (EMFormatInlineAudioPURI *) puri; - - /* it is OK to call UI functions here, since we are called from UI thread */ - - box = gtk_hbutton_box_new (); - po->play_button = g_object_ref (org_gnome_audio_inline_add_button (box, GTK_STOCK_MEDIA_PLAY, G_CALLBACK (org_gnome_audio_inline_play_clicked), po, TRUE)); - po->pause_button = g_object_ref (org_gnome_audio_inline_add_button (box, GTK_STOCK_MEDIA_PAUSE, G_CALLBACK (org_gnome_audio_inline_pause_clicked), po, FALSE)); - po->stop_button = g_object_ref (org_gnome_audio_inline_add_button (box, GTK_STOCK_MEDIA_STOP, G_CALLBACK (org_gnome_audio_inline_stop_clicked), po, FALSE)); - - gtk_widget_show (box); - - return box; -} - -void -org_gnome_audio_inline_format (gpointer ep, - EMFormatHookTarget *t) -{ - EMFormatInlineAudioPURI *pobj; - gint len; - - len = t->part_id->len; - g_string_append (t->part_id, ".org-gnome-audio-inline-button-panel"); - - d(printf ("audio inline formatter: format classid %s\n", t->part_id->str)); - - pobj = (EMFormatInlineAudioPURI *) em_format_puri_new ( - t->format, sizeof (EMFormatInlineAudioPURI), - t->part, t->part_id->str); - pobj->puri.widget_func = org_gnome_audio_inline_button_panel; - pobj->puri.write_func = write_button_panel; - pobj->puri.part = g_object_ref (t->part); - pobj->puri.is_attachment = TRUE; - pobj->filename = NULL; - pobj->playbin = NULL; - pobj->play_button = NULL; - pobj->stop_button = NULL; - pobj->pause_button = NULL; - pobj->bus_id = 0; - pobj->puri.free = org_gnome_audio_inline_pobject_free; - pobj->target_state = GST_STATE_NULL; - - em_format_add_puri (t->format, (EMFormatPURI *) pobj); - - g_string_truncate (t->part_id, len); -} diff --git a/plugins/audio-inline/org-gnome-audio-inline.eplug.xml b/plugins/audio-inline/org-gnome-audio-inline.eplug.xml deleted file mode 100644 index 06903e796f..0000000000 --- a/plugins/audio-inline/org-gnome-audio-inline.eplug.xml +++ /dev/null @@ -1,100 +0,0 @@ -<?xml version="1.0"?> -<e-plugin-list> - <e-plugin - type="shlib" - id="org.gnome.evolution.plugin.audioInline" - location="@PLUGINDIR@/liborg-gnome-audio-inline@SOEXT@" - _name="Inline Audio" - system_plugin="true"> - - <author name="Radek Doulík" email="rodo@novell.com"/> - <_description> - Play audio attachments directly in mail messages. - </_description> - - <hook class="org.gnome.evolution.mail.format:1.0"> - <group id="EMFormatHTMLDisplay"> - <item - mime_type="audio/ac3" - format="org_gnome_audio_inline_format" - flags="inline_disposition"/> - <item - mime_type="audio/x-ac3" - format="org_gnome_audio_inline_format" - flags="inline_disposition"/> - <item - mime_type="audio/basic" - format="org_gnome_audio_inline_format" - flags="inline_disposition"/> - <item - mime_type="audio/mpeg" - format="org_gnome_audio_inline_format" - flags="inline_disposition"/> - <item - mime_type="audio/x-mpeg" - format="org_gnome_audio_inline_format" - flags="inline_disposition"/> - <item - mime_type="audio/mpeg3" - format="org_gnome_audio_inline_format" - flags="inline_disposition"/> - <item - mime_type="audio/x-mpeg3" - format="org_gnome_audio_inline_format" - flags="inline_disposition"/> - <item - mime_type="audio/mp3" - format="org_gnome_audio_inline_format" - flags="inline_disposition"/> - <item - mime_type="audio/x-mp3" - format="org_gnome_audio_inline_format" - flags="inline_disposition"/> - <item - mime_type="audio/mp4" - format="org_gnome_audio_inline_format" - flags="inline_disposition"/> - <item - mime_type="audio/flac" - format="org_gnome_audio_inline_format" - flags="inline_disposition"/> - <item - mime_type="audio/x-flac" - format="org_gnome_audio_inline_format" - flags="inline_disposition"/> - <item - mime_type="audio/mod" - format="org_gnome_audio_inline_format" - flags="inline_disposition"/> - <item - mime_type="audio/x-mod" - format="org_gnome_audio_inline_format" - flags="inline_disposition"/> - <item - mime_type="audio/x-wav" - format="org_gnome_audio_inline_format" - flags="inline_disposition"/> - <item - mime_type="audio/microsoft-wav" - format="org_gnome_audio_inline_format" - flags="inline_disposition"/> - <item - mime_type="audio/x-wma" - format="org_gnome_audio_inline_format" - flags="inline_disposition"/> - <item - mime_type="audio/x-ms-wma" - format="org_gnome_audio_inline_format" - flags="inline_disposition"/> - <item - mime_type="application/ogg" - format="org_gnome_audio_inline_format" - flags="inline_disposition"/> - <item mime_type="application/x-ogg" - format="org_gnome_audio_inline_format" - flags="inline_disposition"/> - </group> - </hook> - - </e-plugin> -</e-plugin-list> diff --git a/plugins/itip-formatter/Makefile.am b/plugins/itip-formatter/Makefile.am deleted file mode 100644 index af8f6c8668..0000000000 --- a/plugins/itip-formatter/Makefile.am +++ /dev/null @@ -1,56 +0,0 @@ -NULL = - -@EVO_PLUGIN_RULE@ - -plugin_DATA = org-gnome-itip-formatter.eplug -plugin_LTLIBRARIES = liborg-gnome-itip-formatter.la - -liborg_gnome_itip_formatter_la_CPPFLAGS = \ - $(AM_CPPFLAGS) \ - -I$(top_srcdir) \ - -I$(top_srcdir)/widgets \ - -DEVOLUTION_PRIVDATADIR=\""$(privdatadir)"\" \ - $(EVOLUTION_DATA_SERVER_CFLAGS) \ - $(GNOME_PLATFORM_CFLAGS) \ - $(NULL) - -liborg_gnome_itip_formatter_la_SOURCES = \ - e-conflict-search-selector.c \ - e-conflict-search-selector.h \ - e-source-conflict-search.c \ - e-source-conflict-search.h \ - itip-formatter.c \ - itip-view.c \ - itip-view.h \ - $(NULL) - -liborg_gnome_itip_formatter_la_LDFLAGS = \ - -module -avoid-version $(NO_UNDEFINED) - -liborg_gnome_itip_formatter_la_LIBADD = \ - $(top_builddir)/e-util/libeutil.la \ - $(top_builddir)/calendar/gui/libevolution-calendar.la \ - $(top_builddir)/mail/libevolution-mail.la \ - $(top_builddir)/shell/libeshell.la \ - $(top_builddir)/em-format/libemformat.la \ - $(top_builddir)/widgets/misc/libemiscwidgets.la \ - $(top_builddir)/libemail-utils/libemail-utils.la \ - $(top_builddir)/libemail-engine/libemail-engine.la \ - $(top_builddir)/libevolution-utils/libevolution-utils.la \ - $(EVOLUTION_DATA_SERVER_LIBS) \ - $(GNOME_PLATFORM_LIBS) \ - $(NULL) - -error_DATA = org-gnome-itip-formatter.error -errordir = $(privdatadir)/errors - -BUILT_SOURCES = $(plugin_DATA) $(error_DATA) - -CLEANFILES = $(BUILT_SOURCES) - -EXTRA_DIST = \ - org-gnome-itip-formatter.eplug.xml \ - org-gnome-itip-formatter.error.xml \ - $(NULL) - --include $(top_srcdir)/git.mk diff --git a/plugins/itip-formatter/itip-view.c b/plugins/itip-formatter/itip-view.c deleted file mode 100644 index 16388f7232..0000000000 --- a/plugins/itip-formatter/itip-view.c +++ /dev/null @@ -1,3062 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) version 3. - * - * 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with the program; if not, see <http://www.gnu.org/licenses/> - * - * - * Authors: - * JP Rosevear <jpr@novell.com> - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <string.h> -#include <glib/gi18n.h> -#include <libedataserverui/libedataserverui.h> - -#include <mail/em-format-hook.h> -#include <mail/em-format-html.h> -#include <e-util/e-util.h> -#include <e-util/e-unicode.h> -#include <calendar/gui/itip-utils.h> -#include <webkit/webkitdom.h> - -#include "itip-view.h" - -#define d(x) - -#define MEETING_ICON "stock_new-meeting" - -#define ITIP_VIEW_GET_PRIVATE(obj) \ - (G_TYPE_INSTANCE_GET_PRIVATE \ - ((obj), ITIP_TYPE_VIEW, ItipViewPrivate)) - -G_DEFINE_TYPE (ItipView, itip_view, G_TYPE_OBJECT) - -typedef struct { - ItipViewInfoItemType type; - gchar *message; - - guint id; -} ItipViewInfoItem; - -struct _ItipViewPrivate { - ESourceRegistry *registry; - gulong source_added_id; - gulong source_removed_id; - gchar *extension_name; - - ItipViewMode mode; - ECalClientSourceType type; - - gchar *sender; - gchar *organizer; - gchar *organizer_sentby; - gchar *delegator; - gchar *attendee; - gchar *attendee_sentby; - gchar *proxy; - - gchar *summary; - - gchar *location; - gchar *status; - gchar *comment; - - struct tm *start_tm; - gint start_tm_is_date : 1; - gchar *start_label; - const gchar *start_header; - - struct tm *end_tm; - gint end_tm_is_date : 1; - gchar *end_label; - const gchar *end_header; - - GSList *upper_info_items; - GSList *lower_info_items; - - guint next_info_item_id; - - gchar *description; - - gint buttons_sensitive : 1; - - gboolean is_recur_set; - - gint needs_decline : 1; - - WebKitDOMDocument *dom_document; - ItipPURI *puri; - - gchar *error; -}; - -#define TEXT_ROW_SENDER "text_row_sender" -#define TABLE_ROW_SUMMARY "table_row_summary" -#define TABLE_ROW_LOCATION "table_row_location" -#define TABLE_ROW_START_DATE "table_row_start_time" -#define TABLE_ROW_END_DATE "table_row_end_time" -#define TABLE_ROW_STATUS "table_row_status" -#define TABLE_ROW_COMMENT "table_row_comment" -#define TABLE_ROW_DESCRIPTION "table_row_description" -#define TABLE_ROW_RSVP_COMMENT "table_row_rsvp_comment" -#define TABLE_ROW_ESCB "table_row_escb" -#define TABLE_ROW_BUTTONS "table_row_buttons" -#define TABLE_ROW_ESCB_LABEL "table_row_escb_label" - -#define TABLE_BUTTONS "table_buttons" - -#define SELECT_ESOURCE "select_esource" -#define TEXTAREA_RSVP_COMMENT "textarea_rsvp_comment" - -#define CHECKBOX_RSVP "checkbox_rsvp" -#define CHECKBOX_RECUR "checkbox_recur" -#define CHECKBOX_UPDATE "checkbox_update" -#define CHECKBOX_FREE_TIME "checkbox_free_time" -#define CHECKBOX_KEEP_ALARM "checkbox_keep_alarm" -#define CHECKBOX_INHERIT_ALARM "checkbox_inherit_alarm" - -#define BUTTON_OPEN_CALENDAR "button_open_calendar" -#define BUTTON_DECLINE "button_decline" -#define BUTTON_DECLINE_ALL "button_decline_all" -#define BUTTON_ACCEPT "button_accept" -#define BUTTON_ACCEPT_ALL "button_accept_all" -#define BUTTON_TENTATIVE "button_tentative" -#define BUTTON_TENTATIVE_ALL "button_tentative_all" -#define BUTTON_SEND_INFORMATION "button_send_information" -#define BUTTON_UPDATE "button_update" -#define BUTTON_UPDATE_ATTENDEE_STATUS "button_update_attendee_status" -#define BUTTON_SAVE "button_save" - -#define TABLE_UPPER_ITIP_INFO "table_upper_itip_info" -#define TABLE_LOWER_ITIP_INFO "table_lower_itip_info" - -#define DIV_ITIP_CONTENT "div_itip_content" -#define DIV_ITIP_ERROR "div_itip_error" - -enum { - PROP_0, - PROP_EXTENSION_NAME, - PROP_REGISTRY -}; - -enum { - SOURCE_SELECTED, - RESPONSE, - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL] = { 0 }; - -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, - gboolean is_date, - gchar *buffer, - gint buffer_size) -{ - gchar *format; - struct tm tomorrow_tm, week_tm; - - /* Calculate a normalized "tomorrow" */ - tomorrow_tm = *current_tm; - /* Don't need this if date is in the past. Also, year assumption won't fail. */ - if (date_tm->tm_year >= current_tm->tm_year && tomorrow_tm.tm_mday == time_days_in_month (current_tm->tm_year + 1900, current_tm->tm_mon)) { - tomorrow_tm.tm_mday = 1; - if (tomorrow_tm.tm_mon == 11) { - tomorrow_tm.tm_mon = 1; - tomorrow_tm.tm_year++; - } else { - tomorrow_tm.tm_mon++; - } - } else { - tomorrow_tm.tm_mday++; - } - - /* Calculate a normalized "next seven days" */ - week_tm = *current_tm; - /* Don't need this if date is in the past. Also, year assumption won't fail. */ - if (date_tm->tm_year >= current_tm->tm_year && week_tm.tm_mday + 6 > time_days_in_month (date_tm->tm_year + 1900, date_tm->tm_mon)) { - week_tm.tm_mday = (week_tm.tm_mday + 6) % time_days_in_month (date_tm->tm_year + 1900, date_tm->tm_mon); - if (week_tm.tm_mon == 11) { - week_tm.tm_mon = 1; - week_tm.tm_year++; - } else { - week_tm.tm_mon++; - } - } else { - week_tm.tm_mday += 6; - } - - /* 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 (is_date || (!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 time, - * in 24-hour format, without seconds. */ - format = _("Today %H:%M"); - else - /* strftime format of 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 time, - * in 12-hour format, without seconds. */ - format = _("Today %l:%M %p"); - else - /* strftime format of a time, - * in 12-hour format. */ - format = _("Today %l:%M:%S %p"); - } - - /* Tomorrow */ - } else if (date_tm->tm_mday == tomorrow_tm.tm_mday && - date_tm->tm_mon == tomorrow_tm.tm_mon && - date_tm->tm_year == tomorrow_tm.tm_year) { - if (is_date || (!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 = _("Tomorrow"); - } else if (use_24_hour_format) { - if (!show_zero_seconds && date_tm->tm_sec == 0) - /* strftime format of a time, - * in 24-hour format, without seconds. */ - format = _("Tomorrow %H:%M"); - else - /* strftime format of a time, - * in 24-hour format. */ - format = _("Tomorrow %H:%M:%S"); - } else { - if (!show_zero_seconds && date_tm->tm_sec == 0) - /* strftime format of a time, - * in 12-hour format, without seconds. */ - format = _("Tomorrow %l:%M %p"); - else - /* strftime format of a time, - * in 12-hour format. */ - format = _("Tomorrow %l:%M:%S %p"); - } - - /* Within 6 days */ - } else if ((date_tm->tm_year >= current_tm->tm_year && - date_tm->tm_mon >= current_tm->tm_mon && - date_tm->tm_mday >= current_tm->tm_mday) && - - (date_tm->tm_year < week_tm.tm_year || - - (date_tm->tm_year == week_tm.tm_year && - date_tm->tm_mon < week_tm.tm_mon) || - - (date_tm->tm_year == week_tm.tm_year && - date_tm->tm_mon == week_tm.tm_mon && - date_tm->tm_mday < week_tm.tm_mday))) { - if (is_date || (!show_midnight && date_tm->tm_hour == 0 - && date_tm->tm_min == 0 && date_tm->tm_sec == 0)) { - /* strftime format of a weekday. */ - format = _("%A"); - } else if (use_24_hour_format) { - if (!show_zero_seconds && date_tm->tm_sec == 0) - /* strftime format of a weekday and a - * time, in 24-hour format, without seconds. */ - format = _("%A %H:%M"); - else - /* strftime format of a weekday 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 and a - * time, in 12-hour format, without seconds. */ - format = _("%A %l:%M %p"); - else - /* strftime format of a weekday and a - * time, in 12-hour format. */ - format = _("%A %l:%M:%S %p"); - } - - /* This Year */ - } else if (date_tm->tm_year == current_tm->tm_year) { - if (is_date || (!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 - * without a year. */ - 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 - * without a year and a time, - * in 24-hour format, without seconds. */ - format = _("%A, %B %e %H:%M"); - else - /* strftime format of a weekday, a date without a year - * 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 without a year - * and a time, in 12-hour format, without seconds. */ - format = _("%A, %B %e %l:%M %p"); - else - /* strftime format of a weekday, a date without a year - * and a time, in 12-hour format. */ - format = _("%A, %B %e %l:%M:%S %p"); - } - } else { - if (is_date || (!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 %l:%M %p"); - else - /* strftime format of a weekday, a date and a - * time, in 12-hour format. */ - format = _("%A, %B %e, %Y %l:%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_fix_am_pm (buffer, buffer_size, format, date_tm) == 0) - buffer[0] = '\0'; -} - -static gchar * -dupe_first_bold (const gchar *format, - const gchar *first, - const gchar *second) -{ - gchar *f, *s, *res; - - f = g_markup_printf_escaped ("<b>%s</b>", first ? first : ""); - s = g_markup_escape_text (second ? second : "", -1); - - res = g_strdup_printf (format, f, s); - - g_free (f); - g_free (s); - - return res; -} - -static gchar * -set_calendar_sender_text (ItipView *view) -{ - ItipViewPrivate *priv; - const gchar *organizer, *attendee; - gchar *sender = NULL; - gchar *on_behalf_of = NULL; - - priv = view->priv; - - organizer = priv->organizer ? priv->organizer : _("An unknown person"); - attendee = priv->attendee ? priv->attendee : _("An unknown person"); - - /* The current account ID (i.e. the delegatee) is receiving a copy of the request/response. Here we ask the delegatee to respond/accept on behalf of the delegator. */ - if (priv->organizer && priv->proxy) - on_behalf_of = dupe_first_bold (_("Please respond on behalf of %s"), priv->proxy, NULL); - else if (priv->attendee && priv->proxy) - on_behalf_of = dupe_first_bold (_("Received on behalf of %s"), priv->proxy, NULL); - - switch (priv->mode) { - case ITIP_VIEW_MODE_PUBLISH: - if (priv->organizer_sentby) - sender = dupe_first_bold (_("%s through %s has published the following meeting information:"), organizer, priv->organizer_sentby); - else - sender = dupe_first_bold (_("%s has published the following meeting information:"), organizer, NULL); - break; - case ITIP_VIEW_MODE_REQUEST: - /* FIXME is the delegator stuff handled correctly here? */ - if (priv->delegator) { - sender = dupe_first_bold (_("%s has delegated the following meeting to you:"), priv->delegator, NULL); - } else { - if (priv->organizer_sentby) - sender = dupe_first_bold (_("%s through %s requests your presence at the following meeting:"), organizer, priv->organizer_sentby); - else - sender = dupe_first_bold (_("%s requests your presence at the following meeting:"), organizer, NULL); - } - break; - case ITIP_VIEW_MODE_ADD: - /* FIXME What text for this? */ - if (priv->organizer_sentby) - sender = dupe_first_bold (_("%s through %s wishes to add to an existing meeting:"), organizer, priv->organizer_sentby); - else - sender = dupe_first_bold (_("%s wishes to add to an existing meeting:"), organizer, NULL); - break; - case ITIP_VIEW_MODE_REFRESH: - if (priv->attendee_sentby) - sender = dupe_first_bold (_("%s through %s wishes to receive the latest information for the following meeting:"), attendee, priv->attendee_sentby); - else - sender = dupe_first_bold (_("%s wishes to receive the latest information for the following meeting:"), attendee, NULL); - break; - case ITIP_VIEW_MODE_REPLY: - if (priv->attendee_sentby) - sender = dupe_first_bold (_("%s through %s has sent back the following meeting response:"), attendee, priv->attendee_sentby); - else - sender = dupe_first_bold (_("%s has sent back the following meeting response:"), attendee, NULL); - break; - case ITIP_VIEW_MODE_CANCEL: - if (priv->organizer_sentby) - sender = dupe_first_bold (_("%s through %s has canceled the following meeting:"), organizer, priv->organizer_sentby); - else - sender = dupe_first_bold (_("%s has canceled the following meeting:"), organizer, NULL); - break; - case ITIP_VIEW_MODE_COUNTER: - if (priv->attendee_sentby) - sender = dupe_first_bold (_("%s through %s has proposed the following meeting changes."), attendee, priv->attendee_sentby); - else - sender = dupe_first_bold (_("%s has proposed the following meeting changes:"), attendee, NULL); - break; - case ITIP_VIEW_MODE_DECLINECOUNTER: - if (priv->organizer_sentby) - sender = dupe_first_bold (_("%s through %s has declined the following meeting changes:"), organizer, priv->organizer_sentby); - else - sender = dupe_first_bold (_("%s has declined the following meeting changes:"), organizer, NULL); - break; - default: - break; - } - - if (sender && on_behalf_of) - sender = g_strjoin (NULL, sender, "\n", on_behalf_of, NULL); - - g_free (on_behalf_of); - - return sender; -} - -static gchar * -set_tasklist_sender_text (ItipView *view) -{ - ItipViewPrivate *priv; - const gchar *organizer, *attendee; - gchar *sender = NULL; - gchar *on_behalf_of = NULL; - - priv = view->priv; - - organizer = priv->organizer ? priv->organizer : _("An unknown person"); - attendee = priv->attendee ? priv->attendee : _("An unknown person"); - - /* The current account ID (i.e. the delegatee) is receiving a copy of the request/response. Here we ask the delegatee to respond/accept on behalf of the delegator. */ - if (priv->organizer && priv->proxy) - on_behalf_of = dupe_first_bold (_("Please respond on behalf of %s"), priv->proxy, NULL); - else if (priv->attendee && priv->proxy) - on_behalf_of = dupe_first_bold (_("Received on behalf of %s"), priv->proxy, NULL); - - switch (priv->mode) { - case ITIP_VIEW_MODE_PUBLISH: - if (priv->organizer_sentby) - sender = dupe_first_bold (_("%s through %s has published the following task:"), organizer, priv->organizer_sentby); - else - sender = dupe_first_bold (_("%s has published the following task:"), organizer, NULL); - break; - case ITIP_VIEW_MODE_REQUEST: - /* FIXME is the delegator stuff handled correctly here? */ - if (priv->delegator) { - sender = dupe_first_bold (_("%s requests the assignment of %s to the following task:"), organizer, priv->delegator); - } else { - if (priv->organizer_sentby) - sender = dupe_first_bold (_("%s through %s has assigned you a task:"), organizer, priv->organizer_sentby); - else - sender = dupe_first_bold (_("%s has assigned you a task:"), organizer, NULL); - } - break; - case ITIP_VIEW_MODE_ADD: - /* FIXME What text for this? */ - if (priv->organizer_sentby) - sender = dupe_first_bold (_("%s through %s wishes to add to an existing task:"), organizer, priv->organizer_sentby); - else - sender = dupe_first_bold (_("%s wishes to add to an existing task:"), organizer, NULL); - break; - case ITIP_VIEW_MODE_REFRESH: - if (priv->attendee_sentby) - sender = dupe_first_bold (_("%s through %s wishes to receive the latest information for the following assigned task:"), attendee, priv->attendee_sentby); - else - sender = dupe_first_bold (_("%s wishes to receive the latest information for the following assigned task:"), attendee, NULL); - break; - case ITIP_VIEW_MODE_REPLY: - if (priv->attendee_sentby) - sender = dupe_first_bold (_("%s through %s has sent back the following assigned task response:"), attendee, priv->attendee_sentby); - else - sender = dupe_first_bold (_("%s has sent back the following assigned task response:"), attendee, NULL); - break; - case ITIP_VIEW_MODE_CANCEL: - if (priv->organizer_sentby) - sender = dupe_first_bold (_("%s through %s has canceled the following assigned task:"), organizer, priv->organizer_sentby); - else - sender = dupe_first_bold (_("%s has canceled the following assigned task:"), organizer, NULL); - break; - case ITIP_VIEW_MODE_COUNTER: - if (priv->attendee_sentby) - sender = dupe_first_bold (_("%s through %s has proposed the following task assignment changes:"), attendee, priv->attendee_sentby); - else - sender = dupe_first_bold (_("%s has proposed the following task assignment changes:"), attendee, NULL); - break; - case ITIP_VIEW_MODE_DECLINECOUNTER: - if (priv->organizer_sentby) - sender = dupe_first_bold (_("%s through %s has declined the following assigned task:"), organizer, priv->organizer_sentby); - else - sender = dupe_first_bold (_("%s has declined the following assigned task:"), organizer, NULL); - break; - default: - break; - } - - if (sender && on_behalf_of) - sender = g_strjoin (NULL, sender, "\n", on_behalf_of, NULL); - - g_free (on_behalf_of); - - return sender; -} - -static gchar * -set_journal_sender_text (ItipView *view) -{ - ItipViewPrivate *priv; - const gchar *organizer; - gchar *sender = NULL; - gchar *on_behalf_of = NULL; - - priv = view->priv; - - organizer = priv->organizer ? priv->organizer : _("An unknown person"); - - /* The current account ID (i.e. the delegatee) is receiving a copy of the request/response. Here we ask the delegatee to respond/accept on behalf of the delegator. */ - if (priv->organizer && priv->proxy) - on_behalf_of = dupe_first_bold (_("Please respond on behalf of %s"), priv->proxy, NULL); - else if (priv->attendee && priv->proxy) - on_behalf_of = dupe_first_bold (_("Received on behalf of %s"), priv->proxy, NULL); - - switch (priv->mode) { - case ITIP_VIEW_MODE_PUBLISH: - if (priv->organizer_sentby) - sender = dupe_first_bold (_("%s through %s has published the following memo:"), organizer, priv->organizer_sentby); - else - sender = dupe_first_bold (_("%s has published the following memo:"), organizer, NULL); - break; - case ITIP_VIEW_MODE_ADD: - /* FIXME What text for this? */ - if (priv->organizer_sentby) - sender = dupe_first_bold (_("%s through %s wishes to add to an existing memo:"), organizer, priv->organizer_sentby); - else - sender = dupe_first_bold (_("%s wishes to add to an existing memo:"), organizer, NULL); - break; - case ITIP_VIEW_MODE_CANCEL: - if (priv->organizer_sentby) - sender = dupe_first_bold (_("%s through %s has canceled the following shared memo:"), organizer, priv->organizer_sentby); - else - sender = dupe_first_bold (_("%s has canceled the following shared memo:"), organizer, NULL); - break; - default: - break; - } - - if (sender && on_behalf_of) - sender = g_strjoin (NULL, sender, "\n", on_behalf_of, NULL); - - g_free (on_behalf_of); - - return sender; -} - -static void -set_sender_text (ItipView *view) -{ - ItipViewPrivate *priv; - priv = view->priv; - - switch (priv->type) { - case E_CAL_CLIENT_SOURCE_TYPE_EVENTS: - priv->sender = set_calendar_sender_text (view); - break; - case E_CAL_CLIENT_SOURCE_TYPE_TASKS: - priv->sender = set_tasklist_sender_text (view); - break; - case E_CAL_CLIENT_SOURCE_TYPE_MEMOS: - priv->sender = set_journal_sender_text (view); - break; - default: - priv->sender = NULL; - break; - } - - if (priv->sender && priv->dom_document) { - WebKitDOMElement *div; - - div = webkit_dom_document_get_element_by_id ( - priv->dom_document, TEXT_ROW_SENDER); - webkit_dom_html_element_set_inner_html ( - WEBKIT_DOM_HTML_ELEMENT (div), priv->sender, NULL); - } -} - -static void -update_start_end_times (ItipView *view) -{ - ItipViewPrivate *priv; - WebKitDOMElement *row, *col; - gchar buffer[256]; - time_t now; - struct tm *now_tm; - - priv = view->priv; - - now = time (NULL); - now_tm = localtime (&now); - - if (priv->start_label) - g_free (priv->start_label); - if (priv->end_label) - g_free (priv->end_label); - - #define is_same(_member) (priv->start_tm->_member == priv->end_tm->_member) - if (priv->start_tm && priv->end_tm && priv->start_tm_is_date && priv->end_tm_is_date - && is_same (tm_mday) && is_same (tm_mon) && is_same (tm_year)) { - /* it's an all day event in one particular day */ - format_date_and_time_x (priv->start_tm, now_tm, FALSE, TRUE, FALSE, priv->start_tm_is_date, buffer, 256); - priv->start_label = g_strdup (buffer); - priv->start_header = _("All day:"); - priv->end_header = NULL; - priv->end_label = NULL; - } else { - if (priv->start_tm) { - format_date_and_time_x (priv->start_tm, now_tm, FALSE, TRUE, FALSE, priv->start_tm_is_date, buffer, 256); - priv->start_header = priv->start_tm_is_date ? _("Start day:") : _("Start time:"); - priv->start_label = g_strdup (buffer); - } else { - priv->start_header = NULL; - priv->start_label = NULL; - } - - if (priv->end_tm) { - format_date_and_time_x (priv->end_tm, now_tm, FALSE, TRUE, FALSE, priv->end_tm_is_date, buffer, 256); - priv->end_header = priv->end_tm_is_date ? _("End day:") : _("End time:"); - priv->end_label = g_strdup (buffer); - } else { - priv->end_header = NULL; - priv->end_label = NULL; - } - } - #undef is_same - - if (priv->dom_document) { - row = webkit_dom_document_get_element_by_id ( - priv->dom_document, TABLE_ROW_START_DATE); - if (priv->start_header && priv->start_label) { - webkit_dom_html_element_set_hidden ( - WEBKIT_DOM_HTML_ELEMENT (row), FALSE); - - col = webkit_dom_element_get_first_element_child (row); - webkit_dom_html_element_set_inner_html ( - WEBKIT_DOM_HTML_ELEMENT (col), priv->start_header, NULL); - - col = webkit_dom_element_get_last_element_child (row); - webkit_dom_html_element_set_inner_html ( - WEBKIT_DOM_HTML_ELEMENT (col), priv->start_label, NULL); - } else { - webkit_dom_html_element_set_hidden ( - WEBKIT_DOM_HTML_ELEMENT (row), TRUE); - } - - row = webkit_dom_document_get_element_by_id ( - priv->dom_document, TABLE_ROW_END_DATE); - if (priv->end_header && priv->end_label) { - webkit_dom_html_element_set_hidden ( - WEBKIT_DOM_HTML_ELEMENT (row), FALSE); - - col = webkit_dom_element_get_first_element_child (row); - webkit_dom_html_element_set_inner_html ( - WEBKIT_DOM_HTML_ELEMENT (col), priv->end_header, NULL); - - col = webkit_dom_element_get_last_element_child (row); - webkit_dom_html_element_set_inner_html ( - WEBKIT_DOM_HTML_ELEMENT (col), priv->end_label, NULL); - } else { - webkit_dom_html_element_set_hidden ( - WEBKIT_DOM_HTML_ELEMENT (row), TRUE); - } - } -} - -static void -button_clicked_cb (WebKitDOMElement *element, - WebKitDOMEvent *event, - gpointer data) -{ - ItipViewResponse response; - gchar *responseStr; - - responseStr = webkit_dom_html_button_element_get_value ( - WEBKIT_DOM_HTML_BUTTON_ELEMENT (element)); - - response = atoi (responseStr); - - //d(printf("Clicked btton %d\n", response)); - g_signal_emit (G_OBJECT (data), signals[RESPONSE], 0, response); -} - -static void -rsvp_toggled_cb (WebKitDOMHTMLInputElement *input, - WebKitDOMEvent *event, - gpointer data) -{ - WebKitDOMElement *el; - - ItipView *view = data; - gboolean rsvp; - - rsvp = webkit_dom_html_input_element_get_checked (input); - - el = webkit_dom_document_get_element_by_id ( - view->priv->dom_document, TEXTAREA_RSVP_COMMENT); - webkit_dom_html_text_area_element_set_disabled ( - WEBKIT_DOM_HTML_TEXT_AREA_ELEMENT (el), !rsvp); -} - -static void -recur_toggled_cb (WebKitDOMHTMLInputElement *input, - WebKitDOMEvent *event, - gpointer data) -{ - ItipView *view = data; - - itip_view_set_mode (view, view->priv->mode); -} - -/* - alarm_check_toggled_cb - check1 was changed, so make the second available based on state of the first check. -*/ -static void -alarm_check_toggled_cb (WebKitDOMHTMLInputElement *check1, - WebKitDOMEvent *event, - ItipView *view) -{ - WebKitDOMElement *check2; - gchar *id = webkit_dom_html_element_get_id (WEBKIT_DOM_HTML_ELEMENT (check1)); - - if (g_strcmp0 (id, CHECKBOX_INHERIT_ALARM)) { - check2 = webkit_dom_document_get_element_by_id ( - view->priv->dom_document, CHECKBOX_KEEP_ALARM); - } else { - check2 = webkit_dom_document_get_element_by_id ( - view->priv->dom_document, CHECKBOX_INHERIT_ALARM); - } - - g_free (id); - - webkit_dom_html_input_element_set_disabled ( - WEBKIT_DOM_HTML_INPUT_ELEMENT (check2), - (webkit_dom_html_element_get_hidden ( - WEBKIT_DOM_HTML_ELEMENT (check1)) && - webkit_dom_html_input_element_get_checked (check1))); -} - -static void -source_changed_cb (WebKitDOMElement *select, - WebKitDOMEvent *event, - ItipView *view) -{ - ESource *source; - - source = itip_view_ref_source (view); - - d(printf("Source changed to '%s'\n", e_source_get_display_name (source))); - g_signal_emit (view, signals[SOURCE_SELECTED], 0, source); - - g_object_unref (source); -} - -static gchar * -parse_html_mnemonics (const gchar *label, - gchar **access_key) -{ - const gchar *pos = NULL; - gchar ak = 0; - GString *html_label = NULL; - - pos = strstr (label, "_"); - if (pos != NULL) { - ak = pos[1]; - - /* Convert to uppercase */ - if (ak >= 'a') - ak = ak - 32; - - html_label = g_string_new (""); - g_string_append_len (html_label, label, pos - label); - g_string_append_printf (html_label, "<u>%c</u>", pos[1]); - g_string_append (html_label, &pos[2]); - - if (access_key) { - if (ak) { - *access_key = g_strdup_printf ("%c", ak); - } else { - *access_key = NULL; - } - } - - } else { - html_label = g_string_new (label); - - if (access_key) { - *access_key = NULL; - } - } - - return g_string_free (html_label, FALSE); -} - -static void -append_checkbox_table_row (GString *buffer, - const gchar *name, - const gchar *label) -{ - gchar *access_key, *html_label; - - html_label = parse_html_mnemonics (label, &access_key); - - g_string_append_printf ( - buffer, - "<tr id=\"table_row_%s\" hidden=\"\"><td colspan=\"2\">" - "<input type=\"checkbox\" name=\"%s\" id=\"%s\" value=\"%s\" >" - "<label for=\"%s\" accesskey=\"%s\">%s</label>" - "</td></tr>\n", - name, name, name, name, name, - access_key ? access_key : "", html_label); - - g_free (html_label); - - if (access_key) - g_free (access_key); -} - -static void -append_text_table_row (GString *buffer, - const gchar *id, - const gchar *label, - const gchar *value) -{ - if (label && *label) { - - g_string_append_printf (buffer, - "<tr id=\"%s\" %s><th>%s</th><td>%s</td></tr>\n", - id, (value && *value) ? "" : "hidden=\"\"", label, value); - - } else { - - g_string_append_printf ( - buffer, - "<tr id=\"%s\" hidden=\"\"><td colspan=\"2\"></td></tr>\n", - id); - - } -} - -static void -append_info_item_row (ItipView *view, - const gchar *table_id, - ItipViewInfoItem *item) -{ - WebKitDOMElement *table; - WebKitDOMHTMLElement *row, *cell; - const gchar *icon_name; - gchar *id; - - table = webkit_dom_document_get_element_by_id ( - view->priv->dom_document, table_id); - row = webkit_dom_html_table_element_insert_row ( - WEBKIT_DOM_HTML_TABLE_ELEMENT (table), -1, NULL); - - id = g_strdup_printf ("%s_row_%d", table_id, item->id); - webkit_dom_html_element_set_id (row, id); - g_free (id); - - switch (item->type) { - case ITIP_VIEW_INFO_ITEM_TYPE_INFO: - icon_name = GTK_STOCK_DIALOG_INFO; - break; - case ITIP_VIEW_INFO_ITEM_TYPE_WARNING: - icon_name = GTK_STOCK_DIALOG_WARNING; - break; - case ITIP_VIEW_INFO_ITEM_TYPE_ERROR: - icon_name = GTK_STOCK_DIALOG_ERROR; - break; - case ITIP_VIEW_INFO_ITEM_TYPE_PROGRESS: - icon_name = GTK_STOCK_FIND; - break; - case ITIP_VIEW_INFO_ITEM_TYPE_NONE: - default: - icon_name = NULL; - } - - cell = webkit_dom_html_table_row_element_insert_cell ( - (WebKitDOMHTMLTableRowElement *) row, -1, NULL); - - if (icon_name) { - WebKitDOMElement *image; - gchar *icon_uri; - - image = webkit_dom_document_create_element ( - view->priv->dom_document, "IMG", NULL); - - icon_uri = g_strdup_printf ("gtk-stock://%s", icon_name); - webkit_dom_html_image_element_set_src ( - WEBKIT_DOM_HTML_IMAGE_ELEMENT (image), icon_uri); - g_free (icon_uri); - - webkit_dom_node_append_child ( - WEBKIT_DOM_NODE (cell), - WEBKIT_DOM_NODE (image), - NULL); - } - - cell = webkit_dom_html_table_row_element_insert_cell ( - (WebKitDOMHTMLTableRowElement *) row, -1, NULL); - - webkit_dom_html_element_set_inner_html (cell, item->message, NULL); - - d(printf("Added row %s_row_%d ('%s')\n", table_id, item->id, item->message)); -} - -static void -remove_info_item_row (ItipView *view, - const gchar *table_id, - guint id) -{ - WebKitDOMElement *row; - gchar *row_id; - - row_id = g_strdup_printf ("%s_row_%d", table_id, id); - row = webkit_dom_document_get_element_by_id ( - view->priv->dom_document, row_id); - g_free (row_id); - - webkit_dom_node_remove_child ( - webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (row)), - WEBKIT_DOM_NODE (row), - NULL); - - d(printf("Removed row %s_row_%d\n", table_id, id)); -} - -static void -buttons_table_write_button (GString *buffer, - const gchar *name, - const gchar *label, - const gchar *icon, - ItipViewResponse response) -{ - gchar *access_key, *html_label; - - html_label = parse_html_mnemonics (label, &access_key); - - g_string_append_printf ( - buffer, - "<td><button type=\"button\" name=\"%s\" value=\"%d\" id=\"%s\" accesskey=\"%s\" hidden>" - "<div><img src=\"gtk-stock://%s?size=%d\"> <span>%s</span></div>" - "</button></td>\n", - name, response, name, access_key ? access_key : "" , icon, - GTK_ICON_SIZE_BUTTON, html_label); - - g_free (html_label); - - if (access_key) - g_free (access_key); -} - -static void -append_buttons_table (GString *buffer) -{ - g_string_append (buffer, - "<table class=\"itip buttons\" border=\"0\" " - "id=\"" TABLE_BUTTONS "\" cellspacing=\"6\" " - "cellpadding=\"0\" >" - "<tr id=\"" TABLE_ROW_BUTTONS "\">"); - - /* Everything gets the open button */ - buttons_table_write_button ( - buffer, BUTTON_OPEN_CALENDAR, _("_Open Calendar"), - GTK_STOCK_JUMP_TO, ITIP_VIEW_RESPONSE_OPEN); - buttons_table_write_button ( - buffer, BUTTON_DECLINE_ALL, _("_Decline all"), - GTK_STOCK_CANCEL, ITIP_VIEW_RESPONSE_DECLINE); - buttons_table_write_button ( - buffer, BUTTON_DECLINE, _("_Decline"), - GTK_STOCK_CANCEL, ITIP_VIEW_RESPONSE_DECLINE); - buttons_table_write_button ( - buffer, BUTTON_TENTATIVE_ALL, _("_Tentative all"), - GTK_STOCK_DIALOG_QUESTION, ITIP_VIEW_RESPONSE_TENTATIVE); - buttons_table_write_button ( - buffer, BUTTON_TENTATIVE, _("_Tentative"), - GTK_STOCK_DIALOG_QUESTION, ITIP_VIEW_RESPONSE_TENTATIVE); - buttons_table_write_button ( - buffer, BUTTON_ACCEPT_ALL, _("A_ccept all"), - GTK_STOCK_APPLY, ITIP_VIEW_RESPONSE_ACCEPT); - buttons_table_write_button ( - buffer, BUTTON_ACCEPT, _("A_ccept"), - GTK_STOCK_APPLY, ITIP_VIEW_RESPONSE_ACCEPT); - buttons_table_write_button ( - buffer, BUTTON_SEND_INFORMATION, _("_Send Information"), - GTK_STOCK_REFRESH, ITIP_VIEW_RESPONSE_REFRESH); - buttons_table_write_button ( - buffer, BUTTON_UPDATE_ATTENDEE_STATUS, _("_Update Attendee Status"), - GTK_STOCK_REFRESH, ITIP_VIEW_RESPONSE_UPDATE); - buttons_table_write_button ( - buffer, BUTTON_UPDATE, _("_Update"), - GTK_STOCK_REFRESH, ITIP_VIEW_RESPONSE_CANCEL); - - g_string_append (buffer, "</tr></table>"); -} - -static void -itip_view_rebuild_source_list (ItipView *view) -{ - ESourceRegistry *registry; - WebKitDOMElement *select; - GList *list, *link; - const gchar *extension_name; - - d(printf("Assigning a new source list!\n")); - - if (!view->priv->dom_document) - return; - - registry = itip_view_get_registry (view); - extension_name = itip_view_get_extension_name (view); - - select = webkit_dom_document_get_element_by_id ( - view->priv->dom_document, SELECT_ESOURCE); - - while (webkit_dom_node_has_child_nodes (WEBKIT_DOM_NODE (select))) { - webkit_dom_node_remove_child ( - WEBKIT_DOM_NODE (select), - webkit_dom_node_get_last_child (WEBKIT_DOM_NODE (select)), - NULL); - } - - if (extension_name == NULL) - return; - - list = e_source_registry_list_sources (registry, extension_name); - - for (link = list; link != NULL; link = g_list_next (link)) { - ESource *source = E_SOURCE (link->data); - WebKitDOMElement *option; - - option = webkit_dom_document_create_element ( - view->priv->dom_document, "OPTION", NULL); - webkit_dom_html_option_element_set_value ( - WEBKIT_DOM_HTML_OPTION_ELEMENT (option), - e_source_get_uid (source)); - webkit_dom_html_option_element_set_label ( - WEBKIT_DOM_HTML_OPTION_ELEMENT (option), - e_source_get_display_name (source)); - webkit_dom_html_element_set_inner_html ( - WEBKIT_DOM_HTML_ELEMENT (option), - e_source_get_display_name (source), NULL); - webkit_dom_html_element_set_class_name ( - WEBKIT_DOM_HTML_ELEMENT (option), "calendar"); - - webkit_dom_node_append_child ( - WEBKIT_DOM_NODE (select), - WEBKIT_DOM_NODE (option), - NULL); - } - - g_list_free_full (list, (GDestroyNotify) g_object_unref); - - source_changed_cb (select, NULL, view); -} - -static void -itip_view_source_added_cb (ESourceRegistry *registry, - ESource *source, - ItipView *view) -{ - const gchar *extension_name; - - extension_name = itip_view_get_extension_name (view); - - /* If we don't have an extension name set - * yet then disregard the signal emission. */ - if (extension_name == NULL) - return; - - if (e_source_has_extension (source, extension_name)) - itip_view_rebuild_source_list (view); -} - -static void -itip_view_source_removed_cb (ESourceRegistry *registry, - ESource *source, - ItipView *view) -{ - const gchar *extension_name; - - extension_name = itip_view_get_extension_name (view); - - /* If we don't have an extension name set - * yet then disregard the signal emission. */ - if (extension_name == NULL) - return; - - if (e_source_has_extension (source, extension_name)) - itip_view_rebuild_source_list (view); -} - -static void -itip_view_set_registry (ItipView *view, - ESourceRegistry *registry) -{ - g_return_if_fail (E_IS_SOURCE_REGISTRY (registry)); - g_return_if_fail (view->priv->registry == NULL); - - view->priv->registry = g_object_ref (registry); -} - -static void -itip_view_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) -{ - switch (property_id) { - case PROP_EXTENSION_NAME: - itip_view_set_extension_name ( - ITIP_VIEW (object), - g_value_get_string (value)); - return; - - case PROP_REGISTRY: - itip_view_set_registry ( - ITIP_VIEW (object), - g_value_get_object (value)); - return; - } - - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); -} - -static void -itip_view_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) -{ - switch (property_id) { - case PROP_EXTENSION_NAME: - g_value_set_string ( - value, itip_view_get_extension_name ( - ITIP_VIEW (object))); - return; - - case PROP_REGISTRY: - g_value_set_object ( - value, itip_view_get_registry ( - ITIP_VIEW (object))); - return; - } - - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); -} - -static void -itip_view_dispose (GObject *object) -{ - ItipViewPrivate *priv; - - priv = ITIP_VIEW_GET_PRIVATE (object); - - if (priv->registry != NULL) { - g_signal_handler_disconnect ( - priv->registry, priv->source_added_id); - g_signal_handler_disconnect ( - priv->registry, priv->source_removed_id); - g_object_unref (priv->registry); - priv->registry = NULL; - } - - /* Chain up to parent's dispose() method. */ - G_OBJECT_CLASS (itip_view_parent_class)->dispose (object); -} - -static void -itip_view_finalize (GObject *object) -{ - ItipViewPrivate *priv; - GSList *iter; - - priv = ITIP_VIEW_GET_PRIVATE (object); - - d(printf("Itip view finalized!\n")); - - g_free (priv->extension_name); - g_free (priv->sender); - g_free (priv->organizer); - g_free (priv->organizer_sentby); - g_free (priv->delegator); - g_free (priv->attendee); - g_free (priv->attendee_sentby); - g_free (priv->proxy); - g_free (priv->summary); - g_free (priv->location); - g_free (priv->status); - g_free (priv->comment); - g_free (priv->start_tm); - g_free (priv->start_label); - g_free (priv->end_tm); - g_free (priv->end_label); - g_free (priv->description); - g_free (priv->error); - - for (iter = priv->lower_info_items; iter; iter = iter->next) { - ItipViewInfoItem *item = iter->data; - g_free (item->message); - g_free (item); - } - - g_slist_free (priv->lower_info_items); - - for (iter = priv->upper_info_items; iter; iter = iter->next) { - ItipViewInfoItem *item = iter->data; - g_free (item->message); - g_free (item); - } - - g_slist_free (priv->upper_info_items); - - /* Chain up to parent's finalize() method. */ - G_OBJECT_CLASS (itip_view_parent_class)->finalize (object); -} - -static void -itip_view_constructed (GObject *object) -{ - ItipView *view; - ESourceRegistry *registry; - - view = ITIP_VIEW (object); - registry = itip_view_get_registry (view); - - view->priv->source_added_id = g_signal_connect ( - registry, "source-added", - G_CALLBACK (itip_view_source_added_cb), view); - - view->priv->source_removed_id = g_signal_connect ( - registry, "source-removed", - G_CALLBACK (itip_view_source_removed_cb), view); - - /* Chain up to parent's constructed() method. */ - G_OBJECT_CLASS (itip_view_parent_class)->constructed (object); -} - -static void -itip_view_class_init (ItipViewClass *class) -{ - GObjectClass *object_class; - - g_type_class_add_private (class, sizeof (ItipViewPrivate)); - - object_class = G_OBJECT_CLASS (class); - object_class->set_property = itip_view_set_property; - object_class->get_property = itip_view_get_property; - object_class->dispose = itip_view_dispose; - object_class->finalize = itip_view_finalize; - object_class->constructed = itip_view_constructed; - - g_object_class_install_property ( - object_class, - PROP_REGISTRY, - g_param_spec_string ( - "extension-name", - "Extension Name", - "Show only data sources with this extension", - NULL, - G_PARAM_READWRITE)); - - g_object_class_install_property ( - object_class, - PROP_REGISTRY, - g_param_spec_object ( - "registry", - "Registry", - "Data source registry", - E_TYPE_SOURCE_REGISTRY, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT_ONLY)); - - signals[SOURCE_SELECTED] = g_signal_new ( - "source_selected", - G_TYPE_FROM_CLASS (class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (ItipViewClass, source_selected), - NULL, NULL, - g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, 1, - E_TYPE_SOURCE); - - signals[RESPONSE] = g_signal_new ( - "response", - G_TYPE_FROM_CLASS (class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (ItipViewClass, response), - NULL, NULL, - g_cclosure_marshal_VOID__INT, - G_TYPE_NONE, 1, - G_TYPE_INT); -} - -static void -itip_view_init (ItipView *view) -{ - view->priv = ITIP_VIEW_GET_PRIVATE (view); -} - -ItipView * -itip_view_new (ItipPURI *puri, - ESourceRegistry *registry) -{ - ItipView *view; - - view = g_object_new (ITIP_TYPE_VIEW, "registry", registry, NULL); - view->priv->puri = puri; - - return view; -} - -void -itip_view_write (GString *buffer) -{ - g_string_append (buffer, - "<html>\n" - "<head>\n" - "<title>ITIP</title>\n" - "<link type=\"text/css\" rel=\"stylesheet\" href=\"evo-file://" EVOLUTION_PRIVDATADIR "/theme/webview.css\" />\n" - "</head>\n" - "<body>\n"); - - g_string_append_printf (buffer, - "<img src=\"gtk-stock://%s?size=%d\" class=\"itip icon\" />\n", - MEETING_ICON, GTK_ICON_SIZE_BUTTON); - - g_string_append (buffer, - "<div class=\"itip content\" id=\"" DIV_ITIP_CONTENT "\">\n"); - - /* The first section listing the sender */ - /* FIXME What to do if the send and organizer do not match */ - g_string_append (buffer, - "<div id=\"" TEXT_ROW_SENDER "\" class=\"itip sender\"></div>\n"); - - g_string_append (buffer, "<hr>\n"); - - /* Elementary event information */ - g_string_append (buffer, - "<table class=\"itip table\" border=\"0\" " - "cellspacing=\"5\" cellpadding=\"0\">\n"); - - append_text_table_row (buffer, TABLE_ROW_SUMMARY, NULL, NULL); - append_text_table_row (buffer, TABLE_ROW_LOCATION, _("Location:"), NULL); - append_text_table_row (buffer, TABLE_ROW_START_DATE, _("Start time:"), NULL); - append_text_table_row (buffer, TABLE_ROW_END_DATE, _("End time:"), NULL); - append_text_table_row (buffer, TABLE_ROW_STATUS, _("Status:"), NULL); - append_text_table_row (buffer, TABLE_ROW_COMMENT, _("Comment:"), NULL); - - g_string_append (buffer, "</table>\n"); - - /* Upper Info items */ - g_string_append (buffer, - "<table class=\"itip info\" id=\"" TABLE_UPPER_ITIP_INFO "\" border=\"0\" " - "cellspacing=\"5\" cellpadding=\"0\">"); - - /* Description */ - g_string_append (buffer, - "<div id=\"" TABLE_ROW_DESCRIPTION "\" class=\"itip description\" hidden=\"\"></div>\n"); - - g_string_append (buffer, "<hr>\n"); - - /* Lower Info items */ - g_string_append (buffer, - "<table class=\"itip info\" id=\"" TABLE_LOWER_ITIP_INFO "\" border=\"0\" " - "cellspacing=\"5\" cellpadding=\"0\">"); - - g_string_append (buffer, - "<table class=\"itip table\" border=\"0\" " - "cellspacing=\"5\" cellpadding=\"0\">\n"); - - g_string_append (buffer, - "<tr id=\"" TABLE_ROW_ESCB "\" hidden=\"\""">" - "<th><label id=\"" TABLE_ROW_ESCB_LABEL "\" for=\"" SELECT_ESOURCE "\"></label></th>" - "<td><select name=\"" SELECT_ESOURCE "\" id=\"" SELECT_ESOURCE "\"></select></td>" - "</tr>\n"); - - /* RSVP area */ - append_checkbox_table_row (buffer, CHECKBOX_RSVP, _("Send reply to sender")); - - /* Comments */ - g_string_append_printf (buffer, - "<tr id=\"" TABLE_ROW_RSVP_COMMENT "\" hidden=\"\">" - "<th>%s</th>" - "<td><textarea name=\"" TEXTAREA_RSVP_COMMENT "\" " - "id=\"" TEXTAREA_RSVP_COMMENT "\" " - "rows=\"3\" cols=\"40\" disabled=\"\">" - "</textarea></td>\n" - "</tr>\n", - _("Comment:")); - - /* Updates */ - append_checkbox_table_row (buffer, CHECKBOX_UPDATE, _("Send _updates to attendees")); - - /* The recurrence check button */ - append_checkbox_table_row (buffer, CHECKBOX_RECUR, _("_Apply to all instances")); - append_checkbox_table_row (buffer, CHECKBOX_FREE_TIME, _("Show time as _free")); - append_checkbox_table_row (buffer, CHECKBOX_KEEP_ALARM, _("_Preserve my reminder")); - append_checkbox_table_row (buffer, CHECKBOX_INHERIT_ALARM, _("_Inherit reminder")); - - g_string_append (buffer, "</table>\n"); - - /* Buttons table */ - append_buttons_table (buffer); - - /* <div class="itip content" > */ - g_string_append (buffer, "</div>\n"); - - g_string_append (buffer, "<div class=\"itip error\" id=\"" DIV_ITIP_ERROR "\"></div>"); - - g_string_append (buffer, "</body></html>"); -} - -void -itip_view_write_for_printing (ItipView *view, - GString *buffer) -{ - if (view->priv->error && *view->priv->error) { - g_string_append (buffer, view->priv->error); - return; - } - - g_string_append (buffer, - "<div class=\"itip print_content\" id=\"" DIV_ITIP_CONTENT "\">\n"); - - /* The first section listing the sender */ - /* FIXME What to do if the send and organizer do not match */ - g_string_append_printf (buffer, - "<div id=\"" TEXT_ROW_SENDER "\" class=\"itip sender\">%s</div>\n", - view->priv->sender ? view->priv->sender : ""); - - g_string_append (buffer, "<hr>\n"); - - /* Elementary event information */ - g_string_append (buffer, - "<table class=\"itip table\" border=\"0\" " - "cellspacing=\"5\" cellpadding=\"0\">\n"); - - append_text_table_row ( - buffer, TABLE_ROW_SUMMARY, - NULL, view->priv->summary); - append_text_table_row ( - buffer, TABLE_ROW_LOCATION, - _("Location:"), view->priv->location); - append_text_table_row ( - buffer, TABLE_ROW_START_DATE, - view->priv->start_header, view->priv->start_label); - append_text_table_row ( - buffer, TABLE_ROW_END_DATE, - view->priv->end_header, view->priv->end_label); - append_text_table_row ( - buffer, TABLE_ROW_STATUS, - _("Status:"), view->priv->status); - append_text_table_row ( - buffer, TABLE_ROW_COMMENT, - _("Comment:"), view->priv->comment); - - g_string_append (buffer, "</table>\n"); - - /* Description */ - g_string_append_printf ( - buffer, - "<div id=\"" TABLE_ROW_DESCRIPTION "\" " - "class=\"itip description\" %s>%s</div>\n", - view->priv->description ? "" : "hidden=\"\"", view->priv->description); - - g_string_append (buffer, "</div>"); -} - -void -itip_view_create_dom_bindings (ItipView *view, - WebKitDOMElement *element) -{ - WebKitDOMElement *el; - WebKitDOMDocument *doc; - - doc = webkit_dom_node_get_owner_document (WEBKIT_DOM_NODE (element)); - view->priv->dom_document = doc; - - el = webkit_dom_document_get_element_by_id (doc, CHECKBOX_RECUR); - if (el) { - webkit_dom_event_target_add_event_listener ( - WEBKIT_DOM_EVENT_TARGET (el), "click", - G_CALLBACK (recur_toggled_cb), FALSE, view); - } - - el = webkit_dom_document_get_element_by_id (doc, CHECKBOX_RSVP); - if (el) { - webkit_dom_event_target_add_event_listener ( - WEBKIT_DOM_EVENT_TARGET (el), "click", - G_CALLBACK (rsvp_toggled_cb), FALSE, view); - } - - el = webkit_dom_document_get_element_by_id (doc, CHECKBOX_INHERIT_ALARM); - if (el) { - webkit_dom_event_target_add_event_listener ( - WEBKIT_DOM_EVENT_TARGET (el), "click", - G_CALLBACK (alarm_check_toggled_cb), FALSE, view); - } - - el = webkit_dom_document_get_element_by_id (doc, CHECKBOX_KEEP_ALARM); - if (el) { - webkit_dom_event_target_add_event_listener ( - WEBKIT_DOM_EVENT_TARGET (el), "click", - G_CALLBACK (alarm_check_toggled_cb), FALSE, view); - } - - el = webkit_dom_document_get_element_by_id (doc, BUTTON_OPEN_CALENDAR); - if (el) { - webkit_dom_event_target_add_event_listener ( - WEBKIT_DOM_EVENT_TARGET (el), "click", - G_CALLBACK (button_clicked_cb), FALSE, view); - } - - el = webkit_dom_document_get_element_by_id (doc, BUTTON_ACCEPT); - if (el) { - webkit_dom_event_target_add_event_listener ( - WEBKIT_DOM_EVENT_TARGET (el), "click", - G_CALLBACK (button_clicked_cb), FALSE, view); - } - - el = webkit_dom_document_get_element_by_id (doc, BUTTON_ACCEPT_ALL); - if (el) { - webkit_dom_event_target_add_event_listener ( - WEBKIT_DOM_EVENT_TARGET (el), "click", - G_CALLBACK (button_clicked_cb), FALSE, view); - } - - el = webkit_dom_document_get_element_by_id (doc, BUTTON_TENTATIVE); - if (el) { - webkit_dom_event_target_add_event_listener ( - WEBKIT_DOM_EVENT_TARGET (el), "click", - G_CALLBACK (button_clicked_cb), FALSE, view); - } - - el = webkit_dom_document_get_element_by_id (doc, BUTTON_TENTATIVE_ALL); - if (el) { - webkit_dom_event_target_add_event_listener ( - WEBKIT_DOM_EVENT_TARGET (el), "click", - G_CALLBACK (button_clicked_cb), FALSE, view); - } - - el = webkit_dom_document_get_element_by_id (doc, BUTTON_DECLINE); - if (el) { - webkit_dom_event_target_add_event_listener ( - WEBKIT_DOM_EVENT_TARGET (el), "click", - G_CALLBACK (button_clicked_cb), FALSE, view); - } - - el = webkit_dom_document_get_element_by_id (doc, BUTTON_DECLINE_ALL); - if (el) { - webkit_dom_event_target_add_event_listener ( - WEBKIT_DOM_EVENT_TARGET (el), "click", - G_CALLBACK (button_clicked_cb), FALSE, view); - } - - el = webkit_dom_document_get_element_by_id (doc, BUTTON_UPDATE); - if (el) { - webkit_dom_event_target_add_event_listener ( - WEBKIT_DOM_EVENT_TARGET (el), "click", - G_CALLBACK (button_clicked_cb), FALSE, view); - } - - el = webkit_dom_document_get_element_by_id (doc, BUTTON_UPDATE_ATTENDEE_STATUS); - if (el) { - webkit_dom_event_target_add_event_listener ( - WEBKIT_DOM_EVENT_TARGET (el), "click", - G_CALLBACK (button_clicked_cb), FALSE, view); - } - - el = webkit_dom_document_get_element_by_id (doc, BUTTON_SEND_INFORMATION); - if (el) { - webkit_dom_event_target_add_event_listener ( - WEBKIT_DOM_EVENT_TARGET (el), "click", - G_CALLBACK (button_clicked_cb), FALSE, view); - } - - el = webkit_dom_document_get_element_by_id (doc, SELECT_ESOURCE); - if (el) { - webkit_dom_event_target_add_event_listener ( - WEBKIT_DOM_EVENT_TARGET (el), "change", - G_CALLBACK (source_changed_cb), FALSE, view); - } -} - -ItipPURI * -itip_view_get_puri (ItipView *view) -{ - g_return_val_if_fail (ITIP_IS_VIEW (view), NULL); - - return view->priv->puri; -} - -ESourceRegistry * -itip_view_get_registry (ItipView *view) -{ - g_return_val_if_fail (ITIP_IS_VIEW (view), NULL); - - return view->priv->registry; -} - -const gchar * -itip_view_get_extension_name (ItipView *view) -{ - g_return_val_if_fail (ITIP_IS_VIEW (view), NULL); - - return view->priv->extension_name; -} - -void -itip_view_set_extension_name (ItipView *view, - const gchar *extension_name) -{ - g_return_if_fail (ITIP_IS_VIEW (view)); - - /* Avoid unnecessary rebuilds. */ - if (g_strcmp0 (extension_name, view->priv->extension_name) == 0) - return; - - g_free (view->priv->extension_name); - view->priv->extension_name = g_strdup (extension_name); - - g_object_notify (G_OBJECT (view), "extension-name"); - - itip_view_rebuild_source_list (view); -} - -static void -show_button (ItipView *view, - const gchar *id) -{ - WebKitDOMElement *button; - - button = webkit_dom_document_get_element_by_id ( - view->priv->dom_document, id); - webkit_dom_html_element_set_hidden ( - WEBKIT_DOM_HTML_ELEMENT (button), FALSE); -} - -void -itip_view_set_mode (ItipView *view, - ItipViewMode mode) -{ - WebKitDOMElement *row, *cell; - WebKitDOMElement *button; - - g_return_if_fail (ITIP_IS_VIEW (view)); - - view->priv->mode = mode; - - set_sender_text (view); - - if (!view->priv->dom_document) - return; - - row = webkit_dom_document_get_element_by_id ( - view->priv->dom_document, TABLE_ROW_BUTTONS); - cell = webkit_dom_element_get_first_element_child (row); - do { - button = webkit_dom_element_get_first_element_child (cell); - webkit_dom_html_element_set_hidden ( - WEBKIT_DOM_HTML_ELEMENT (button), TRUE); - } while ((cell = webkit_dom_element_get_next_element_sibling (cell)) != NULL); - - view->priv->is_recur_set = itip_view_get_recur_check_state (view); - - /* Always visible */ - show_button (view, BUTTON_OPEN_CALENDAR); - - switch (mode) { - case ITIP_VIEW_MODE_PUBLISH: - if (view->priv->needs_decline) { - show_button (view, BUTTON_DECLINE); - } - show_button (view, BUTTON_ACCEPT); - break; - case ITIP_VIEW_MODE_REQUEST: - show_button (view, view->priv->is_recur_set ? BUTTON_DECLINE_ALL : BUTTON_DECLINE); - show_button (view, view->priv->is_recur_set ? BUTTON_TENTATIVE_ALL : BUTTON_TENTATIVE); - show_button (view, view->priv->is_recur_set ? BUTTON_ACCEPT_ALL : BUTTON_ACCEPT); - break; - case ITIP_VIEW_MODE_ADD: - if (view->priv->type != E_CAL_CLIENT_SOURCE_TYPE_MEMOS) { - show_button (view, BUTTON_DECLINE); - show_button (view, BUTTON_TENTATIVE); - } - show_button (view, BUTTON_ACCEPT); - break; - case ITIP_VIEW_MODE_REFRESH: - show_button (view, BUTTON_SEND_INFORMATION); - break; - case ITIP_VIEW_MODE_REPLY: - show_button (view, BUTTON_UPDATE_ATTENDEE_STATUS); - break; - case ITIP_VIEW_MODE_CANCEL: - show_button (view, BUTTON_UPDATE); - break; - case ITIP_VIEW_MODE_COUNTER: - case ITIP_VIEW_MODE_DECLINECOUNTER: - show_button (view, BUTTON_DECLINE); - show_button (view, BUTTON_TENTATIVE); - show_button (view, BUTTON_ACCEPT); - break; - default: - break; - } -} - -ItipViewMode -itip_view_get_mode (ItipView *view) -{ - g_return_val_if_fail (ITIP_IS_VIEW (view), ITIP_VIEW_MODE_NONE); - - return view->priv->mode; -} - -void -itip_view_set_item_type (ItipView *view, - ECalClientSourceType type) -{ - WebKitDOMElement *label; - const gchar *header; - gchar *access_key, *html_label; - - g_return_if_fail (ITIP_IS_VIEW (view)); - - view->priv->type = type; - - if (!view->priv->dom_document) - return; - - label = webkit_dom_document_get_element_by_id ( - view->priv->dom_document, TABLE_ROW_ESCB_LABEL); - - switch (view->priv->type) { - case E_CAL_CLIENT_SOURCE_TYPE_EVENTS: - header = _("_Calendar:"); - break; - case E_CAL_CLIENT_SOURCE_TYPE_TASKS: - header = _("_Tasks:"); - break; - case E_CAL_CLIENT_SOURCE_TYPE_MEMOS: - header = _("_Memos:"); - break; - default: - header = NULL; - break; - } - - if (!header) { - set_sender_text (view); - return; - } - - html_label = parse_html_mnemonics (header, &access_key); - - webkit_dom_html_element_set_access_key ( - WEBKIT_DOM_HTML_ELEMENT (label), access_key); - webkit_dom_html_element_set_inner_html ( - WEBKIT_DOM_HTML_ELEMENT (label), html_label, NULL); - - g_free (html_label); - - if (access_key) - g_free (access_key); - - set_sender_text (view); -} - -ECalClientSourceType -itip_view_get_item_type (ItipView *view) -{ - g_return_val_if_fail (ITIP_IS_VIEW (view), ITIP_VIEW_MODE_NONE); - - return view->priv->type; -} - -void -itip_view_set_organizer (ItipView *view, - const gchar *organizer) -{ - g_return_if_fail (ITIP_IS_VIEW (view)); - - if (view->priv->organizer) - g_free (view->priv->organizer); - - view->priv->organizer = e_utf8_ensure_valid (organizer); - - set_sender_text (view); -} - -const gchar * -itip_view_get_organizer (ItipView *view) -{ - g_return_val_if_fail (ITIP_IS_VIEW (view), NULL); - - return view->priv->organizer; -} - -void -itip_view_set_organizer_sentby (ItipView *view, - const gchar *sentby) -{ - g_return_if_fail (ITIP_IS_VIEW (view)); - - if (view->priv->organizer_sentby) - g_free (view->priv->organizer_sentby); - - view->priv->organizer_sentby = e_utf8_ensure_valid (sentby); - - set_sender_text (view); -} - -const gchar * -itip_view_get_organizer_sentby (ItipView *view) -{ - g_return_val_if_fail (ITIP_IS_VIEW (view), NULL); - - return view->priv->organizer_sentby; -} - -void -itip_view_set_attendee (ItipView *view, - const gchar *attendee) -{ - g_return_if_fail (ITIP_IS_VIEW (view)); - - if (view->priv->attendee) - g_free (view->priv->attendee); - - view->priv->attendee = e_utf8_ensure_valid (attendee); - - set_sender_text (view); -} - -const gchar * -itip_view_get_attendee (ItipView *view) -{ - g_return_val_if_fail (ITIP_IS_VIEW (view), NULL); - - return view->priv->attendee; -} - -void -itip_view_set_attendee_sentby (ItipView *view, - const gchar *sentby) -{ - g_return_if_fail (ITIP_IS_VIEW (view)); - - if (view->priv->attendee_sentby) - g_free (view->priv->attendee_sentby); - - view->priv->attendee_sentby = e_utf8_ensure_valid (sentby); - - set_sender_text (view); -} - -const gchar * -itip_view_get_attendee_sentby (ItipView *view) -{ - g_return_val_if_fail (ITIP_IS_VIEW (view), NULL); - - return view->priv->attendee_sentby; -} - -void -itip_view_set_proxy (ItipView *view, - const gchar *proxy) -{ - g_return_if_fail (ITIP_IS_VIEW (view)); - - if (view->priv->proxy) - g_free (view->priv->proxy); - - view->priv->proxy = e_utf8_ensure_valid (proxy); - - set_sender_text (view); -} - -const gchar * -itip_view_get_proxy (ItipView *view) -{ - g_return_val_if_fail (ITIP_IS_VIEW (view), NULL); - - return view->priv->proxy; -} - -void -itip_view_set_delegator (ItipView *view, - const gchar *delegator) -{ - g_return_if_fail (ITIP_IS_VIEW (view)); - - if (view->priv->delegator) - g_free (view->priv->delegator); - - view->priv->delegator = e_utf8_ensure_valid (delegator); - - set_sender_text (view); -} - -const gchar * -itip_view_get_delegator (ItipView *view) -{ - g_return_val_if_fail (ITIP_IS_VIEW (view), NULL); - - return view->priv->delegator; -} - -void -itip_view_set_summary (ItipView *view, - const gchar *summary) -{ - WebKitDOMElement *row, *col; - - g_return_if_fail (ITIP_IS_VIEW (view)); - - if (view->priv->summary) - g_free (view->priv->summary); - - view->priv->summary = summary ? g_strstrip (e_utf8_ensure_valid (summary)) : NULL; - - if (!view->priv->dom_document) - return; - - row = webkit_dom_document_get_element_by_id ( - view->priv->dom_document, TABLE_ROW_SUMMARY); - webkit_dom_html_element_set_hidden ( - WEBKIT_DOM_HTML_ELEMENT (row), (view->priv->summary == NULL)); - - col = webkit_dom_element_get_last_element_child (row); - webkit_dom_html_element_set_inner_html ( - WEBKIT_DOM_HTML_ELEMENT (col), - view->priv->summary ? view->priv->summary : "", - NULL); -} - -const gchar * -itip_view_get_summary (ItipView *view) -{ - g_return_val_if_fail (ITIP_IS_VIEW (view), NULL); - - return view->priv->summary; -} - -void -itip_view_set_location (ItipView *view, - const gchar *location) -{ - WebKitDOMElement *row, *col; - - g_return_if_fail (ITIP_IS_VIEW (view)); - - if (view->priv->location) - g_free (view->priv->location); - - view->priv->location = location ? g_strstrip (e_utf8_ensure_valid (location)) : NULL; - - if (!view->priv->dom_document) - return; - - row = webkit_dom_document_get_element_by_id ( - view->priv->dom_document, TABLE_ROW_LOCATION); - webkit_dom_html_element_set_hidden ( - WEBKIT_DOM_HTML_ELEMENT (row), (view->priv->location == NULL)); - - col = webkit_dom_element_get_last_element_child (row); - webkit_dom_html_element_set_inner_html ( - WEBKIT_DOM_HTML_ELEMENT (col), - view->priv->location ? view->priv->location : "", - NULL); -} - -const gchar * -itip_view_get_location (ItipView *view) -{ - g_return_val_if_fail (ITIP_IS_VIEW (view), NULL); - - return view->priv->location; -} - -void -itip_view_set_status (ItipView *view, - const gchar *status) -{ - WebKitDOMElement *row, *col; - - g_return_if_fail (ITIP_IS_VIEW (view)); - - if (view->priv->status) - g_free (view->priv->status); - - view->priv->status = status ? g_strstrip (e_utf8_ensure_valid (status)) : NULL; - - if (!view->priv->dom_document) - return; - - row = webkit_dom_document_get_element_by_id ( - view->priv->dom_document, TABLE_ROW_STATUS); - webkit_dom_html_element_set_hidden ( - WEBKIT_DOM_HTML_ELEMENT (row), (view->priv->status == NULL)); - - col = webkit_dom_element_get_last_element_child (row); - webkit_dom_html_element_set_inner_html ( - WEBKIT_DOM_HTML_ELEMENT (col), - view->priv->status ? view->priv->status : "", - NULL); -} - -const gchar * -itip_view_get_status (ItipView *view) -{ - g_return_val_if_fail (ITIP_IS_VIEW (view), NULL); - - return view->priv->status; -} - -void -itip_view_set_comment (ItipView *view, - const gchar *comment) -{ - WebKitDOMElement *row, *col; - - g_return_if_fail (ITIP_IS_VIEW (view)); - - if (view->priv->comment) - g_free (view->priv->comment); - - view->priv->comment = comment ? g_strstrip (e_utf8_ensure_valid (comment)) : NULL; - - if (!view->priv->dom_document) - return; - - row = webkit_dom_document_get_element_by_id ( - view->priv->dom_document, TABLE_ROW_COMMENT); - webkit_dom_html_element_set_hidden ( - WEBKIT_DOM_HTML_ELEMENT (row), (view->priv->comment == NULL)); - - col = webkit_dom_element_get_last_element_child (row); - webkit_dom_html_element_set_inner_html ( - WEBKIT_DOM_HTML_ELEMENT (col), - view->priv->comment ? view->priv->comment : "", - NULL); -} - -const gchar * -itip_view_get_comment (ItipView *view) -{ - g_return_val_if_fail (ITIP_IS_VIEW (view), NULL); - - return view->priv->comment; -} - -void -itip_view_set_description (ItipView *view, - const gchar *description) -{ - WebKitDOMElement *div; - - g_return_if_fail (ITIP_IS_VIEW (view)); - - if (view->priv->description) - g_free (view->priv->description); - - view->priv->description = description ? g_strstrip (e_utf8_ensure_valid (description)) : NULL; - - if (!view->priv->dom_document) - return; - - div = webkit_dom_document_get_element_by_id ( - view->priv->dom_document, TABLE_ROW_DESCRIPTION); - webkit_dom_html_element_set_hidden ( - WEBKIT_DOM_HTML_ELEMENT (div), (view->priv->description == NULL)); - - webkit_dom_html_element_set_inner_html ( - WEBKIT_DOM_HTML_ELEMENT (div), - view->priv->description ? view->priv->description : "", - NULL); -} - -const gchar * -itip_view_get_description (ItipView *view) -{ - g_return_val_if_fail (ITIP_IS_VIEW (view), NULL); - - return view->priv->description; -} - -void -itip_view_set_start (ItipView *view, - struct tm *start, - gboolean is_date) -{ - ItipViewPrivate *priv; - - 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; - } - - priv->start_tm_is_date = is_date && start; - - update_start_end_times (view); -} - -const struct tm * -itip_view_get_start (ItipView *view, - gboolean *is_date) -{ - g_return_val_if_fail (ITIP_IS_VIEW (view), NULL); - - if (is_date) - *is_date = view->priv->start_tm_is_date; - - return view->priv->start_tm; -} - -void -itip_view_set_end (ItipView *view, - struct tm *end, - gboolean is_date) -{ - ItipViewPrivate *priv; - - 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; - } - - priv->end_tm_is_date = is_date && end; - - update_start_end_times (view); -} - -const struct tm * -itip_view_get_end (ItipView *view, - gboolean *is_date) -{ - g_return_val_if_fail (ITIP_IS_VIEW (view), NULL); - - if (is_date) - *is_date = view->priv->end_tm_is_date; - - return view->priv->end_tm; -} - -guint -itip_view_add_upper_info_item (ItipView *view, - ItipViewInfoItemType type, - const gchar *message) -{ - ItipViewPrivate *priv; - ItipViewInfoItem *item; - - g_return_val_if_fail (ITIP_IS_VIEW (view), 0); - - priv = view->priv; - - item = g_new0 (ItipViewInfoItem, 1); - - item->type = type; - item->message = e_utf8_ensure_valid (message); - item->id = priv->next_info_item_id++; - - priv->upper_info_items = g_slist_append (priv->upper_info_items, item); - - if (!view->priv->dom_document) - return item->id; - - append_info_item_row (view, TABLE_UPPER_ITIP_INFO, item); - - return item->id; -} - -guint -itip_view_add_upper_info_item_printf (ItipView *view, - ItipViewInfoItemType type, - const gchar *format, - ...) -{ - va_list args; - gchar *message; - guint id; - - g_return_val_if_fail (ITIP_IS_VIEW (view), 0); - - va_start (args, format); - message = g_strdup_vprintf (format, args); - va_end (args); - - id = itip_view_add_upper_info_item (view, type, message); - g_free (message); - - return id; -} - -void -itip_view_remove_upper_info_item (ItipView *view, - guint id) -{ - ItipViewPrivate *priv; - GSList *l; - - g_return_if_fail (ITIP_IS_VIEW (view)); - - priv = view->priv; - - for (l = priv->upper_info_items; l; l = l->next) { - ItipViewInfoItem *item = l->data; - - if (item->id == id) { - priv->upper_info_items = g_slist_remove (priv->upper_info_items, item); - - g_free (item->message); - g_free (item); - - if (!view->priv->dom_document) - remove_info_item_row (view, TABLE_UPPER_ITIP_INFO, id); - - return; - } - } -} - -void -itip_view_clear_upper_info_items (ItipView *view) -{ - ItipViewPrivate *priv; - GSList *l; - - g_return_if_fail (ITIP_IS_VIEW (view)); - - priv = view->priv; - - for (l = priv->upper_info_items; l; l = l->next) { - ItipViewInfoItem *item = l->data; - - if (view->priv->dom_document) - remove_info_item_row (view, TABLE_UPPER_ITIP_INFO, item->id); - - g_free (item->message); - g_free (item); - } - - g_slist_free (priv->upper_info_items); - priv->upper_info_items = NULL; -} - -guint -itip_view_add_lower_info_item (ItipView *view, - ItipViewInfoItemType type, - const gchar *message) -{ - ItipViewPrivate *priv; - ItipViewInfoItem *item; - - g_return_val_if_fail (ITIP_IS_VIEW (view), 0); - - priv = view->priv; - - item = g_new0 (ItipViewInfoItem, 1); - - item->type = type; - item->message = e_utf8_ensure_valid (message); - item->id = priv->next_info_item_id++; - - priv->lower_info_items = g_slist_append (priv->lower_info_items, item); - - if (!view->priv->dom_document) - return item->id; - - append_info_item_row (view, TABLE_LOWER_ITIP_INFO, item); - - return item->id; -} - -guint -itip_view_add_lower_info_item_printf (ItipView *view, - ItipViewInfoItemType type, - const gchar *format, - ...) -{ - va_list args; - gchar *message; - guint id; - - g_return_val_if_fail (ITIP_IS_VIEW (view), 0); - - va_start (args, format); - message = g_strdup_vprintf (format, args); - va_end (args); - - id = itip_view_add_lower_info_item (view, type, message); - g_free (message); - - return id; -} - -void -itip_view_remove_lower_info_item (ItipView *view, - guint id) -{ - ItipViewPrivate *priv; - GSList *l; - - g_return_if_fail (ITIP_IS_VIEW (view)); - - priv = view->priv; - - for (l = priv->lower_info_items; l; l = l->next) { - ItipViewInfoItem *item = l->data; - - if (item->id == id) { - priv->lower_info_items = g_slist_remove (priv->lower_info_items, item); - - g_free (item->message); - g_free (item); - - if (view->priv->dom_document) - remove_info_item_row (view, TABLE_LOWER_ITIP_INFO, id); - - return; - } - } -} - -void -itip_view_clear_lower_info_items (ItipView *view) -{ - ItipViewPrivate *priv; - GSList *l; - - g_return_if_fail (ITIP_IS_VIEW (view)); - - priv = view->priv; - - for (l = priv->lower_info_items; l; l = l->next) { - ItipViewInfoItem *item = l->data; - - if (view->priv->dom_document) - remove_info_item_row (view, TABLE_LOWER_ITIP_INFO, item->id); - - g_free (item->message); - g_free (item); - } - - g_slist_free (priv->lower_info_items); - priv->lower_info_items = NULL; -} - -void -itip_view_set_source (ItipView *view, - ESource *source) -{ - WebKitDOMElement *select; - WebKitDOMElement *row; - ESource *selected_source; - gulong i, len; - - g_return_if_fail (ITIP_IS_VIEW (view)); - - d(printf("Settings default source '%s'\n", e_source_get_display_name (source))); - - if (!view->priv->dom_document) - return; - - row = webkit_dom_document_get_element_by_id ( - view->priv->dom_document, TABLE_ROW_ESCB); - webkit_dom_html_element_set_hidden ( - WEBKIT_DOM_HTML_ELEMENT (row), (source == NULL)); - if (source == NULL) - return; - - select = webkit_dom_document_get_element_by_id ( - view->priv->dom_document, SELECT_ESOURCE); - - /* <select> does not emit 'change' event when already selected - * <option> is re-selected, but we need to notify itip formatter, - * so that it would make all the buttons sensitive. */ - selected_source = itip_view_ref_source (view); - if (source == selected_source) - source_changed_cb (select, NULL, view); - if (selected_source != NULL) - g_object_unref (selected_source); - - if (webkit_dom_html_select_element_get_disabled ( - WEBKIT_DOM_HTML_SELECT_ELEMENT (select))) { - webkit_dom_html_select_element_set_disabled ( - WEBKIT_DOM_HTML_SELECT_ELEMENT (select), FALSE); - } - - len = webkit_dom_html_select_element_get_length ( - WEBKIT_DOM_HTML_SELECT_ELEMENT (select)); - for (i = 0; i < len; i++) { - - WebKitDOMNode *node; - WebKitDOMHTMLOptionElement *option; - gchar *value; - - node = webkit_dom_html_select_element_item ( - WEBKIT_DOM_HTML_SELECT_ELEMENT (select), i); - option = WEBKIT_DOM_HTML_OPTION_ELEMENT (node); - - value = webkit_dom_html_option_element_get_value (option); - if (g_strcmp0 (value, e_source_get_uid (source)) == 0) { - webkit_dom_html_option_element_set_selected ( - option, TRUE); - - g_free (value); - break; - } - - g_free (value); - } -} - -ESource * -itip_view_ref_source (ItipView *view) -{ - ESourceRegistry *registry; - WebKitDOMElement *select; - gchar *uid; - ESource *source; - gboolean disable = FALSE; - - g_return_val_if_fail (ITIP_IS_VIEW (view), NULL); - - if (!view->priv->dom_document) - return NULL; - - select = webkit_dom_document_get_element_by_id ( - view->priv->dom_document, SELECT_ESOURCE); - if (webkit_dom_html_select_element_get_disabled ( - WEBKIT_DOM_HTML_SELECT_ELEMENT (select))) { - webkit_dom_html_select_element_set_disabled ( - WEBKIT_DOM_HTML_SELECT_ELEMENT (select), FALSE); - disable = TRUE; - } - - uid = webkit_dom_html_select_element_get_value ( - WEBKIT_DOM_HTML_SELECT_ELEMENT (select)); - - registry = itip_view_get_registry (view); - source = e_source_registry_ref_source (registry, uid); - - g_free (uid); - - if (disable) { - webkit_dom_html_select_element_set_disabled ( - WEBKIT_DOM_HTML_SELECT_ELEMENT (select), TRUE); - } - - return source; -} - -void -itip_view_set_rsvp (ItipView *view, - gboolean rsvp) -{ - WebKitDOMElement *el; - - g_return_if_fail (ITIP_IS_VIEW (view)); - - if (!view->priv->dom_document) - return; - - el = webkit_dom_document_get_element_by_id ( - view->priv->dom_document, CHECKBOX_RSVP); - webkit_dom_html_input_element_set_checked ( - WEBKIT_DOM_HTML_INPUT_ELEMENT (el), rsvp); - - el = webkit_dom_document_get_element_by_id ( - view->priv->dom_document, TEXTAREA_RSVP_COMMENT); - webkit_dom_html_text_area_element_set_disabled ( - WEBKIT_DOM_HTML_TEXT_AREA_ELEMENT (el), !rsvp); -} - -gboolean -itip_view_get_rsvp (ItipView *view) -{ - WebKitDOMElement *el; - - g_return_val_if_fail (ITIP_IS_VIEW (view), FALSE); - - if (!view->priv->dom_document) - return FALSE; - - el = webkit_dom_document_get_element_by_id ( - view->priv->dom_document, CHECKBOX_UPDATE); - return webkit_dom_html_input_element_get_checked (WEBKIT_DOM_HTML_INPUT_ELEMENT (el)); -} - -void -itip_view_set_show_rsvp_check (ItipView *view, - gboolean show) -{ - WebKitDOMElement *label; - WebKitDOMElement *el; - - g_return_if_fail (ITIP_IS_VIEW (view)); - - if (!view->priv->dom_document) - return; - - el = webkit_dom_document_get_element_by_id ( - view->priv->dom_document, "table_row_" CHECKBOX_RSVP); - webkit_dom_html_element_set_hidden (WEBKIT_DOM_HTML_ELEMENT (el), !show); - - el = webkit_dom_document_get_element_by_id ( - view->priv->dom_document, CHECKBOX_RSVP); - label = webkit_dom_element_get_next_element_sibling (el); - webkit_dom_html_element_set_hidden (WEBKIT_DOM_HTML_ELEMENT (label), !show); - - if (!show) { - webkit_dom_html_input_element_set_checked ( - WEBKIT_DOM_HTML_INPUT_ELEMENT (el), FALSE); - } - - el = webkit_dom_document_get_element_by_id ( - view->priv->dom_document, TABLE_ROW_RSVP_COMMENT); - webkit_dom_html_element_set_hidden (WEBKIT_DOM_HTML_ELEMENT (el), !show); -} - -gboolean -itip_view_get_show_rsvp_check (ItipView *view) -{ - WebKitDOMElement *el; - - g_return_val_if_fail (ITIP_IS_VIEW (view), FALSE); - - if (!view->priv->dom_document) - return FALSE; - - el = webkit_dom_document_get_element_by_id ( - view->priv->dom_document, CHECKBOX_RSVP); - return !webkit_dom_html_element_get_hidden (WEBKIT_DOM_HTML_ELEMENT (el)); -} - -void -itip_view_set_update (ItipView *view, - gboolean update) -{ - WebKitDOMElement *el; - - g_return_if_fail (ITIP_IS_VIEW (view)); - - if (!view->priv->dom_document) - return; - - el = webkit_dom_document_get_element_by_id ( - view->priv->dom_document, CHECKBOX_UPDATE); - - webkit_dom_html_input_element_set_checked ( - WEBKIT_DOM_HTML_INPUT_ELEMENT (el), update); -} - -gboolean -itip_view_get_update (ItipView *view) -{ - WebKitDOMElement *el; - - g_return_val_if_fail (ITIP_IS_VIEW (view), FALSE); - - if (!view->priv->dom_document) - return FALSE; - - el = webkit_dom_document_get_element_by_id ( - view->priv->dom_document, CHECKBOX_UPDATE); - return webkit_dom_html_input_element_get_checked (WEBKIT_DOM_HTML_INPUT_ELEMENT (el)); -} - -void -itip_view_set_show_update_check (ItipView *view, - gboolean show) -{ - WebKitDOMElement *label; - WebKitDOMElement *el; - - g_return_if_fail (ITIP_IS_VIEW (view)); - - if (!view->priv->dom_document) - return; - - el = webkit_dom_document_get_element_by_id ( - view->priv->dom_document, "table_row_" CHECKBOX_UPDATE); - webkit_dom_html_element_set_hidden (WEBKIT_DOM_HTML_ELEMENT (el), !show); - - el = webkit_dom_document_get_element_by_id ( - view->priv->dom_document, CHECKBOX_UPDATE); - label = webkit_dom_element_get_next_element_sibling (el); - webkit_dom_html_element_set_hidden (WEBKIT_DOM_HTML_ELEMENT (label), !show); - - if (!show) { - webkit_dom_html_input_element_set_checked ( - WEBKIT_DOM_HTML_INPUT_ELEMENT (el), FALSE); - } -} - -gboolean -itip_view_get_show_update_check (ItipView *view) -{ - WebKitDOMElement *el; - - g_return_val_if_fail (ITIP_IS_VIEW (view), FALSE); - - if (!view->priv->dom_document) - return FALSE; - - el = webkit_dom_document_get_element_by_id ( - view->priv->dom_document, CHECKBOX_UPDATE); - return !webkit_dom_html_element_get_hidden (WEBKIT_DOM_HTML_ELEMENT (el)); -} - -void -itip_view_set_rsvp_comment (ItipView *view, - const gchar *comment) -{ - WebKitDOMElement *el; - - g_return_if_fail (ITIP_IS_VIEW (view)); - - if (!view->priv->dom_document) - return; - - el = webkit_dom_document_get_element_by_id ( - view->priv->dom_document, TEXTAREA_RSVP_COMMENT); - webkit_dom_html_element_set_hidden ( - WEBKIT_DOM_HTML_ELEMENT (el), (comment == NULL)); - - if (comment) { - webkit_dom_html_text_area_element_set_value ( - WEBKIT_DOM_HTML_TEXT_AREA_ELEMENT (el), comment); - } -} - -gchar * -itip_view_get_rsvp_comment (ItipView *view) -{ - WebKitDOMElement *el; - - g_return_val_if_fail (ITIP_IS_VIEW (view), NULL); - - if (!view->priv->dom_document) - return NULL; - - el = webkit_dom_document_get_element_by_id ( - view->priv->dom_document, TEXTAREA_RSVP_COMMENT); - - if (webkit_dom_html_element_get_hidden (WEBKIT_DOM_HTML_ELEMENT (el))) { - return NULL; - } - - return webkit_dom_html_text_area_element_get_value ( - WEBKIT_DOM_HTML_TEXT_AREA_ELEMENT (el)); -} - -void -itip_view_set_needs_decline (ItipView *view, - gboolean needs_decline) -{ - g_return_if_fail (ITIP_IS_VIEW (view)); - - view->priv->needs_decline = needs_decline; -} - -void -itip_view_set_buttons_sensitive (ItipView *view, - gboolean sensitive) -{ - WebKitDOMElement *el, *cell; - - g_return_if_fail (ITIP_IS_VIEW (view)); - - d(printf("Settings buttons %s\n", sensitive ? "sensitive" : "insensitive")); - - view->priv->buttons_sensitive = sensitive; - - if (!view->priv->dom_document) - return; - - el = webkit_dom_document_get_element_by_id ( - view->priv->dom_document, CHECKBOX_UPDATE); - webkit_dom_html_input_element_set_disabled ( - WEBKIT_DOM_HTML_INPUT_ELEMENT (el), !sensitive); - - el = webkit_dom_document_get_element_by_id ( - view->priv->dom_document, CHECKBOX_RECUR); - webkit_dom_html_input_element_set_disabled ( - WEBKIT_DOM_HTML_INPUT_ELEMENT (el), !sensitive); - - el = webkit_dom_document_get_element_by_id ( - view->priv->dom_document, CHECKBOX_FREE_TIME); - webkit_dom_html_input_element_set_disabled ( - WEBKIT_DOM_HTML_INPUT_ELEMENT (el), !sensitive); - - el = webkit_dom_document_get_element_by_id ( - view->priv->dom_document, CHECKBOX_KEEP_ALARM); - webkit_dom_html_input_element_set_disabled ( - WEBKIT_DOM_HTML_INPUT_ELEMENT (el), !sensitive); - - el = webkit_dom_document_get_element_by_id ( - view->priv->dom_document, CHECKBOX_INHERIT_ALARM); - webkit_dom_html_input_element_set_disabled ( - WEBKIT_DOM_HTML_INPUT_ELEMENT (el), !sensitive); - - el = webkit_dom_document_get_element_by_id ( - view->priv->dom_document, CHECKBOX_RSVP); - webkit_dom_html_input_element_set_disabled ( - WEBKIT_DOM_HTML_INPUT_ELEMENT (el), !sensitive); - - el = webkit_dom_document_get_element_by_id ( - view->priv->dom_document, TEXTAREA_RSVP_COMMENT); - webkit_dom_html_text_area_element_set_disabled ( - WEBKIT_DOM_HTML_TEXT_AREA_ELEMENT (el), !sensitive); - - el = webkit_dom_document_get_element_by_id ( - view->priv->dom_document, SELECT_ESOURCE); - webkit_dom_html_select_element_set_disabled ( - WEBKIT_DOM_HTML_SELECT_ELEMENT (el), !sensitive); - - el = webkit_dom_document_get_element_by_id ( - view->priv->dom_document, TABLE_ROW_BUTTONS); - cell = webkit_dom_element_get_first_element_child (el); - do { - WebKitDOMElement *btn; - btn = webkit_dom_element_get_first_element_child (cell); - if (!webkit_dom_html_element_get_hidden ( - WEBKIT_DOM_HTML_ELEMENT (btn))) { - webkit_dom_html_button_element_set_disabled ( - WEBKIT_DOM_HTML_BUTTON_ELEMENT (btn), !sensitive); - } - } while ((cell = webkit_dom_element_get_next_element_sibling (cell)) != NULL); -} - -gboolean -itip_view_get_buttons_sensitive (ItipView *view) -{ - g_return_val_if_fail (ITIP_IS_VIEW (view), FALSE); - - return view->priv->buttons_sensitive; -} - -gboolean -itip_view_get_recur_check_state (ItipView *view) -{ - WebKitDOMElement *el; - - g_return_val_if_fail (ITIP_IS_VIEW (view), FALSE); - - if (!view->priv->dom_document) - return FALSE; - - el = webkit_dom_document_get_element_by_id ( - view->priv->dom_document, CHECKBOX_RECUR); - return webkit_dom_html_input_element_get_checked ( - WEBKIT_DOM_HTML_INPUT_ELEMENT (el)); -} - -void -itip_view_set_show_recur_check (ItipView *view, - gboolean show) -{ - WebKitDOMElement *label; - WebKitDOMElement *el; - - g_return_if_fail (ITIP_IS_VIEW (view)); - - if (!view->priv->dom_document) - return; - - el = webkit_dom_document_get_element_by_id ( - view->priv->dom_document, "table_row_" CHECKBOX_RECUR); - webkit_dom_html_element_set_hidden (WEBKIT_DOM_HTML_ELEMENT (el), !show); - - el = webkit_dom_document_get_element_by_id ( - view->priv->dom_document, CHECKBOX_RECUR); - label = webkit_dom_element_get_next_element_sibling (el); - webkit_dom_html_element_set_hidden (WEBKIT_DOM_HTML_ELEMENT (label), !show); - - if (!show) { - webkit_dom_html_input_element_set_checked ( - WEBKIT_DOM_HTML_INPUT_ELEMENT (el), FALSE); - } - - /* and update state of the second check */ - alarm_check_toggled_cb ( - WEBKIT_DOM_HTML_INPUT_ELEMENT (el), - NULL, view); -} - -void -itip_view_set_show_free_time_check (ItipView *view, - gboolean show) -{ - WebKitDOMElement *label; - WebKitDOMElement *el; - - g_return_if_fail (ITIP_IS_VIEW (view)); - - if (!view->priv->dom_document) - return; - - el = webkit_dom_document_get_element_by_id ( - view->priv->dom_document, "table_row_" CHECKBOX_FREE_TIME); - webkit_dom_html_element_set_hidden (WEBKIT_DOM_HTML_ELEMENT (el), !show); - - el = webkit_dom_document_get_element_by_id ( - view->priv->dom_document, CHECKBOX_FREE_TIME); - label = webkit_dom_element_get_next_element_sibling (el); - webkit_dom_html_element_set_hidden (WEBKIT_DOM_HTML_ELEMENT (label), !show); - - if (!show) { - webkit_dom_html_input_element_set_checked ( - WEBKIT_DOM_HTML_INPUT_ELEMENT (el), FALSE); - } - - /* and update state of the second check */ - alarm_check_toggled_cb ( - WEBKIT_DOM_HTML_INPUT_ELEMENT (el), - NULL, view); -} - -gboolean -itip_view_get_free_time_check_state (ItipView *view) -{ - WebKitDOMElement *el; - - g_return_val_if_fail (ITIP_IS_VIEW (view), FALSE); - - if (!view->priv->dom_document) - return FALSE; - - el = webkit_dom_document_get_element_by_id ( - view->priv->dom_document, CHECKBOX_FREE_TIME); - return webkit_dom_html_input_element_get_checked ( - WEBKIT_DOM_HTML_INPUT_ELEMENT (el)); -} - -void -itip_view_set_show_keep_alarm_check (ItipView *view, - gboolean show) -{ - WebKitDOMElement *label; - WebKitDOMElement *el; - - g_return_if_fail (ITIP_IS_VIEW (view)); - - if (!view->priv->dom_document) - return; - - el = webkit_dom_document_get_element_by_id ( - view->priv->dom_document, "table_row_" CHECKBOX_KEEP_ALARM); - webkit_dom_html_element_set_hidden (WEBKIT_DOM_HTML_ELEMENT (el), !show); - - el = webkit_dom_document_get_element_by_id ( - view->priv->dom_document, CHECKBOX_KEEP_ALARM); - label = webkit_dom_element_get_next_element_sibling (el); - webkit_dom_html_element_set_hidden (WEBKIT_DOM_HTML_ELEMENT (label), !show); - - if (!show) { - webkit_dom_html_input_element_set_checked ( - WEBKIT_DOM_HTML_INPUT_ELEMENT (el), FALSE); - } - - /* and update state of the second check */ - alarm_check_toggled_cb ( - WEBKIT_DOM_HTML_INPUT_ELEMENT (el), - NULL, view); -} - -gboolean -itip_view_get_keep_alarm_check_state (ItipView *view) -{ - WebKitDOMElement *el; - - g_return_val_if_fail (ITIP_IS_VIEW (view), FALSE); - - if (!view->priv->dom_document) - return FALSE; - - el = webkit_dom_document_get_element_by_id ( - view->priv->dom_document, CHECKBOX_KEEP_ALARM); - return webkit_dom_html_input_element_get_checked ( - WEBKIT_DOM_HTML_INPUT_ELEMENT (el)); -} - -void -itip_view_set_show_inherit_alarm_check (ItipView *view, - gboolean show) -{ - WebKitDOMElement *label; - WebKitDOMElement *el; - - g_return_if_fail (ITIP_IS_VIEW (view)); - - if (!view->priv->dom_document) - return; - - el = webkit_dom_document_get_element_by_id ( - view->priv->dom_document, "table_row_" CHECKBOX_INHERIT_ALARM); - webkit_dom_html_element_set_hidden (WEBKIT_DOM_HTML_ELEMENT (el), !show); - - el = webkit_dom_document_get_element_by_id ( - view->priv->dom_document, CHECKBOX_INHERIT_ALARM); - label = webkit_dom_element_get_next_element_sibling (el); - webkit_dom_html_element_set_hidden (WEBKIT_DOM_HTML_ELEMENT (label), !show); - - if (!show) { - webkit_dom_html_input_element_set_checked ( - WEBKIT_DOM_HTML_INPUT_ELEMENT (el), FALSE); - } - - /* and update state of the second check */ - alarm_check_toggled_cb ( - WEBKIT_DOM_HTML_INPUT_ELEMENT (el), - NULL, view); -} - -gboolean -itip_view_get_inherit_alarm_check_state (ItipView *view) -{ - WebKitDOMElement *el; - - g_return_val_if_fail (ITIP_IS_VIEW (view), FALSE); - - if (!view->priv->dom_document) - return FALSE; - - el = webkit_dom_document_get_element_by_id ( - view->priv->dom_document, CHECKBOX_INHERIT_ALARM); - return webkit_dom_html_input_element_get_checked ( - WEBKIT_DOM_HTML_INPUT_ELEMENT (el)); -} - -void -itip_view_set_error (ItipView *view, - const gchar *error_html, - gboolean show_save_btn) -{ - WebKitDOMElement *content, *error; - GString *str; - - g_return_if_fail (ITIP_IS_VIEW (view)); - g_return_if_fail (error_html); - - str = g_string_new (error_html); - - if (show_save_btn) { - g_string_append (str, - "<table border=\"0\" width=\"100%\">" - "<tr width=\"100%\" id=\"" TABLE_ROW_BUTTONS "\">"); - - buttons_table_write_button ( - str, BUTTON_SAVE, _("_Save"), - GTK_STOCK_SAVE, ITIP_VIEW_RESPONSE_SAVE); - - g_string_append (str, "</tr></table>"); - } - - view->priv->error = str->str; - g_string_free (str, FALSE); - - if (!view->priv->dom_document) - return; - - content = webkit_dom_document_get_element_by_id ( - view->priv->dom_document, DIV_ITIP_CONTENT); - webkit_dom_html_element_set_hidden ( - WEBKIT_DOM_HTML_ELEMENT (content), TRUE); - - error = webkit_dom_document_get_element_by_id ( - view->priv->dom_document, DIV_ITIP_ERROR); - webkit_dom_html_element_set_hidden ( - WEBKIT_DOM_HTML_ELEMENT (error), FALSE); - - webkit_dom_html_element_set_inner_html ( - WEBKIT_DOM_HTML_ELEMENT (error), view->priv->error, NULL); - - if (show_save_btn) { - WebKitDOMElement *el; - - show_button (view, BUTTON_SAVE); - - el = webkit_dom_document_get_element_by_id ( - view->priv->dom_document, BUTTON_SAVE); - webkit_dom_event_target_add_event_listener ( - WEBKIT_DOM_EVENT_TARGET (el), "click", - G_CALLBACK (button_clicked_cb), FALSE, view); - } -} diff --git a/plugins/itip-formatter/itip-view.h b/plugins/itip-formatter/itip-view.h deleted file mode 100644 index 2e35aec39d..0000000000 --- a/plugins/itip-formatter/itip-view.h +++ /dev/null @@ -1,246 +0,0 @@ -/* - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) version 3. - * - * 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with the program; if not, see <http://www.gnu.org/licenses/> - * - * - * Authors: - * JP Rosevear <jpr@novell.com> - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -#ifndef ITIP_VIEW_H -#define ITIP_VIEW_H - -#include <stdarg.h> -#include <unistd.h> -#include <gtk/gtk.h> -#include <webkit/webkitdom.h> -#include <libecal/libecal.h> - -/* Standard GObject macros */ -#define ITIP_TYPE_VIEW \ - (itip_view_get_type ()) -#define ITIP_VIEW(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST \ - ((obj), ITIP_TYPE_VIEW, ItipView)) -#define ITIP_VIEW_CLASS(cls) \ - (G_TYPE_CHECK_CLASS_CAST \ - ((cls), ITIP_TYPE_VIEW, ItipViewClass)) -#define ITIP_IS_VIEW(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE \ - ((obj), ITIP_TYPE_VIEW)) -#define ITIP_IS_VIEW_CLASS(cls) \ - (G_TYPE_CHECK_CLASS_TYPE \ - ((cls), ITIP_TYPE_VIEW)) -#define ITIP_VIEW_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS \ - ((obj), ITIP_TYPE_VIEW, ItipViewClass)) - -G_BEGIN_DECLS - -typedef struct _ItipView ItipView; -typedef struct _ItipViewClass ItipViewClass; -typedef struct _ItipViewPrivate ItipViewPrivate; -typedef struct _ItipPURI ItipPURI; - -typedef enum { - ITIP_VIEW_MODE_NONE, - ITIP_VIEW_MODE_PUBLISH, - ITIP_VIEW_MODE_REQUEST, - ITIP_VIEW_MODE_COUNTER, - ITIP_VIEW_MODE_DECLINECOUNTER, - ITIP_VIEW_MODE_ADD, - ITIP_VIEW_MODE_REPLY, - ITIP_VIEW_MODE_REFRESH, - ITIP_VIEW_MODE_CANCEL, - ITIP_VIEW_MODE_HIDE_ALL -} 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_CANCEL, - ITIP_VIEW_RESPONSE_REFRESH, - ITIP_VIEW_RESPONSE_OPEN, - ITIP_VIEW_RESPONSE_SAVE -} ItipViewResponse; - -typedef enum { - ITIP_VIEW_INFO_ITEM_TYPE_NONE, - ITIP_VIEW_INFO_ITEM_TYPE_INFO, - ITIP_VIEW_INFO_ITEM_TYPE_WARNING, - ITIP_VIEW_INFO_ITEM_TYPE_ERROR, - ITIP_VIEW_INFO_ITEM_TYPE_PROGRESS -} ItipViewInfoItemType; - -struct _ItipView { - GObject parent; - ItipViewPrivate *priv; -}; - -struct _ItipViewClass { - GObjectClass parent_class; - - void (*source_selected) (ItipView *view, - ESource *selected_source); - void (*response) (ItipView *view, - gint response); -}; - -GType itip_view_get_type (void); -ItipView * itip_view_new (ItipPURI *puri, - ESourceRegistry *registry); -void itip_view_write (GString *buffer); -void itip_view_write_for_printing (ItipView *view, - GString *buffer); -void itip_view_create_dom_bindings (ItipView *view, - WebKitDOMElement *element); -ItipPURI * itip_view_get_puri (ItipView *view); -ESourceRegistry * - itip_view_get_registry (ItipView *view); -const gchar * itip_view_get_extension_name (ItipView *view); -void itip_view_set_extension_name (ItipView *view, - const gchar *extension_name); -ItipViewMode itip_view_get_mode (ItipView *view); -void itip_view_set_mode (ItipView *view, - ItipViewMode mode); -ECalClientSourceType - itip_view_get_item_type (ItipView *view); -void itip_view_set_item_type (ItipView *view, - ECalClientSourceType type); -const gchar * itip_view_get_organizer (ItipView *view); -void itip_view_set_organizer (ItipView *view, - const gchar *organizer); -const gchar * itip_view_get_organizer_sentby (ItipView *view); -void itip_view_set_organizer_sentby (ItipView *view, - const gchar *sentby); -const gchar * itip_view_get_attendee (ItipView *view); -void itip_view_set_attendee (ItipView *view, - const gchar *attendee); -const gchar * itip_view_get_attendee_sentby (ItipView *view); -void itip_view_set_attendee_sentby (ItipView *view, - const gchar *sentby); -const gchar * itip_view_get_delegator (ItipView *view); -void itip_view_set_delegator (ItipView *view, - const gchar *delegator); -const gchar * itip_view_get_proxy (ItipView *view); -void itip_view_set_proxy (ItipView *view, - const gchar *proxy); -const gchar * itip_view_get_summary (ItipView *view); -void itip_view_set_summary (ItipView *view, - const gchar *summary); -const gchar * itip_view_get_location (ItipView *view); -void itip_view_set_location (ItipView *view, - const gchar *location); -const gchar * itip_view_get_status (ItipView *view); -void itip_view_set_status (ItipView *view, - const gchar *status); -const gchar * itip_view_get_comment (ItipView *view); -void itip_view_set_comment (ItipView *view, - const gchar *comment); -const gchar * itip_view_get_description (ItipView *view); -void itip_view_set_description (ItipView *view, - const gchar *description); -const struct tm * - itip_view_get_start (ItipView *view, - gboolean *is_date); -void itip_view_set_start (ItipView *view, - struct tm *start, - gboolean is_date); -const struct tm * - itip_view_get_end (ItipView *view, - gboolean *is_date); -void itip_view_set_end (ItipView *view, - struct tm *end, - gboolean is_date); -guint itip_view_add_upper_info_item (ItipView *view, - ItipViewInfoItemType type, - const gchar *message); -guint itip_view_add_upper_info_item_printf - (ItipView *view, - ItipViewInfoItemType, - const gchar *format, - ...) G_GNUC_PRINTF (3, 4); -void itip_view_remove_upper_info_item - (ItipView *view, - guint id); -void itip_view_clear_upper_info_items - (ItipView *view); -guint itip_view_add_lower_info_item (ItipView *view, - ItipViewInfoItemType type, - const gchar *message); -guint itip_view_add_lower_info_item_printf - (ItipView *view, - ItipViewInfoItemType type, - const gchar *format, - ...) G_GNUC_PRINTF (3, 4); -void itip_view_remove_lower_info_item - (ItipView *view, - guint id); -void itip_view_clear_lower_info_items - (ItipView *view); -ESource * itip_view_ref_source (ItipView *view); -void itip_view_set_source (ItipView *view, - ESource *source); -gboolean itip_view_get_rsvp (ItipView *view); -void itip_view_set_rsvp (ItipView *view, - gboolean rsvp); -gboolean itip_view_get_show_rsvp_check (ItipView *view); -void itip_view_set_show_rsvp_check (ItipView *view, - gboolean show); -gboolean itip_view_get_update (ItipView *view); -void itip_view_set_update (ItipView *view, - gboolean update); -gboolean itip_view_get_show_update_check (ItipView *view); -void itip_view_set_show_update_check (ItipView *view, - gboolean show); -gchar * itip_view_get_rsvp_comment (ItipView *view); -void itip_view_set_rsvp_comment (ItipView *view, - const gchar *comment); -gboolean itip_view_get_buttons_sensitive (ItipView *view); -void itip_view_set_buttons_sensitive (ItipView *view, - gboolean sensitive); -gboolean itip_view_get_recur_check_state (ItipView *view); -void itip_view_set_show_recur_check (ItipView *view, - gboolean show); -void itip_view_set_needs_decline (ItipView *view, - gboolean needs_decline); -gboolean itip_view_get_free_time_check_state - (ItipView *view); -void itip_view_set_show_free_time_check - (ItipView *view, - gboolean show); -gboolean itip_view_get_keep_alarm_check_state - (ItipView *view); -void itip_view_set_show_keep_alarm_check - (ItipView *view, - gboolean show); -gboolean itip_view_get_inherit_alarm_check_state - (ItipView *view); -void itip_view_set_show_inherit_alarm_check - (ItipView *view, - gboolean show); -void itip_view_set_error (ItipView *view, - const gchar *error_html, - gboolean show_save_btn); - -G_END_DECLS - -#endif /* ITIP_VIEW_H */ - diff --git a/plugins/mail-to-task/mail-to-task.c b/plugins/mail-to-task/mail-to-task.c index e74cece640..89ba097611 100644 --- a/plugins/mail-to-task/mail-to-task.c +++ b/plugins/mail-to-task/mail-to-task.c @@ -47,7 +47,6 @@ #include <mail/e-mail-browser.h> #include <mail/em-utils.h> -#include <mail/em-format-html.h> #include <mail/message-list.h> #include <calendar/gui/dialogs/comp-editor.h> diff --git a/plugins/mailing-list-actions/mailing-list-actions.c b/plugins/mailing-list-actions/mailing-list-actions.c index 3b541d0352..b31414276b 100644 --- a/plugins/mailing-list-actions/mailing-list-actions.c +++ b/plugins/mailing-list-actions/mailing-list-actions.c @@ -45,7 +45,6 @@ #include <mail/e-mail-reader.h> #include <mail/em-composer-utils.h> #include <mail/em-config.h> -#include <mail/em-format-hook.h> #include <mail/em-utils.h> #include <mail/message-list.h> diff --git a/plugins/prefer-plain/prefer-plain.c b/plugins/prefer-plain/prefer-plain.c deleted file mode 100644 index 5793370374..0000000000 --- a/plugins/prefer-plain/prefer-plain.c +++ /dev/null @@ -1,392 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) version 3. - * - * 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with the program; if not, see <http://www.gnu.org/licenses/> - * - * - * Authors: - * Michael Zucchi <notzed@novell.com> - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <gtk/gtk.h> -#include <glib/gi18n-lib.h> -#include <string.h> -#include <stdio.h> - -#include <em-format/em-format.h> -#include <mail/em-config.h> -#include <mail/em-format-hook.h> - -void org_gnome_prefer_plain_multipart_alternative (gpointer ep, EMFormatHookTarget *t); -void org_gnome_prefer_plain_text_html (gpointer ep, EMFormatHookTarget *t); -GtkWidget *org_gnome_prefer_plain_config_mode (EPlugin *epl, struct _EConfigHookItemFactoryData *data); - -enum { - EPP_NORMAL, - EPP_PREFER, - EPP_TEXT -}; - -static GSettings *epp_settings = NULL; -static gint epp_mode = -1; -static gboolean epp_show_suppressed = TRUE; - -static void -make_part_attachment (EMFormat *format, - CamelMimePart *part, - GString *part_id, - gboolean force_html, - GCancellable *cancellable) -{ - EMFormatParserInfo info = {0}; - - if (camel_content_type_is (camel_mime_part_get_content_type (part), "text", "html")) { - /* always show HTML as attachments and not inline */ - camel_mime_part_set_disposition (part, "attachment"); - - if (!camel_mime_part_get_filename (part)) { - gchar *str = g_strdup_printf ("%s.html", _("attachment")); - camel_mime_part_set_filename (part, str); - g_free (str); - } - - em_format_parse_part_as ( - format, part, part_id, &info, "application/octet-stream", cancellable); - } else if (force_html && CAMEL_IS_MIME_MESSAGE (part)) { - /* message was asked to be formatted as text/html; - * might be for cases where message itself is a text/html part */ - CamelMimePart *new_part; - CamelDataWrapper *content; - - content = camel_medium_get_content (CAMEL_MEDIUM (part)); - g_return_if_fail (content != NULL); - - new_part = camel_mime_part_new (); - camel_medium_set_content (CAMEL_MEDIUM (new_part), content); - - em_format_parse_part (format, new_part, part_id, &info, cancellable); - - g_object_unref (new_part); - } else { - em_format_parse_part (format, part, part_id, &info, cancellable); - } -} - -void -org_gnome_prefer_plain_text_html (gpointer ep, - EMFormatHookTarget *t) -{ - /* In text-only mode, all html output is suppressed for the first processing */ - if (epp_mode != EPP_TEXT - || strstr (t->part_id->str, ".alternative-prefer-plain.") != NULL - || em_format_is_inline (t->format, t->part_id->str, t->part, t->info->handler)) { - /* FIXME Not passing a GCancellable here. */ - t->info->handler->old->parse_func ( - t->format, t->part, t->part_id, - t->info, NULL); - } else if (epp_show_suppressed) - make_part_attachment (t->format, t->part, t->part_id, TRUE, NULL); -} - -static void -export_as_attachments (CamelMultipart *mp, - EMFormat *format, - CamelMimePart *except, - GString *part_id) -{ - gint i, nparts; - CamelMimePart *part; - gint len; - - if (!mp || !CAMEL_IS_MULTIPART (mp)) - return; - - len = part_id->len; - nparts = camel_multipart_get_number (mp); - for (i = 0; i < nparts; i++) { - part = camel_multipart_get_part (mp, i); - - if (part != except) { - CamelMultipart *multipart = (CamelMultipart *) camel_medium_get_content ((CamelMedium *) part); - - g_string_append_printf (part_id, ".aleternative-prefer-plain.%d", i); - if (CAMEL_IS_MULTIPART (multipart)) { - export_as_attachments (multipart, format, except, part_id); - } else { - make_part_attachment (format, part, part_id, FALSE, NULL); - } - g_string_truncate (part_id, len); - } - } -} - -void -org_gnome_prefer_plain_multipart_alternative (gpointer ep, - EMFormatHookTarget *t) -{ - CamelMultipart *mp = (CamelMultipart *) camel_medium_get_content ((CamelMedium *) t->part); - CamelMimePart *part, *display_part = NULL, *calendar_part = NULL; - gint i, nparts, partidlen, displayid = 0, calendarid = 0; - - partidlen = t->part_id->len; - - if (epp_mode == EPP_NORMAL) { - gboolean have_plain = FALSE; - - /* Try to find text/html part even when not as last and force - * to show it. Old handler will show the last part of - * multipart/alternate, but if we can offer HTML, then - * offer it, regardless of position in multipart. But do - * this when have only text/plain and text/html parts, - * not more. */ - nparts = camel_multipart_get_number (mp); - for (i = 0; i < nparts; i++) { - CamelContentType *content_type; - - part = camel_multipart_get_part (mp, i); - - if (!part) - continue; - - content_type = camel_mime_part_get_content_type (part); - - if (camel_content_type_is (content_type, "text", "html")) { - displayid = i; - display_part = part; - - if (have_plain) - break; - } else if (camel_content_type_is (content_type, "text", "plain")) { - have_plain = TRUE; - - if (display_part) - break; - } - } - - if (display_part && have_plain && nparts == 2) { - g_string_append_printf (t->part_id, ".alternative-prefer-plain.%d", displayid); - /* FIXME Not passing a GCancellable here. */ - em_format_parse_part_as ( - t->format, display_part, t->part_id, t->info, "text/html", NULL); - g_string_truncate (t->part_id, partidlen); - } else { - /* FIXME Not passing a GCancellable here. */ - t->info->handler->old->parse_func ( - t->format, t->part, t->part_id, t->info, NULL); - } - return; - } else if (!CAMEL_IS_MULTIPART (mp)) { - /* FIXME Not passing GCancellable here. */ - em_format_parse_part_as (t->format, t->part, t->part_id, t->info, "x-evolution/message/source", NULL); - return; - } - - nparts = camel_multipart_get_number (mp); - for (i = 0; i < nparts; i++) { - CamelContentType *ct; - - part = camel_multipart_get_part (mp, i); - - if (!part) - continue; - - ct = camel_mime_part_get_content_type (part); - if (!display_part && camel_content_type_is (ct, "text", "plain")) { - displayid = i; - display_part = part; - } else if (!calendar_part && (camel_content_type_is (ct, "text", "calendar") || camel_content_type_is (ct, "text", "x-calendar"))) { - calendarid = i; - calendar_part = part; - } - } - - /* if we found a text part, show it */ - if (display_part) { - g_string_append_printf(t->part_id, ".alternative-prefer-plain.%d", displayid); - /* FIXME Not passing a GCancellable here. */ - em_format_parse_part_as ( - t->format, display_part, t->part_id, t->info, "text/plain", NULL); - g_string_truncate (t->part_id, partidlen); - } - - /* all other parts are attachments */ - if (epp_show_suppressed) - export_as_attachments (mp, t->format, display_part, t->part_id); - else if (calendar_part) { - g_string_append_printf(t->part_id, ".alternative-prefer-plain.%d", calendarid); - make_part_attachment (t->format, calendar_part, t->part_id, FALSE, NULL); - } - - g_string_truncate (t->part_id, partidlen); -} - -static struct { - const gchar *key; - const gchar *label; - const gchar *description; -} epp_options[] = { - { "normal", - N_("Show HTML if present"), - N_("Let Evolution choose the best part to show.") }, - - { "prefer_plain", - N_("Show plain text if present"), - N_("Show plain text part, if present, otherwise " - "let Evolution choose the best part to show.") }, - - { "only_plain", - N_("Only ever show plain text"), - N_("Always show plain text part and make attachments " - "from other parts, if requested.") }, -}; - -static void -update_info_label (GtkWidget *info_label, - guint mode) -{ - gchar *str = g_strconcat ("<i>", _(epp_options[mode > 2 ? 0 : mode].description), "</i>", NULL); - - gtk_label_set_markup (GTK_LABEL (info_label), str); - - g_free (str); -} - -static void -epp_mode_changed (GtkComboBox *dropdown, - GtkWidget *info_label) -{ - epp_mode = gtk_combo_box_get_active (dropdown); - if (epp_mode > 2) - epp_mode = 0; - - g_settings_set_string (epp_settings, "mode", epp_options[epp_mode].key); - update_info_label (info_label, epp_mode); -} - -static void -epp_show_suppressed_toggled (GtkToggleButton *check, - gpointer data) -{ - g_return_if_fail (check != NULL); - - epp_show_suppressed = gtk_toggle_button_get_active (check); - g_settings_set_boolean (epp_settings, "show-suppressed", epp_show_suppressed); -} - -GtkWidget * -org_gnome_prefer_plain_config_mode (EPlugin *epl, - struct _EConfigHookItemFactoryData *data) -{ - GtkComboBox *dropdown; - GtkCellRenderer *cell; - GtkListStore *store; - GtkWidget *dropdown_label, *info, *check; - guint i; - GtkTreeIter iter; - - if (data->old) - return data->old; - - check = gtk_check_button_new_with_mnemonic (_("Show s_uppressed HTML parts as attachments")); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check), epp_show_suppressed); - gtk_widget_show (check); - g_signal_connect ( - check, "toggled", - G_CALLBACK (epp_show_suppressed_toggled), NULL); - - dropdown = (GtkComboBox *) gtk_combo_box_new (); - cell = gtk_cell_renderer_text_new (); - store = gtk_list_store_new (1, G_TYPE_STRING); - for (i = 0; i < G_N_ELEMENTS (epp_options); i++) { - gtk_list_store_append (store, &iter); - gtk_list_store_set (store, &iter, 0, _(epp_options[i].label), -1); - } - - gtk_cell_layout_pack_start ((GtkCellLayout *) dropdown, cell, TRUE); - gtk_cell_layout_set_attributes((GtkCellLayout *)dropdown, cell, "text", 0, NULL); - gtk_combo_box_set_model (dropdown, (GtkTreeModel *) store); - /*gtk_combo_box_set_active(dropdown, -1);*/ - gtk_combo_box_set_active (dropdown, epp_mode); - gtk_widget_show ((GtkWidget *) dropdown); - - dropdown_label = gtk_label_new_with_mnemonic (_("HTML _Mode")); - gtk_widget_show (dropdown_label); - gtk_label_set_mnemonic_widget (GTK_LABEL (dropdown_label), (GtkWidget *) dropdown); - - info = gtk_label_new (NULL); - gtk_misc_set_alignment (GTK_MISC (info), 0.0, 0.5); - gtk_label_set_line_wrap (GTK_LABEL (info), TRUE); - - gtk_widget_show (info); - update_info_label (info, epp_mode); - - g_signal_connect ( - dropdown, "changed", - G_CALLBACK (epp_mode_changed), info); - - g_object_get (data->parent, "n-rows", &i, NULL); - gtk_table_attach ((GtkTable *) data->parent, check, 0, 2, i, i + 1, GTK_FILL | GTK_EXPAND, 0, 0, 0); - gtk_table_attach ((GtkTable *) data->parent, dropdown_label, 0, 1, i + 1, i + 2, 0, 0, 0, 0); - gtk_table_attach ((GtkTable *) data->parent, (GtkWidget *) dropdown, 1, 2, i + 1, i + 2, GTK_FILL | GTK_EXPAND, 0, 0, 0); - gtk_table_attach ((GtkTable *) data->parent, info, 1, 2, i + 2, i + 3, GTK_FILL | GTK_EXPAND, 0, 0, 0); - - /* since this isnt dynamic, we don't need to track each item */ - - return (GtkWidget *) dropdown; -} - -gint e_plugin_lib_enable (EPlugin *ep, gint enable); - -gint -e_plugin_lib_enable (EPlugin *ep, - gint enable) -{ - gchar *key; - gint i; - - if (epp_settings || epp_mode != -1) - return 0; - - if (enable) { - - epp_settings = g_settings_new ("org.gnome.evolution.plugin.prefer-plain"); - key = g_settings_get_string (epp_settings, "mode"); - if (key) { - for (i = 0; i < G_N_ELEMENTS (epp_options); i++) { - if (!strcmp (epp_options[i].key, key)) { - epp_mode = i; - break; - } - } - g_free (key); - } else { - epp_mode = 0; - } - - epp_show_suppressed = g_settings_get_boolean (epp_settings, "show-suppressed"); - } else { - if (epp_settings) { - g_object_unref (epp_settings); - epp_settings = NULL; - } - } - - return 0; -} diff --git a/plugins/tnef-attachments/Makefile.am b/plugins/tnef-attachments/Makefile.am deleted file mode 100644 index 6a393044d1..0000000000 --- a/plugins/tnef-attachments/Makefile.am +++ /dev/null @@ -1,37 +0,0 @@ -if OS_WIN32 -NO_UNDEFINED_REQUIRED_LIBS = \ - $(top_builddir)/e-util/libeutil.la \ - $(top_builddir)/mail/libevolution-mail.la -endif - -@EVO_PLUGIN_RULE@ - -plugin_DATA = org-gnome-tnef-attachments.eplug - -plugin_LTLIBRARIES = liborg-gnome-tnef-attachments.la - -liborg_gnome_tnef_attachments_la_CPPFLAGS = \ - $(AM_CPPFLAGS) \ - -I$(top_srcdir) \ - -I$(top_srcdir)/widgets \ - $(EVOLUTION_DATA_SERVER_CFLAGS) \ - $(GNOME_PLATFORM_CFLAGS) \ - $(TNEF_CFLAGS) - -liborg_gnome_tnef_attachments_la_SOURCES = tnef-plugin.c - -liborg_gnome_tnef_attachments_la_LDFLAGS = -module -avoid-version $(NO_UNDEFINED) - -liborg_gnome_tnef_attachments_la_LIBADD = \ - $(top_builddir)/e-util/libeutil.la \ - $(top_builddir)/em-format/libemformat.la \ - $(EVOLUTION_DATA_SERVER_LIBS) \ - $(GNOME_PLATFORM_LIBS) \ - -lytnef - -EXTRA_DIST = org-gnome-tnef-attachments.eplug.xml - -BUILT_SOURCES = $(plugin_DATA) -CLEANFILES = $(BUILT_SOURCES) - --include $(top_srcdir)/git.mk diff --git a/plugins/tnef-attachments/org-gnome-tnef-attachments.eplug.xml b/plugins/tnef-attachments/org-gnome-tnef-attachments.eplug.xml deleted file mode 100644 index 5bfb0e65c0..0000000000 --- a/plugins/tnef-attachments/org-gnome-tnef-attachments.eplug.xml +++ /dev/null @@ -1,26 +0,0 @@ -<?xml version="1.0"?> -<e-plugin-list> - <e-plugin - type="shlib" - id="org.gnome.evolution.mail.tnefattachments" - location="@PLUGINDIR@/liborg-gnome-tnef-attachments@SOEXT@" - _name="TNEF Decoder"> - <_description>Decode TNEF (winmail.dat) attachments from Microsoft Outlook.</_description> - <author name="Lucky Wankhede" email="wlakke@novell.com"/> - - <hook class="org.gnome.evolution.mail.format:1.0"> - <group id="EMFormatHTML"> - <item flags="inline_disposition" mime_type="application/vnd.ms-tnef" - format="org_gnome_format_tnef"/> - <item flags="inline_disposition" mime_type="application/ms-tnef" - format="org_gnome_format_tnef"/> - </group> - <group id="EMFormatHTMLDisplay"> - <item flags="inline_disposition" mime_type="application/vnd.ms-tnef" - format="org_gnome_format_tnef"/> - <item flags="inline_disposition" mime_type="application/ms-tnef" - format="org_gnome_format_tnef"/> - </group> - </hook> - </e-plugin> -</e-plugin-list> diff --git a/plugins/vcard-inline/Makefile.am b/plugins/vcard-inline/Makefile.am deleted file mode 100644 index afde012ddf..0000000000 --- a/plugins/vcard-inline/Makefile.am +++ /dev/null @@ -1,40 +0,0 @@ -if OS_WIN32 -NO_UNDEFINED_REQUIRED_LIBS = \ - $(top_builddir)/mail/libevolution-mail.la \ - $(top_builddir)/e-util/libeutil.la \ - $(GNOME_PLATFORM_LIBS) -endif - -@EVO_PLUGIN_RULE@ - -plugin_DATA = org-gnome-vcard-inline.eplug - -plugin_LTLIBRARIES = liborg-gnome-vcard-inline.la - -liborg_gnome_vcard_inline_la_CPPFLAGS = \ - $(AM_CPPFLAGS) \ - -I$(top_srcdir) \ - -I$(top_srcdir)/widgets \ - $(EVOLUTION_DATA_SERVER_CFLAGS) \ - $(GNOME_PLATFORM_CFLAGS) - -liborg_gnome_vcard_inline_la_SOURCES = vcard-inline.c - -liborg_gnome_vcard_inline_la_LDFLAGS = -module -avoid-version $(NO_UNDEFINED) - -liborg_gnome_vcard_inline_la_LIBADD = \ - $(top_builddir)/mail/libevolution-mail.la \ - $(top_builddir)/addressbook/util/libeabutil.la \ - $(top_builddir)/addressbook/gui/widgets/libeabwidgets.la \ - $(top_builddir)/addressbook/gui/merging/libeabbookmerging.la \ - $(top_builddir)/addressbook/printing/libecontactprint.la \ - $(top_builddir)/em-format/libemformat.la \ - $(EVOLUTION_DATA_SERVER_LIBS) \ - $(GNOME_PLATFORM_LIBS) - -EXTRA_DIST = org-gnome-vcard-inline.eplug.xml - -BUILT_SOURCES = $(plugin_DATA) -CLEANFILES = $(BUILT_SOURCES) - --include $(top_srcdir)/git.mk diff --git a/plugins/vcard-inline/org-gnome-vcard-inline.eplug.xml b/plugins/vcard-inline/org-gnome-vcard-inline.eplug.xml deleted file mode 100644 index 45b8a7b6ef..0000000000 --- a/plugins/vcard-inline/org-gnome-vcard-inline.eplug.xml +++ /dev/null @@ -1,33 +0,0 @@ -<?xml version="1.0"?> -<e-plugin-list> - <e-plugin - type="shlib" - id="org.gnome.evolution.plugin.vcardInline" - location="@PLUGINDIR@/liborg-gnome-vcard-inline@SOEXT@" - _name="Inline vCards" - system_plugin="true"> - - <author name="Matthew Barnes" email="mbarnes@redhat.com"/> - <_description> - Show vCards directly in mail messages. - </_description> - - <hook class="org.gnome.evolution.mail.format:1.0"> - <group id="EMFormatHTMLDisplay"> - <item - mime_type="text/vcard" - format="org_gnome_vcard_inline_format" - flags="inline_disposition"/> - <item - mime_type="text/x-vcard" - format="org_gnome_vcard_inline_format" - flags="inline_disposition"/> - <item - mime_type="text/directory" - format="org_gnome_vcard_inline_format" - flags="inline_disposition"/> - </group> - </hook> - - </e-plugin> -</e-plugin-list> diff --git a/plugins/vcard-inline/vcard-inline.c b/plugins/vcard-inline/vcard-inline.c deleted file mode 100644 index 3b5885adbc..0000000000 --- a/plugins/vcard-inline/vcard-inline.c +++ /dev/null @@ -1,452 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) version 3. - * - * 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with the program; if not, see <http://www.gnu.org/licenses/> - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <gtk/gtk.h> -#include <glib/gi18n-lib.h> -#include <libebook/libebook.h> -#include <libedataserverui/libedataserverui.h> - -#include <shell/e-shell.h> -#include <addressbook/gui/merging/eab-contact-merging.h> -#include <addressbook/gui/widgets/eab-contact-display.h> -#include <addressbook/gui/widgets/eab-contact-formatter.h> -#include <addressbook/util/eab-book-util.h> -#include <mail/em-format-hook.h> -#include <mail/em-format-html.h> - -#define d(x) - -typedef struct _VCardInlinePURI VCardInlinePURI; - -struct _VCardInlinePURI { - EMFormatPURI puri; - - GSList *contact_list; - GtkWidget *contact_display; - GtkWidget *message_label; - - EABContactFormatter *formatter; - WebKitDOMElement *iframe; - WebKitDOMElement *toggle_button; - WebKitDOMElement *save_button; -}; - -/* Forward Declarations */ -void org_gnome_vcard_inline_format (gpointer ep, EMFormatHookTarget *target); -gint e_plugin_lib_enable (EPlugin *ep, gint enable); - -gint -e_plugin_lib_enable (EPlugin *ep, - gint enable) -{ - return 0; -} - -static void -org_gnome_vcard_inline_pobject_free (EMFormatPURI *object) -{ - VCardInlinePURI *vcard_object; - - vcard_object = (VCardInlinePURI *) object; - - e_client_util_free_object_slist (vcard_object->contact_list); - vcard_object->contact_list = NULL; - - if (vcard_object->contact_display != NULL) { - g_object_unref (vcard_object->contact_display); - vcard_object->contact_display = NULL; - } - - if (vcard_object->message_label != NULL) { - g_object_unref (vcard_object->message_label); - vcard_object->message_label = NULL; - } - - if (vcard_object->formatter != NULL) { - g_object_unref (vcard_object->formatter); - vcard_object->formatter = NULL; - } - - if (vcard_object->iframe != NULL) { - g_object_unref (vcard_object->iframe); - vcard_object->iframe = NULL; - } - - if (vcard_object->toggle_button != NULL) { - g_object_unref (vcard_object->toggle_button); - vcard_object->toggle_button = NULL; - } - - if (vcard_object->save_button != NULL) { - g_object_unref (vcard_object->save_button); - vcard_object->save_button = NULL; - } -} - -static void -org_gnome_vcard_inline_decode (VCardInlinePURI *vcard_object, - CamelMimePart *mime_part) -{ - CamelDataWrapper *data_wrapper; - CamelMedium *medium; - CamelStream *stream; - GSList *contact_list; - GByteArray *array; - const gchar *string; - const guint8 padding[2] = {0}; - - array = g_byte_array_new (); - medium = CAMEL_MEDIUM (mime_part); - - /* Stream takes ownership of the byte array. */ - stream = camel_stream_mem_new_with_byte_array (array); - data_wrapper = camel_medium_get_content (medium); - camel_data_wrapper_decode_to_stream_sync ( - data_wrapper, stream, NULL, NULL); - - /* because the result is not NULL-terminated */ - g_byte_array_append (array, padding, 2); - - string = (gchar *) array->data; - contact_list = eab_contact_list_from_string (string); - vcard_object->contact_list = contact_list; - - g_object_unref (mime_part); - g_object_unref (stream); -} - -static void -org_gnome_vcard_inline_client_loaded_cb (ESource *source, - GAsyncResult *result, - GSList *contact_list) -{ - EShell *shell; - EClient *client = NULL; - EBookClient *book_client; - ESourceRegistry *registry; - GSList *iter; - GError *error = NULL; - - e_client_utils_open_new_finish (source, result, &client, &error); - - if (error != NULL) { - g_warn_if_fail (client == NULL); - g_warning ( - "%s: Failed to open book client: %s", - G_STRFUNC, error->message); - g_error_free (error); - goto exit; - } - - g_return_if_fail (E_IS_BOOK_CLIENT (client)); - - book_client = E_BOOK_CLIENT (client); - - shell = e_shell_get_default (); - registry = e_shell_get_registry (shell); - - for (iter = contact_list; iter != NULL; iter = iter->next) { - EContact *contact; - - contact = E_CONTACT (iter->data); - eab_merging_book_add_contact ( - registry, book_client, contact, NULL, NULL); - } - - g_object_unref (client); - - exit: - e_client_util_free_object_slist (contact_list); -} - -static void -org_gnome_vcard_inline_save_cb (WebKitDOMEventTarget *button, - WebKitDOMEvent *event, - VCardInlinePURI *vcard_object) -{ - EShell *shell; - ESource *source; - ESourceRegistry *registry; - ESourceSelector *selector; - GSList *contact_list; - const gchar *extension_name; - GtkWidget *dialog; - - shell = e_shell_get_default (); - registry = e_shell_get_registry (shell); - extension_name = E_SOURCE_EXTENSION_ADDRESS_BOOK; - - dialog = e_source_selector_dialog_new (NULL, registry, extension_name); - - selector = e_source_selector_dialog_get_selector ( - E_SOURCE_SELECTOR_DIALOG (dialog)); - - source = e_source_registry_ref_default_address_book (registry); - e_source_selector_set_primary_selection (selector, source); - g_object_unref (source); - - if (gtk_dialog_run (GTK_DIALOG (dialog)) != GTK_RESPONSE_OK) { - gtk_widget_destroy (dialog); - return; - } - - source = e_source_selector_dialog_peek_primary_selection ( - E_SOURCE_SELECTOR_DIALOG (dialog)); - - gtk_widget_destroy (dialog); - - g_return_if_fail (source != NULL); - - contact_list = e_client_util_copy_object_slist (NULL, vcard_object->contact_list); - - e_client_utils_open_new ( - source, E_CLIENT_SOURCE_TYPE_CONTACTS, - FALSE, NULL, (GAsyncReadyCallback) - org_gnome_vcard_inline_client_loaded_cb, - contact_list); -} - -static void -org_gnome_vcard_inline_toggle_cb (WebKitDOMEventTarget *button, - WebKitDOMEvent *event, - EMFormatPURI *puri) -{ - VCardInlinePURI *vcard_object; - EABContactDisplayMode mode; - gchar *uri; - - vcard_object = (VCardInlinePURI *) puri; - - mode = eab_contact_formatter_get_display_mode (vcard_object->formatter); - if (mode == EAB_CONTACT_DISPLAY_RENDER_NORMAL) { - mode = EAB_CONTACT_DISPLAY_RENDER_COMPACT; - - webkit_dom_html_element_set_inner_text ( - WEBKIT_DOM_HTML_ELEMENT (button), - _("Show Full vCard"), NULL); - - } else { - mode = EAB_CONTACT_DISPLAY_RENDER_NORMAL; - - webkit_dom_html_element_set_inner_text ( - WEBKIT_DOM_HTML_ELEMENT (button), - _("Show Compact vCard"), NULL); - } - - eab_contact_formatter_set_display_mode (vcard_object->formatter, mode); - - uri = em_format_build_mail_uri ( - puri->emf->folder, puri->emf->message_uid, - "part_id", G_TYPE_STRING, puri->uri, - "mode", G_TYPE_INT, EM_FORMAT_WRITE_MODE_RAW, NULL); - - webkit_dom_html_iframe_element_set_src ( - WEBKIT_DOM_HTML_IFRAME_ELEMENT (vcard_object->iframe), uri); - - g_free (uri); -} - -static void -org_gnome_vcard_inline_bind_dom (WebKitDOMElement *attachment, - EMFormatPURI *puri) -{ - WebKitDOMNodeList *list; - WebKitDOMElement *iframe, *toggle_button, *save_button; - VCardInlinePURI *vcard_object; - - vcard_object = (VCardInlinePURI *) puri; - - /* IFRAME */ - list = webkit_dom_element_get_elements_by_tag_name (attachment, "iframe"); - if (webkit_dom_node_list_get_length (list) != 1) - return; - iframe = WEBKIT_DOM_ELEMENT (webkit_dom_node_list_item (list, 0)); - if (vcard_object->iframe) - g_object_unref (vcard_object->iframe); - vcard_object->iframe = g_object_ref (iframe); - - /* TOGGLE DISPLAY MODE BUTTON */ - list = webkit_dom_element_get_elements_by_class_name ( - attachment, "org-gnome-vcard-inline-display-mode-button"); - if (webkit_dom_node_list_get_length (list) != 1) - return; - toggle_button = WEBKIT_DOM_ELEMENT (webkit_dom_node_list_item (list, 0)); - if (vcard_object->toggle_button) - g_object_unref (vcard_object->toggle_button); - vcard_object->toggle_button = g_object_ref (toggle_button); - - /* SAVE TO ADDRESSBOOK BUTTON */ - list = webkit_dom_element_get_elements_by_class_name ( - attachment, "org-gnome-vcard-inline-save-button"); - if (webkit_dom_node_list_get_length (list) != 1) - return; - save_button = WEBKIT_DOM_ELEMENT (webkit_dom_node_list_item (list, 0)); - if (vcard_object->save_button) - g_object_unref (vcard_object->save_button); - vcard_object->save_button = g_object_ref (save_button); - - webkit_dom_event_target_add_event_listener ( - WEBKIT_DOM_EVENT_TARGET (toggle_button), - "click", G_CALLBACK (org_gnome_vcard_inline_toggle_cb), - FALSE, puri); - - webkit_dom_event_target_add_event_listener ( - WEBKIT_DOM_EVENT_TARGET (save_button), - "click", G_CALLBACK (org_gnome_vcard_inline_save_cb), - FALSE, puri); - - /* Bind collapse buttons for contact lists. */ - eab_contact_formatter_bind_dom ( - webkit_dom_html_iframe_element_get_content_document ( - WEBKIT_DOM_HTML_IFRAME_ELEMENT (iframe))); -} - -static void -org_gnome_vcard_inline_write (EMFormat *emf, - EMFormatPURI *puri, - CamelStream *stream, - EMFormatWriterInfo *info, - GCancellable *cancellable) -{ - VCardInlinePURI *vpuri; - - vpuri = (VCardInlinePURI *) puri; - - if (info->mode == EM_FORMAT_WRITE_MODE_RAW) { - - EContact *contact; - - if (vpuri->contact_list != NULL) - contact = E_CONTACT (vpuri->contact_list->data); - else - contact = NULL; - - eab_contact_formatter_format_contact_sync ( - vpuri->formatter, contact, stream, cancellable); - - } else { - gchar *str, *uri; - gint length; - const gchar *label = NULL; - EABContactDisplayMode mode; - const gchar *info = NULL; - - length = g_slist_length (vpuri->contact_list); - if (length < 1) - return; - - uri = em_format_build_mail_uri ( - emf->folder, emf->message_uid, - "part_id", G_TYPE_STRING, puri->uri, - "mode", G_TYPE_INT, EM_FORMAT_WRITE_MODE_RAW, NULL); - - mode = eab_contact_formatter_get_display_mode (vpuri->formatter); - if (mode == EAB_CONTACT_DISPLAY_RENDER_COMPACT) { - mode = EAB_CONTACT_DISPLAY_RENDER_NORMAL; - label =_("Show Full vCard"); - } else { - mode = EAB_CONTACT_DISPLAY_RENDER_COMPACT; - label = _("Show Compact vCard"); - } - - str = g_strdup_printf ( - "<div id=\"%s\">" - "<button type=\"button\" " - "name=\"set-display-mode\" " - "class=\"org-gnome-vcard-inline-display-mode-button\" " - "value=\"%d\">%s</button>" - "<button type=\"button\" " - "name=\"save-to-addressbook\" " - "class=\"org-gnome-vcard-inline-save-button\" " - "value=\"%s\">%s</button><br/>" - "<iframe width=\"100%%\" height=\"auto\" frameborder=\"0\"" - "src=\"%s\" name=\"%s\"></iframe>" - "</div>", - puri->uri, - mode, label, - puri->uri, _("Save To Addressbook"), - uri, puri->uri); - - camel_stream_write_string (stream, str, cancellable, NULL); - - g_free (str); - - if (length == 2) { - - info = _("There is one other contact."); - - } else if (length > 2) { - - /* Translators: This will always be two or more. */ - info = g_strdup_printf (ngettext ( - "There is %d other contact.", - "There are %d other contacts.", - length - 1), length - 1); - } - - if (info) { - - str = g_strdup_printf ( - "<div class=\"attachment-info\">%s</div>", - info); - - camel_stream_write_string (stream, str, cancellable, NULL); - - g_free (str); - } - - g_free (uri); - } -} - -void -org_gnome_vcard_inline_format (gpointer ep, - EMFormatHookTarget *target) -{ - VCardInlinePURI *vcard_object; - gint len; - - len = target->part_id->len; - g_string_append (target->part_id, ".org-gnome-vcard-inline-display"); - - vcard_object = (VCardInlinePURI *) em_format_puri_new ( - target->format, sizeof (VCardInlinePURI), - target->part, target->part_id->str); - vcard_object->puri.mime_type = g_strdup("text/html"); - vcard_object->puri.write_func = org_gnome_vcard_inline_write; - vcard_object->puri.bind_func = org_gnome_vcard_inline_bind_dom; - vcard_object->puri.free = org_gnome_vcard_inline_pobject_free; - vcard_object->puri.is_attachment = true; - vcard_object->formatter - = g_object_new ( - EAB_TYPE_CONTACT_FORMATTER, - "display-mode", EAB_CONTACT_DISPLAY_RENDER_COMPACT, - "render-maps", FALSE, NULL); - - em_format_add_puri (target->format, (EMFormatPURI *) vcard_object); - - g_object_ref (target->part); - - org_gnome_vcard_inline_decode (vcard_object, target->part); - - g_string_truncate (target->part_id, len); -} diff --git a/po/POTFILES.in b/po/POTFILES.in index 8fcfd5de50..cc08947540 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -155,8 +155,30 @@ data/org.gnome.evolution.plugin.prefer-plain.gschema.xml.in data/org.gnome.evolution.plugin.templates.gschema.xml.in data/org.gnome.evolution.shell.gschema.xml.in data/org.gnome.evolution.spamassassin.gschema.xml.in -em-format/em-format.c -em-format/em-format-quote.c +em-format/e-mail-formatter-attachment.c +em-format/e-mail-formatter-headers.c +em-format/e-mail-formatter-image.c +em-format/e-mail-formatter-message-rfc822.c +em-format/e-mail-formatter-print-headers.c +em-format/e-mail-formatter-print.c +em-format/e-mail-formatter-quote-text-enriched.c +em-format/e-mail-formatter-quote-text-html.c +em-format/e-mail-formatter-quote-text-plain.c +em-format/e-mail-formatter-secure-button.c +em-format/e-mail-formatter-source.c +em-format/e-mail-formatter-text-enriched.c +em-format/e-mail-formatter-text-html.c +em-format/e-mail-formatter-text-plain.c +em-format/e-mail-formatter-utils.c +em-format/e-mail-formatter.c +em-format/e-mail-parser-application-mbox.c +em-format/e-mail-parser-application-smime.c +em-format/e-mail-parser-inlinepgp-encrypted.c +em-format/e-mail-parser-inlinepgp-signed.c +em-format/e-mail-parser-message-external.c +em-format/e-mail-parser-multipart-encrypted.c +em-format/e-mail-parser-multipart-signed.c +em-format/e-mail-part-utils.c e-util/e-activity.c e-util/e-categories-config.c e-util/e-charset.c @@ -192,7 +214,6 @@ libemail-utils/mail-mt.c libevolution-utils/e-alert-dialog.c mail/e-mail-account-manager.c mail/e-mail-account-tree-view.c -mail/e-mail-attachment-bar.c mail/e-mail-autoconfig.c mail/e-mail-backend.c mail/e-mail-browser.c @@ -236,9 +257,6 @@ mail/em-folder-selector.c mail/em-folder-tree.c mail/em-folder-tree-model.c mail/em-folder-utils.c -mail/em-format-html.c -mail/em-format-html-display.c -mail/em-format-html-print.c mail/em-subscription-editor.c mail/em-utils.c mail/em-vfolder-editor.c @@ -267,6 +285,7 @@ modules/addressbook/e-book-shell-sidebar.c modules/addressbook/e-book-shell-view-actions.c modules/addressbook/e-book-shell-view.c [type: gettext/glade]modules/addressbook/ldap-config.ui +modules/audio-inline/e-mail-formatter-audio-inline.c modules/backup-restore/e-mail-config-restore-page.c modules/backup-restore/e-mail-config-restore-ready-page.c modules/backup-restore/evolution-backup-restore.c @@ -316,6 +335,11 @@ modules/calendar/e-task-shell-view-actions.c modules/calendar/e-task-shell-view.c modules/calendar/e-task-shell-view-private.c modules/imap-features/e-mail-config-imap-headers-page.c +modules/itip-formatter/e-mail-formatter-itip.c +modules/itip-formatter/itip-view.c +modules/itip-formatter/org-gnome-itip-formatter.error.xml +modules/itip-formatter/plugin/config-ui.c +modules/itip-formatter/plugin/org-gnome-itip-formatter.eplug.xml modules/mail/em-account-prefs.c modules/mail/e-mail-attachment-handler.c modules/mail/e-mail-shell-backend.c @@ -339,18 +363,23 @@ modules/online-accounts/camel-sasl-xoauth.c modules/plugin-manager/evolution-plugin-manager.c modules/plugin-python/example/org-gnome-hello-python.eplug.xml modules/plugin-python/example/org-gnome-hello-python-ui.xml +modules/prefer-plain/e-mail-parser-prefer-plain.c +modules/prefer-plain/plugin/config-ui.c +modules/prefer-plain/plugin/org-gnome-prefer-plain.eplug.xml modules/spamassassin/evolution-spamassassin.c modules/spamassassin/evolution-spamassassin.schemas.in modules/startup-wizard/e-mail-config-import-page.c modules/startup-wizard/e-mail-config-import-progress-page.c modules/startup-wizard/e-startup-assistant.c modules/startup-wizard/evolution-startup-wizard.c +modules/text-highlight/text-highlight.c +modules/vcard-inline/e-mail-formatter-vcard-inline.c +modules/vcard-inline/e-mail-parser-vcard-inline.c modules/web-inspector/evolution-web-inspector.c plugins/attachment-reminder/apps-evolution-attachment-reminder.schemas.in plugins/attachment-reminder/attachment-reminder.c plugins/attachment-reminder/org-gnome-attachment-reminder.error.xml plugins/attachment-reminder/org-gnome-evolution-attachment-reminder.eplug.xml -plugins/audio-inline/org-gnome-audio-inline.eplug.xml plugins/bbdb/bbdb.c plugins/bbdb/org-gnome-evolution-bbdb.eplug.xml plugins/dbx-import/dbx-importer.c @@ -368,10 +397,6 @@ plugins/face/face.c plugins/face/org-gnome-face.eplug.xml plugins/face/org-gnome-face.error.xml plugins/image-inline/org-gnome-image-inline.eplug.xml -plugins/itip-formatter/itip-formatter.c -plugins/itip-formatter/itip-view.c -plugins/itip-formatter/org-gnome-itip-formatter.eplug.xml -plugins/itip-formatter/org-gnome-itip-formatter.error.xml plugins/mailing-list-actions/mailing-list-actions.c plugins/mailing-list-actions/org-gnome-mailing-list-actions.eplug.xml plugins/mailing-list-actions/org-gnome-mailing-list-actions.error.xml @@ -382,8 +407,6 @@ plugins/mail-to-task/mail-to-task.c plugins/mail-to-task/org-gnome-mail-to-task.eplug.xml plugins/mark-all-read/mark-all-read.c plugins/mark-all-read/org-gnome-mark-all-read.eplug.xml -plugins/prefer-plain/org-gnome-prefer-plain.eplug.xml -plugins/prefer-plain/prefer-plain.c plugins/pst-import/org-gnome-pst-import.eplug.xml plugins/pst-import/pst-importer.c plugins/publish-calendar/org-gnome-publish-calendar.eplug.xml @@ -400,9 +423,6 @@ plugins/save-calendar/save-calendar.c plugins/templates/apps-evolution-template-placeholders.schemas.in plugins/templates/org-gnome-templates.eplug.xml plugins/templates/templates.c -plugins/tnef-attachments/org-gnome-tnef-attachments.eplug.xml -plugins/vcard-inline/org-gnome-vcard-inline.eplug.xml -plugins/vcard-inline/vcard-inline.c shell/apps_evolution_shell.schemas.in shell/e-shell-backend.c shell/e-shell.c @@ -451,6 +471,7 @@ widgets/misc/e-action-combo-box.c widgets/misc/e-activity-proxy.c widgets/misc/e-alert-bar.c widgets/misc/e-attachment.c +widgets/misc/e-attachment-bar.c widgets/misc/e-attachment-dialog.c widgets/misc/e-attachment-handler-image.c widgets/misc/e-attachment-handler-sendto.c |