Commit 93119147 authored by Dan Vrátil's avatar Dan Vrátil
Browse files

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.
parent 5b834056
......@@ -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
......
......@@ -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
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
/*
* 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
......@@ -12,119 +14,90 @@
* 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)
*
*/
#include "e-mail-formatter-audio-inline.h"
#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;
#include <glib/gi18n-lib.h>
gchar *filename;
GstElement *playbin;
gulong bus_id;
GstState target_state;
GtkWidget *play_button;
GtkWidget *pause_button;
GtkWidget *stop_button;
};
#include <libebackend/libebackend.h>
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;
}
#include <em-format/e-mail-formatter-extension.h>
#include <em-format/e-mail-formatter.h>
if (po->pause_button) {
g_object_unref (po->pause_button);
po->pause_button = NULL;
}
#include "e-util/e-mktemp.h"
if (po->stop_button) {
g_object_unref (po->stop_button);
po->stop_button = NULL;
}
#include <camel/camel.h>
#include <gst/gst.h>
if (po->filename) {
g_unlink (po->filename);
g_free (po->filename);
po->filename = NULL;
}
#include "e-mail-part-audio-inline.h"
if (po->bus_id) {
g_source_remove (po->bus_id);
po->bus_id = 0;
}
#define d(x)
if (po->playbin) {
gst_element_set_state (po->playbin, GST_STATE_NULL);
gst_object_unref (po->playbin);
po->playbin = NULL;
}
}
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
org_gnome_audio_inline_pause_clicked (GtkWidget *button,
EMFormatPURI *puri)
pause_clicked (GtkWidget *button,
EMailPartAudioInline *part)
{
EMFormatInlineAudioPURI *po = (EMFormatInlineAudioPURI *) puri;
if (po->playbin) {
if (part->playbin) {
/* pause playing */
gst_element_set_state (po->playbin, GST_STATE_PAUSED);
gst_element_set_state (part->playbin, GST_STATE_PAUSED);
}
}
static void
org_gnome_audio_inline_stop_clicked (GtkWidget *button,
EMFormatPURI *puri)
stop_clicked (GtkWidget *button,
EMailPartAudioInline *part)
{
EMFormatInlineAudioPURI *po = (EMFormatInlineAudioPURI *) puri;
if (po->playbin) {
if (part->playbin) {
/* ready to play */
gst_element_set_state (po->playbin, GST_STATE_READY);
po->target_state = GST_STATE_READY;
gst_element_set_state (part->playbin, GST_STATE_READY);
part->target_state = GST_STATE_READY;
}
}
static void
org_gnome_audio_inline_set_audiosink (GstElement *playbin)
set_audiosink (GstElement *playbin)
{
GstElement *audiosink;
......@@ -140,30 +113,30 @@ org_gnome_audio_inline_set_audiosink (GstElement *playbin)
}
static gboolean
org_gnome_audio_inline_gst_callback (GstBus *bus,
GstMessage *message,
gpointer data)
gst_callback (GstBus *bus,
GstMessage *message,
gpointer data)
{
EMFormatInlineAudioPURI *po = (EMFormatInlineAudioPURI *) data;
EMailPartAudioInline *part = data;
GstMessageType msg_type;
g_return_val_if_fail (po != NULL, TRUE);
g_return_val_if_fail (po->playbin != NULL, TRUE);
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 (po->playbin, GST_STATE_NULL);
gst_element_set_state (part->playbin, GST_STATE_NULL);
break;
case GST_MESSAGE_EOS:
gst_element_set_state (po->playbin, GST_STATE_READY);
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 (po->playbin))
if (GST_MESSAGE_SRC (message) != GST_OBJECT (part->playbin))
break;
gst_message_parse_state_changed (message, &old_state, &new_state, NULL);
......@@ -171,12 +144,18 @@ org_gnome_audio_inline_gst_callback (GstBus *bus,
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);
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;
......@@ -188,15 +167,14 @@ org_gnome_audio_inline_gst_callback (GstBus *bus,
}
static void
org_gnome_audio_inline_play_clicked (GtkWidget *button,
EMFormatPURI *puri)
play_clicked (GtkWidget *button,
EMailPartAudioInline *part)
{
EMFormatInlineAudioPURI *po = (EMFormatInlineAudioPURI *) puri;
GstState cur_state;
d(printf ("audio inline formatter: play\n"));
if (!po->filename) {
if (!part->filename) {
CamelStream *stream;
CamelDataWrapper *data;
GError *error = NULL;
......@@ -204,14 +182,14 @@ org_gnome_audio_inline_play_clicked (GtkWidget *button,
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");
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 (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);
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);
......@@ -222,20 +200,20 @@ org_gnome_audio_inline_play_clicked (GtkWidget *button,
GstBus *bus;
/* create a disk reader */
po->playbin = gst_element_factory_make ("playbin", "playbin");
if (po->playbin == NULL) {
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 (po->filename, NULL, NULL);
g_object_set (po->playbin, "uri", uri, NULL);
uri = g_filename_to_uri (part->filename, NULL, NULL);
g_object_set (part->playbin, "uri", uri, NULL);
g_free (uri);
org_gnome_audio_inline_set_audiosink (po->playbin);
set_audiosink (part->playbin);
bus = gst_element_get_bus (po->playbin);
po->bus_id = gst_bus_add_watch (bus, org_gnome_audio_inline_gst_callback, po);
bus = gst_element_get_bus (part->playbin);
part->bus_id = gst_bus_add_watch (bus, gst_callback, part);
gst_object_unref (bus);
} else {
......@@ -244,24 +222,24 @@ org_gnome_audio_inline_play_clicked (GtkWidget *button,
}
}
gst_element_get_state (po->playbin, &cur_state, NULL, 0);
gst_element_get_state (part->playbin, &cur_state, NULL, 0);
if (cur_state >= GST_STATE_PAUSED) {
gst_element_set_state (po->playbin, GST_STATE_READY);
gst_element_set_state (part->playbin, GST_STATE_READY);
}
if (po->playbin) {
if (part->playbin) {
/* start playing */
gst_element_set_state (po->playbin, GST_STATE_PLAYING);
gst_element_set_state (part->playbin, GST_STATE_PLAYING);
}
}
static GtkWidget *
org_gnome_audio_inline_add_button (GtkWidget *box,
const gchar *stock_icon,
GCallback cb,
gpointer data,
gboolean sensitive)
add_button (GtkWidget *box,
const gchar *stock_icon,
GCallback cb,
gpointer data,
gboolean sensitive)
{
GtkWidget *button;
......@@ -275,73 +253,131 @@ org_gnome_audio_inline_add_button (GtkWidget *box,
return button;
}
static void
write_button_panel (EMFormat *emf,
EMFormatPURI *puri,
CamelStream *stream,
EMFormatWriterInfo *info,
GCancellable *cancellable)
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/x-org-gnome-audio-inline-button-panel\" "
"<object type=\"application/vnd.evolution.widget.audio-inline\" "
"width=\"100%%\" height=\"auto\" data=\"%s\" id=\"%s\"></object>",
puri->uri, puri->uri);
part->id, part->id);
camel_stream_write_string (stream, str, cancellable, NULL);
g_free (str);
return TRUE;
}
static GtkWidget *
org_gnome_audio_inline_button_panel (EMFormat *emf,
EMFormatPURI *puri,
GCancellable *cancellable)
emfe_audio_inline_get_widget (EMailFormatterExtension *extension,
EMailPartList *context,
EMailPart *part,
GHashTable *params)
{
GtkWidget *box;
EMFormatInlineAudioPURI *po = (EMFormatInlineAudioPURI *) puri;
EMailPartAudioInline *ai_part;
/* it is OK to call UI functions here, since we are called from UI thread */
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 ();
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));
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 **