diff options
author | Matthew Barnes <mbarnes@redhat.com> | 2009-08-29 08:21:54 +0800 |
---|---|---|
committer | Matthew Barnes <mbarnes@redhat.com> | 2009-08-30 05:23:20 +0800 |
commit | 32f545cdf031ebe3718791f18e8fb6b6141fd081 (patch) | |
tree | 980723161c32da855ca91b135318d7fa67dc18c7 /modules | |
parent | e8382099228d46ebef684c5384bab6ec710283ce (diff) | |
download | gsoc2013-evolution-32f545cdf031ebe3718791f18e8fb6b6141fd081.tar.gz gsoc2013-evolution-32f545cdf031ebe3718791f18e8fb6b6141fd081.tar.zst gsoc2013-evolution-32f545cdf031ebe3718791f18e8fb6b6141fd081.zip |
Simplify EPlugin loading at startup.
- Require all EPlugin and EPluginHook subtypes be registered before
loading plugins. This drastically simplifies the EPlugin/EPluginHook
negotiation.
- Turn most EPluginHook subtypes into GTypeModules and register their
types from an e_module_load() function (does not include shell hooks).
- Convert EPluginLib and the Mono and Python bindings to GTypeModules
and register their types from an e_module_load() function, and kill
EPluginTypeHook.
Diffstat (limited to 'modules')
46 files changed, 4364 insertions, 172 deletions
diff --git a/modules/Makefile.am b/modules/Makefile.am index 5030d2aeb6..f792a4d9ee 100644 --- a/modules/Makefile.am +++ b/modules/Makefile.am @@ -1,3 +1,11 @@ -SUBDIRS = addressbook calendar mail +if ENABLE_MONO +MONO_DIR = plugin-mono +endif + +if ENABLE_PYTHON +PYTHON_DIR = plugin-python +endif + +SUBDIRS = addressbook calendar mail plugin-lib $(MONO_DIR) $(PYTHON_DIR) -include $(top_srcdir)/git.mk diff --git a/modules/addressbook/Makefile.am b/modules/addressbook/Makefile.am index 5ba744dee6..05b169841e 100644 --- a/modules/addressbook/Makefile.am +++ b/modules/addressbook/Makefile.am @@ -34,6 +34,8 @@ libevolution_module_addressbook_la_SOURCES = \ autocompletion-config.h \ eab-composer-util.c \ eab-composer-util.h \ + e-book-config-hook.c \ + e-book-config-hook.h \ e-book-shell-backend.c \ e-book-shell-backend.h \ e-book-shell-content.c \ diff --git a/modules/addressbook/e-book-config-hook.c b/modules/addressbook/e-book-config-hook.c new file mode 100644 index 0000000000..d8c03a5329 --- /dev/null +++ b/modules/addressbook/e-book-config-hook.c @@ -0,0 +1,67 @@ +/* + * e-book-config-hook.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/> + * + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#include "e-book-config-hook.h" + +#include "e-util/e-config.h" +#include "addressbook/gui/widgets/eab-config.h" + +static const EConfigHookTargetMask no_masks[] = { + { NULL } +}; + +static const EConfigHookTargetMap targets[] = { + { "source", EAB_CONFIG_TARGET_SOURCE, no_masks }, + { NULL } +}; + +static void +book_config_hook_class_init (EPluginHookClass *class) +{ + gint ii; + + class->id = "org.gnome.evolution.addressbook.config:1.0"; + + for (ii = 0; targets[ii].type != NULL; ii++) + e_config_hook_class_add_target_map ( + (EConfigHookClass *) class, &targets[ii]); +} + +void +e_book_config_hook_register_type (GTypeModule *type_module) +{ + const GTypeInfo type_info = { + sizeof (EConfigHookClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) book_config_hook_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + sizeof (EConfigHook), + 0, /* n_preallocs */ + (GInstanceInitFunc) NULL, + NULL /* value_table */ + }; + + g_type_module_register_type ( + type_module, e_config_hook_get_type (), + "EBookConfigHook", &type_info, 0); +} diff --git a/modules/addressbook/e-book-config-hook.h b/modules/addressbook/e-book-config-hook.h new file mode 100644 index 0000000000..a5d9e06457 --- /dev/null +++ b/modules/addressbook/e-book-config-hook.h @@ -0,0 +1,33 @@ +/* + * e-book-config-hook.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/> + * + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifndef E_BOOK_CONFIG_HOOK_H +#define E_BOOK_CONFIG_HOOK_H + +#include <glib-object.h> + +G_BEGIN_DECLS + +void e_book_config_hook_register_type (GTypeModule *type_module); + +G_END_DECLS + +#endif /* E_BOOK_CONFIG_HOOK_H */ diff --git a/modules/addressbook/e-book-shell-backend.c b/modules/addressbook/e-book-shell-backend.c index 87ac638822..f96cb0dd22 100644 --- a/modules/addressbook/e-book-shell-backend.c +++ b/modules/addressbook/e-book-shell-backend.c @@ -39,7 +39,6 @@ #include "addressbook/gui/contact-list-editor/e-contact-list-editor.h" #include "addressbook/importers/evolution-addressbook-importers.h" -#include "eab-config.h" #include "addressbook-config.h" #include "autocompletion-config.h" @@ -498,8 +497,6 @@ book_shell_backend_constructed (GObject *object) book_shell_backend_init_importers (); book_shell_backend_ensure_sources (shell_backend); - e_plugin_hook_register_type (eab_config_get_type ()); - g_signal_connect_swapped ( shell, "handle-uri", G_CALLBACK (book_shell_backend_handle_uri_cb), diff --git a/modules/addressbook/evolution-module-addressbook.c b/modules/addressbook/evolution-module-addressbook.c index 3089133e43..73b3634b91 100644 --- a/modules/addressbook/evolution-module-addressbook.c +++ b/modules/addressbook/evolution-module-addressbook.c @@ -19,6 +19,8 @@ * */ +#include "e-book-config-hook.h" + #include "e-book-shell-backend.h" #include "e-book-shell-content.h" #include "e-book-shell-sidebar.h" @@ -33,6 +35,8 @@ e_module_load (GTypeModule *type_module) { /* Register dynamically loaded types. */ + e_book_config_hook_register_type (type_module); + e_book_shell_backend_register_type (type_module); e_book_shell_content_register_type (type_module); e_book_shell_sidebar_register_type (type_module); diff --git a/modules/calendar/Makefile.am b/modules/calendar/Makefile.am index 8f771167d9..490d42a05e 100644 --- a/modules/calendar/Makefile.am +++ b/modules/calendar/Makefile.am @@ -10,6 +10,12 @@ module_LTLIBRARIES = \ libevolution_module_calendar_la_SOURCES = \ evolution-module-calendar.c \ + e-cal-attachment-handler.c \ + e-cal-attachment-handler.h \ + e-cal-config-hook.c \ + e-cal-config-hook.h \ + e-cal-event-hook.c \ + e-cal-event-hook.h \ e-cal-shell-backend.c \ e-cal-shell-backend.h \ e-cal-shell-content.c \ @@ -57,9 +63,6 @@ libevolution_module_calendar_la_SOURCES = \ e-task-shell-view-private.c \ e-task-shell-view-private.h -# Removed from all three -# $(top_builddir)/a11y/calendar/libevolution-calendar-a11y.la - libevolution_module_calendar_la_LIBADD = \ $(top_builddir)/shell/libeshell.la \ $(top_builddir)/calendar/gui/libevolution-calendar.la \ diff --git a/modules/calendar/e-cal-attachment-handler.c b/modules/calendar/e-cal-attachment-handler.c new file mode 100644 index 0000000000..dd95cc5d08 --- /dev/null +++ b/modules/calendar/e-cal-attachment-handler.c @@ -0,0 +1,512 @@ +/* + * e-cal-attachment-handler.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/> + * + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#include "e-cal-attachment-handler.h" + +#include <glib/gi18n.h> +#include <libical/ical.h> +#include <libecal/e-cal.h> +#include <camel/camel-stream-mem.h> +#include <libedataserverui/e-source-selector.h> + +#include "calendar/common/authentication.h" + +#define E_CAL_ATTACHMENT_HANDLER_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE \ + ((obj), E_TYPE_CAL_ATTACHMENT_HANDLER, ECalAttachmentHandlerPrivate)) + +typedef struct _ImportContext ImportContext; + +struct _ECalAttachmentHandlerPrivate { + gint placeholder; +}; + +struct _ImportContext { + ECal *client; + icalcomponent *component; + ECalSourceType source_type; +}; + +static gpointer parent_class; +static GType cal_attachment_handler_type; + +static const gchar *ui = +"<ui>" +" <popup name='context'>" +" <placeholder name='custom-actions'>" +" <menuitem action='import-to-calendar'/>" +" <menuitem action='import-to-tasks'/>" +" </placeholder>" +" </popup>" +"</ui>"; + +static icalcomponent * +attachment_handler_get_component (EAttachment *attachment) +{ + CamelDataWrapper *wrapper; + CamelMimePart *mime_part; + CamelStream *stream; + GByteArray *buffer; + icalcomponent *component; + const gchar *key = "__icalcomponent__"; + + component = g_object_get_data (G_OBJECT (attachment), key); + if (component != NULL) + return component; + + mime_part = e_attachment_get_mime_part (attachment); + if (!CAMEL_IS_MIME_PART (mime_part)) + return NULL; + + buffer = g_byte_array_new (); + stream = camel_stream_mem_new (); + camel_stream_mem_set_byte_array (CAMEL_STREAM_MEM (stream), buffer); + wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (mime_part)); + camel_data_wrapper_decode_to_stream (wrapper, stream); + camel_object_unref (stream); + + component = e_cal_util_parse_ics_string ((gchar *) buffer->data); + + g_byte_array_free (buffer, TRUE); + + if (component == NULL) + return NULL; + + g_object_set_data_full ( + G_OBJECT (attachment), key, component, + (GDestroyNotify) icalcomponent_free); + + return component; +} + +static gboolean +attachment_handler_update_objects (ECal *client, + icalcomponent *component) +{ + icalcomponent_kind kind; + icalcomponent *vcalendar; + gboolean success; + + kind = icalcomponent_isa (component); + + switch (kind) { + case ICAL_VTODO_COMPONENT: + case ICAL_VEVENT_COMPONENT: + vcalendar = e_cal_util_new_top_level (); + if (icalcomponent_get_method (component) == ICAL_METHOD_CANCEL) + icalcomponent_set_method (vcalendar, ICAL_METHOD_CANCEL); + else + icalcomponent_set_method (vcalendar, ICAL_METHOD_PUBLISH); + icalcomponent_add_component ( + vcalendar, icalcomponent_new_clone (component)); + break; + + case ICAL_VCALENDAR_COMPONENT: + vcalendar = icalcomponent_new_clone (component); + if (!icalcomponent_get_first_property (vcalendar, ICAL_METHOD_PROPERTY)) + icalcomponent_set_method (vcalendar, ICAL_METHOD_PUBLISH); + break; + + default: + return FALSE; + } + + success = e_cal_receive_objects (client, vcalendar, NULL); + + icalcomponent_free (vcalendar); + + return success; +} + +static void +attachment_handler_import_event (ECal *client, + ECalendarStatus status, + EAttachment *attachment) +{ + icalcomponent *component; + icalcomponent *subcomponent; + icalcompiter iter; + + /* FIXME Notify the user somehow. */ + g_return_if_fail (status == E_CALENDAR_STATUS_OK); + + component = attachment_handler_get_component (attachment); + g_return_if_fail (component != NULL); + + iter = icalcomponent_begin_component (component, ICAL_ANY_COMPONENT); + + while ((subcomponent = icalcompiter_deref (&iter)) != NULL) { + icalcomponent_kind kind; + + kind = icalcomponent_isa (subcomponent); + icalcompiter_next (&iter); + + if (kind == ICAL_VEVENT_COMPONENT) + continue; + + if (kind == ICAL_VTIMEZONE_COMPONENT) + continue; + + icalcomponent_remove_component (component, subcomponent); + icalcomponent_free (subcomponent); + } + + /* XXX Do something with the return value. */ + attachment_handler_update_objects (client, component); + + g_object_unref (attachment); + g_object_unref (client); +} + +static void +attachment_handler_import_todo (ECal *client, + ECalendarStatus status, + EAttachment *attachment) +{ + icalcomponent *component; + icalcomponent *subcomponent; + icalcompiter iter; + + /* FIXME Notify the user somehow. */ + g_return_if_fail (status == E_CALENDAR_STATUS_OK); + + component = attachment_handler_get_component (attachment); + g_return_if_fail (component != NULL); + + iter = icalcomponent_begin_component (component, ICAL_ANY_COMPONENT); + + while ((subcomponent = icalcompiter_deref (&iter)) != NULL) { + icalcomponent_kind kind; + + kind = icalcomponent_isa (subcomponent); + icalcompiter_next (&iter); + + if (kind == ICAL_VTODO_COMPONENT) + continue; + + if (kind == ICAL_VTIMEZONE_COMPONENT) + continue; + + icalcomponent_remove_component (component, subcomponent); + icalcomponent_free (subcomponent); + } + + /* XXX Do something with the return value. */ + attachment_handler_update_objects (client, component); + + g_object_unref (attachment); + g_object_unref (client); +} + +static void +attachment_handler_row_activated_cb (GtkDialog *dialog) +{ + gtk_dialog_response (dialog, GTK_RESPONSE_OK); +} + +static void +attachment_handler_run_dialog (GtkWindow *parent, + EAttachment *attachment, + ECalSourceType source_type, + const gchar *title) +{ + GtkWidget *dialog; + GtkWidget *container; + GtkWidget *widget; + GCallback callback; + ESourceSelector *selector; + ESourceList *source_list; + ESource *source; + ECal *client; + icalcomponent *component; + GError *error = NULL; + + component = attachment_handler_get_component (attachment); + g_return_if_fail (component != NULL); + + e_cal_get_sources (&source_list, source_type, &error); + if (error != NULL) { + g_warning ("%s", error->message); + g_error_free (error); + return; + } + + source = e_source_list_peek_source_any (source_list); + g_return_if_fail (source != NULL); + + dialog = gtk_dialog_new_with_buttons ( + title, parent, GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, NULL); + + widget = gtk_button_new_with_mnemonic (_("I_mport")); + gtk_button_set_image ( + GTK_BUTTON (widget), gtk_image_new_from_icon_name ( + "stock_mail-import", GTK_ICON_SIZE_MENU)); + gtk_dialog_add_action_widget ( + GTK_DIALOG (dialog), widget, GTK_RESPONSE_OK); + gtk_widget_show (widget); + + gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE); + gtk_window_set_default_size (GTK_WINDOW (dialog), 300, 400); + + container = gtk_dialog_get_content_area (GTK_DIALOG (dialog)); + + widget = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy ( + GTK_SCROLLED_WINDOW (widget), + GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type ( + GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN); + gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0); + gtk_widget_show (widget); + + container = widget; + + widget = e_source_selector_new (source_list); + selector = E_SOURCE_SELECTOR (widget); + e_source_selector_set_primary_selection (selector, source); + e_source_selector_show_selection (selector, FALSE); + gtk_container_add (GTK_CONTAINER (container), widget); + gtk_widget_show (widget); + + g_signal_connect_swapped ( + widget, "row-activated", + G_CALLBACK (attachment_handler_row_activated_cb), dialog); + + if (gtk_dialog_run (GTK_DIALOG (dialog)) != GTK_RESPONSE_OK) + goto exit; + + source = e_source_selector_peek_primary_selection (selector); + if (source == NULL) + goto exit; + + client = auth_new_cal_from_source (source, source_type); + if (client == NULL) + goto exit; + + if (source_type == E_CAL_SOURCE_TYPE_EVENT) + callback = G_CALLBACK (attachment_handler_import_event); + else if (source_type == E_CAL_SOURCE_TYPE_TODO) + callback = G_CALLBACK (attachment_handler_import_todo); + else + goto exit; + + g_object_ref (attachment); + g_signal_connect (client, "cal-opened", callback, attachment); + e_cal_open_async (client, FALSE); + +exit: + gtk_widget_destroy (dialog); +} + +static void +attachment_handler_import_to_calendar (GtkAction *action, + EAttachmentHandler *handler) +{ + EAttachment *attachment; + EAttachmentView *view; + GList *selected; + gpointer parent; + + view = e_attachment_handler_get_view (handler); + + parent = gtk_widget_get_toplevel (GTK_WIDGET (view)); + parent = GTK_WIDGET_TOPLEVEL (parent) ? parent : NULL; + + selected = e_attachment_view_get_selected_attachments (view); + g_return_if_fail (g_list_length (selected) == 1); + attachment = E_ATTACHMENT (selected->data); + + attachment_handler_run_dialog ( + parent, attachment, + E_CAL_SOURCE_TYPE_EVENT, + _("Select a Calendar")); + + g_object_unref (attachment); + g_list_free (selected); +} + +static void +attachment_handler_import_to_tasks (GtkAction *action, + EAttachmentHandler *handler) +{ + EAttachment *attachment; + EAttachmentView *view; + GList *selected; + gpointer parent; + + view = e_attachment_handler_get_view (handler); + + parent = gtk_widget_get_toplevel (GTK_WIDGET (view)); + parent = GTK_WIDGET_TOPLEVEL (parent) ? parent : NULL; + + selected = e_attachment_view_get_selected_attachments (view); + g_return_if_fail (g_list_length (selected) == 1); + attachment = E_ATTACHMENT (selected->data); + + attachment_handler_run_dialog ( + parent, attachment, + E_CAL_SOURCE_TYPE_TODO, + _("Select a Task List")); + + g_object_unref (attachment); + g_list_free (selected); +} + +static GtkActionEntry standard_entries[] = { + + { "import-to-calendar", + "stock_mail-import", + N_("I_mport to Calendar"), + NULL, + NULL, /* XXX Add a tooltip! */ + G_CALLBACK (attachment_handler_import_to_calendar) }, + + { "import-to-tasks", + "stock_mail-import", + N_("I_mport to Tasks"), + NULL, + NULL, /* XXX Add a tooltip! */ + G_CALLBACK (attachment_handler_import_to_tasks) } +}; + +static void +cal_attachment_handler_update_actions (EAttachmentView *view) +{ + EAttachment *attachment; + GtkAction *action; + GList *selected; + icalcomponent *component; + icalcomponent *subcomponent; + icalcomponent_kind kind; + gboolean is_vevent = FALSE; + gboolean is_vtodo = FALSE; + + selected = e_attachment_view_get_selected_attachments (view); + + if (g_list_length (selected) != 1) + goto exit; + + attachment = E_ATTACHMENT (selected->data); + component = attachment_handler_get_component (attachment); + + if (component == NULL) + goto exit; + + subcomponent = icalcomponent_get_inner (component); + + if (subcomponent == NULL) + goto exit; + + kind = icalcomponent_isa (subcomponent); + is_vevent = (kind == ICAL_VEVENT_COMPONENT); + is_vtodo = (kind == ICAL_VTODO_COMPONENT); + +exit: + action = e_attachment_view_get_action (view, "import-to-calendar"); + gtk_action_set_visible (action, is_vevent); + + action = e_attachment_view_get_action (view, "import-to-tasks"); + gtk_action_set_visible (action, is_vtodo); + + g_list_foreach (selected, (GFunc) g_object_unref, NULL); + g_list_free (selected); +} + +static void +cal_attachment_handler_constructed (GObject *object) +{ + EAttachmentHandler *handler; + EAttachmentView *view; + GtkActionGroup *action_group; + GtkUIManager *ui_manager; + GError *error = NULL; + + handler = E_ATTACHMENT_HANDLER (object); + + /* Chain up to parent's constructed() method. */ + G_OBJECT_CLASS (parent_class)->constructed (object); + + view = e_attachment_handler_get_view (handler); + + action_group = e_attachment_view_add_action_group (view, "calendar"); + gtk_action_group_add_actions ( + action_group, standard_entries, + G_N_ELEMENTS (standard_entries), handler); + + ui_manager = e_attachment_view_get_ui_manager (view); + gtk_ui_manager_add_ui_from_string (ui_manager, ui, -1, &error); + + if (error != NULL) { + g_warning ("%s", error->message); + g_error_free (error); + } + + g_signal_connect ( + view, "update_actions", + G_CALLBACK (cal_attachment_handler_update_actions), + NULL); +} + +static void +cal_attachment_handler_class_init (ECalAttachmentHandlerClass *class) +{ + GObjectClass *object_class; + + parent_class = g_type_class_peek_parent (class); + g_type_class_add_private (class, sizeof (ECalAttachmentHandlerPrivate)); + + object_class = G_OBJECT_CLASS (class); + object_class->constructed = cal_attachment_handler_constructed; +} + +static void +cal_attachment_handler_init (ECalAttachmentHandler *handler) +{ + handler->priv = E_CAL_ATTACHMENT_HANDLER_GET_PRIVATE (handler); +} + +GType +e_cal_attachment_handler_get_type (void) +{ + return cal_attachment_handler_type; +} + +void +e_cal_attachment_handler_register_type (GTypeModule *type_module) +{ + static const GTypeInfo type_info = { + sizeof (ECalAttachmentHandlerClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) cal_attachment_handler_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + sizeof (ECalAttachmentHandler), + 0, /* n_preallocs */ + (GInstanceInitFunc) cal_attachment_handler_init, + NULL /* value_table */ + }; + + cal_attachment_handler_type = g_type_module_register_type ( + type_module, E_TYPE_ATTACHMENT_HANDLER, + "ECalAttachmentHandler", &type_info, 0); +} diff --git a/modules/calendar/e-cal-attachment-handler.h b/modules/calendar/e-cal-attachment-handler.h new file mode 100644 index 0000000000..b792fbf765 --- /dev/null +++ b/modules/calendar/e-cal-attachment-handler.h @@ -0,0 +1,67 @@ +/* + * e-cal-attachment-handler.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/> + * + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifndef E_CAL_ATTACHMENT_HANDLER_H +#define E_CAL_ATTACHMENT_HANDLER_H + +#include <misc/e-attachment-handler.h> + +/* Standard GObject macros */ +#define E_TYPE_CAL_ATTACHMENT_HANDLER \ + (e_cal_attachment_handler_get_type ()) +#define E_CAL_ATTACHMENT_HANDLER(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_CAL_ATTACHMENT_HANDLER, ECalAttachmentHandler)) +#define E_CAL_ATTACHMENT_HANDLER_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), E_TYPE_CAL_ATTACHMENT_HANDLER, ECalAttachmentHandlerClass)) +#define E_IS_CAL_ATTACHMENT_HANDLER(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_CAL_ATTACHMENT_HANDLER)) +#define E_IS_CAL_ATTACHMENT_HANDLER_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), E_TYPE_CAL_ATTACHMENT_HANDLER)) +#define E_CAL_ATTACHMENT_HANDLER_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), E_TYPE_CAL_ATTACHMENT_HANDLER, ECalAttachmentHandlerClass)) + +G_BEGIN_DECLS + +typedef struct _ECalAttachmentHandler ECalAttachmentHandler; +typedef struct _ECalAttachmentHandlerClass ECalAttachmentHandlerClass; +typedef struct _ECalAttachmentHandlerPrivate ECalAttachmentHandlerPrivate; + +struct _ECalAttachmentHandler { + EAttachmentHandler parent; + ECalAttachmentHandlerPrivate *priv; +}; + +struct _ECalAttachmentHandlerClass { + EAttachmentHandlerClass parent_class; +}; + +GType e_cal_attachment_handler_get_type (void); +void e_cal_attachment_handler_register_type + (GTypeModule *type_module); + +G_END_DECLS + +#endif /* E_CAL_ATTACHMENT_HANDLER_H */ diff --git a/modules/calendar/e-cal-config-hook.c b/modules/calendar/e-cal-config-hook.c new file mode 100644 index 0000000000..4a0522460c --- /dev/null +++ b/modules/calendar/e-cal-config-hook.c @@ -0,0 +1,68 @@ +/* + * e-cal-config-hook.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/> + * + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#include "e-cal-config-hook.h" + +#include "e-util/e-config.h" +#include "calendar/gui/e-cal-config.h" + +static const EConfigHookTargetMask no_masks[] = { + { NULL } +}; + +static const EConfigHookTargetMap targets[] = { + { "source", EC_CONFIG_TARGET_SOURCE, no_masks }, + { "prefs", EC_CONFIG_TARGET_PREFS, no_masks }, + { NULL } +}; + +static void +cal_config_hook_class_init (EPluginHookClass *class) +{ + gint ii; + + class->id = "org.gnome.evolution.calendar.config:1.0"; + + for (ii = 0; targets[ii].type != NULL; ii++) + e_config_hook_class_add_target_map ( + (EConfigHookClass *) class, &targets[ii]); +} + +void +e_cal_config_hook_register_type (GTypeModule *type_module) +{ + const GTypeInfo type_info = { + sizeof (EConfigHookClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) cal_config_hook_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + sizeof (EConfigHook), + 0, /* n_preallocs */ + (GInstanceInitFunc) NULL, + NULL /* value_table */ + }; + + g_type_module_register_type ( + type_module, e_config_hook_get_type (), + "ECalConfigHook", &type_info, 0); +} diff --git a/modules/calendar/e-cal-config-hook.h b/modules/calendar/e-cal-config-hook.h new file mode 100644 index 0000000000..a22ec56bbc --- /dev/null +++ b/modules/calendar/e-cal-config-hook.h @@ -0,0 +1,33 @@ +/* + * e-cal-config-hook.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/> + * + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifndef E_CAL_CONFIG_HOOK_H +#define E_CAL_CONFIG_HOOK_H + +#include <glib-object.h> + +G_BEGIN_DECLS + +void e_cal_config_hook_register_type (GTypeModule *type_module); + +G_END_DECLS + +#endif /* E_CAL_CONFIG_HOOK_H */ diff --git a/modules/calendar/e-cal-event-hook.c b/modules/calendar/e-cal-event-hook.c new file mode 100644 index 0000000000..b263727107 --- /dev/null +++ b/modules/calendar/e-cal-event-hook.c @@ -0,0 +1,72 @@ +/* + * e-cal-event-hook.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/> + * + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#include "e-cal-event-hook.h" + +#include "e-util/e-event.h" +#include "calendar/gui/e-cal-event.h" + +static const EEventHookTargetMask masks[] = { + { "migration", E_CAL_EVENT_MODULE_MIGRATION }, + { NULL } +}; + +static const EEventHookTargetMap targets[] = { + { "module", E_CAL_EVENT_TARGET_BACKEND, masks }, + { NULL } +}; + +static void +cal_event_hook_class_init (EPluginHookClass *class) +{ + EEventHookClass *event_hook_class; + gint ii; + + event_hook_class = (EEventHookClass *) class; + event_hook_class->event = (EEvent *) e_cal_event_peek (); + + class->id = "org.gnome.evolution.calendar.events:1.0"; + + for (ii = 0; targets[ii].type != NULL; ii++) + e_event_hook_class_add_target_map ( + (EEventHookClass *) class, &targets[ii]); +} + +void +e_cal_event_hook_register_type (GTypeModule *type_module) +{ + const GTypeInfo type_info = { + sizeof (EEventHookClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) cal_event_hook_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + sizeof (EEventHook), + 0, /* n_preallocs */ + (GInstanceInitFunc) NULL, + NULL /* value_table */ + }; + + g_type_module_register_type ( + type_module, e_event_hook_get_type (), + "ECalEventHook", &type_info, 0); +} diff --git a/modules/calendar/e-cal-event-hook.h b/modules/calendar/e-cal-event-hook.h new file mode 100644 index 0000000000..9dde31f900 --- /dev/null +++ b/modules/calendar/e-cal-event-hook.h @@ -0,0 +1,33 @@ +/* + * e-cal-event-hook.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/> + * + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifndef E_CAL_EVENT_HOOK_H +#define E_CAL_EVENT_HOOK_H + +#include <glib-object.h> + +G_BEGIN_DECLS + +void e_cal_event_hook_register_type (GTypeModule *type_module); + +G_END_DECLS + +#endif /* E_CAL_EVENT_HOOK_H */ diff --git a/modules/calendar/e-cal-shell-backend.c b/modules/calendar/e-cal-shell-backend.c index 6d9c74411b..5149574323 100644 --- a/modules/calendar/e-cal-shell-backend.c +++ b/modules/calendar/e-cal-shell-backend.c @@ -38,9 +38,6 @@ #include "calendar/common/authentication.h" #include "calendar/gui/calendar-config.h" #include "calendar/gui/comp-util.h" -#include "calendar/gui/e-attachment-handler-calendar.h" -#include "calendar/gui/e-cal-config.h" -#include "calendar/gui/e-cal-event.h" #include "calendar/gui/dialogs/cal-prefs-dialog.h" #include "calendar/gui/dialogs/calendar-setup.h" #include "calendar/gui/dialogs/event-editor.h" @@ -509,13 +506,6 @@ static GtkActionEntry source_entries[] = { }; static void -cal_shell_backend_init_hooks (void) -{ - e_plugin_hook_register_type (e_cal_config_hook_get_type ()); - e_plugin_hook_register_type (e_cal_event_hook_get_type ()); -} - -static void cal_shell_backend_init_importers (void) { EImportClass *import_class; @@ -778,15 +768,12 @@ cal_shell_backend_constructed (GObject *object) G_CALLBACK (cal_shell_backend_window_created_cb), shell_backend); - cal_shell_backend_init_hooks (); cal_shell_backend_init_importers (); /* Initialize settings before initializing preferences, * since the preferences bind to the shell settings. */ e_cal_shell_backend_init_settings (shell); cal_shell_backend_init_preferences (shell); - - e_attachment_handler_calendar_get_type (); } static void diff --git a/modules/calendar/evolution-module-calendar.c b/modules/calendar/evolution-module-calendar.c index 63bf98ead9..f72e8a97e4 100644 --- a/modules/calendar/evolution-module-calendar.c +++ b/modules/calendar/evolution-module-calendar.c @@ -19,6 +19,11 @@ * */ +#include "e-cal-attachment-handler.h" + +#include "e-cal-config-hook.h" +#include "e-cal-event-hook.h" + #include "e-cal-shell-backend.h" #include "e-cal-shell-content.h" #include "e-cal-shell-sidebar.h" @@ -43,6 +48,11 @@ e_module_load (GTypeModule *type_module) { /* Register dynamically loaded types. */ + e_cal_attachment_handler_register_type (type_module); + + e_cal_config_hook_register_type (type_module); + e_cal_event_hook_register_type (type_module); + e_cal_shell_backend_register_type (type_module); e_cal_shell_content_register_type (type_module); e_cal_shell_sidebar_register_type (type_module); diff --git a/modules/mail/Makefile.am b/modules/mail/Makefile.am index 866a137b08..462161843c 100644 --- a/modules/mail/Makefile.am +++ b/modules/mail/Makefile.am @@ -12,8 +12,14 @@ module_LTLIBRARIES = libevolution-module-mail.la libevolution_module_mail_la_SOURCES = \ evolution-module-mail.c \ - e-attachment-handler-mail.c \ - e-attachment-handler-mail.h \ + e-mail-attachment-handler.c \ + e-mail-attachment-handler.h \ + e-mail-config-hook.c \ + e-mail-config-hook.h \ + e-mail-event-hook.c \ + e-mail-event-hook.h \ + e-mail-junk-hook.c \ + e-mail-junk-hook.h \ e-mail-shell-backend.c \ e-mail-shell-backend.h \ e-mail-shell-content.c \ diff --git a/modules/mail/e-attachment-handler-mail.h b/modules/mail/e-attachment-handler-mail.h deleted file mode 100644 index c62ea99cab..0000000000 --- a/modules/mail/e-attachment-handler-mail.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * e-attachment-handler-mail.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/> - * - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -#ifndef E_ATTACHMENT_HANDLER_MAIL_H -#define E_ATTACHMENT_HANDLER_MAIL_H - -#include <widgets/misc/e-attachment-handler.h> - -/* Standard GObject macros */ -#define E_TYPE_ATTACHMENT_HANDLER_MAIL \ - (e_attachment_handler_mail_get_type ()) -#define E_ATTACHMENT_HANDLER_MAIL(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST \ - ((obj), E_TYPE_ATTACHMENT_HANDLER_MAIL, EAttachmentHandlerMail)) -#define E_ATTACHMENT_HANDLER_MAIL_CLASS(cls) \ - (G_TYPE_CHECK_CLASS_CAST \ - ((cls), E_TYPE_ATTACHMENT_HANDLER_MAIL, EAttachmentHandlerMailClass)) -#define E_IS_ATTACHMENT_HANDLER_MAIL(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE \ - ((obj), E_TYPE_ATTACHMENT_HANDLER_MAIL)) -#define E_IS_ATTACHMENT_HANDLER_MAIL_CLASS(cls) \ - (G_TYPE_CHECK_CLASS_TYPE \ - ((cls), E_TYPE_ATTACHMENT_HANDLER_MAIL)) -#define E_ATTACHMENT_HANDLER_MAIL_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS \ - ((obj), E_TYPE_ATTACHMENT_HANDLER_MAIL, EAttachmentHandlerMailClass)) - -G_BEGIN_DECLS - -typedef struct _EAttachmentHandlerMail EAttachmentHandlerMail; -typedef struct _EAttachmentHandlerMailClass EAttachmentHandlerMailClass; -typedef struct _EAttachmentHandlerMailPrivate EAttachmentHandlerMailPrivate; - -struct _EAttachmentHandlerMail { - EAttachmentHandler parent; - EAttachmentHandlerMailPrivate *priv; -}; - -struct _EAttachmentHandlerMailClass { - EAttachmentHandlerClass parent_class; -}; - -GType e_attachment_handler_mail_get_type (void); - -G_END_DECLS - -#endif /* E_ATTACHMENT_HANDLER_MAIL_H */ diff --git a/modules/mail/e-attachment-handler-mail.c b/modules/mail/e-mail-attachment-handler.c index c17c97d8ca..91fe5d3e5f 100644 --- a/modules/mail/e-attachment-handler-mail.c +++ b/modules/mail/e-mail-attachment-handler.c @@ -1,5 +1,5 @@ /* - * e-attachment-handler-mail.c + * e-mail-attachment-handler.c * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -19,7 +19,7 @@ * */ -#include "e-attachment-handler-mail.h" +#include "e-mail-attachment-handler.h" #include <glib/gi18n.h> #include <camel/camel-folder.h> @@ -29,15 +29,16 @@ #include "mail/em-composer-utils.h" #include "mail/mail-tools.h" -#define E_ATTACHMENT_HANDLER_MAIL_GET_PRIVATE(obj) \ +#define E_MAIL_ATTACHMENT_HANDLER_GET_PRIVATE(obj) \ (G_TYPE_INSTANCE_GET_PRIVATE \ - ((obj), E_TYPE_ATTACHMENT_HANDLER_MAIL, EAttachmentHandlerMailPrivate)) + ((obj), E_TYPE_MAIL_ATTACHMENT_HANDLER, EMailAttachmentHandlerPrivate)) -struct _EAttachmentHandlerMailPrivate { +struct _EMailAttachmentHandlerPrivate { gint placeholder; }; static gpointer parent_class; +static GType mail_attachment_handler_type; static const gchar *ui = "<ui>" @@ -57,7 +58,7 @@ static GtkTargetEntry target_table[] = { }; static void -attachment_handler_mail_forward (GtkAction *action, +mail_attachment_handler_forward (GtkAction *action, EAttachmentView *view) { EAttachment *attachment; @@ -79,7 +80,7 @@ attachment_handler_mail_forward (GtkAction *action, } static void -attachment_handler_mail_reply_all (GtkAction *action, +mail_attachment_handler_reply_all (GtkAction *action, EAttachmentView *view) { EAttachment *attachment; @@ -103,7 +104,7 @@ attachment_handler_mail_reply_all (GtkAction *action, } static void -attachment_handler_mail_reply_sender (GtkAction *action, +mail_attachment_handler_reply_sender (GtkAction *action, EAttachmentView *view) { EAttachment *attachment; @@ -133,25 +134,25 @@ static GtkActionEntry standard_entries[] = { N_("_Forward"), NULL, NULL, /* XXX Add a tooltip! */ - G_CALLBACK (attachment_handler_mail_forward) }, + G_CALLBACK (mail_attachment_handler_forward) }, { "mail-reply-all", "mail-reply-all", N_("Reply to _All"), NULL, NULL, /* XXX Add a tooltip! */ - G_CALLBACK (attachment_handler_mail_reply_all) }, + G_CALLBACK (mail_attachment_handler_reply_all) }, { "mail-reply-sender", "mail-reply-sender", N_("_Reply to Sender"), NULL, NULL, /* XXX Add a tooltip! */ - G_CALLBACK (attachment_handler_mail_reply_sender) } + G_CALLBACK (mail_attachment_handler_reply_sender) } }; static void -attachment_handler_mail_message_rfc822 (EAttachmentView *view, +mail_attachment_handler_message_rfc822 (EAttachmentView *view, GdkDragContext *drag_context, gint x, gint y, @@ -213,7 +214,7 @@ exit: } static void -attachment_handler_mail_x_uid_list (EAttachmentView *view, +mail_attachment_handler_x_uid_list (EAttachmentView *view, GdkDragContext *drag_context, gint x, gint y, @@ -380,7 +381,7 @@ exit: } static void -attachment_handler_mail_update_actions (EAttachmentView *view) +mail_attachment_handler_update_actions (EAttachmentView *view) { EAttachment *attachment; CamelMimePart *mime_part; @@ -413,7 +414,7 @@ exit: } static void -attachment_handler_mail_constructed (GObject *object) +mail_attachment_handler_constructed (GObject *object) { EAttachmentHandler *handler; EAttachmentView *view; @@ -443,28 +444,28 @@ attachment_handler_mail_constructed (GObject *object) g_signal_connect ( view, "update-actions", - G_CALLBACK (attachment_handler_mail_update_actions), + G_CALLBACK (mail_attachment_handler_update_actions), NULL); g_signal_connect ( view, "drag-data-received", - G_CALLBACK (attachment_handler_mail_message_rfc822), + G_CALLBACK (mail_attachment_handler_message_rfc822), NULL); g_signal_connect ( view, "drag-data-received", - G_CALLBACK (attachment_handler_mail_x_uid_list), + G_CALLBACK (mail_attachment_handler_x_uid_list), NULL); } static GdkDragAction -attachment_handler_mail_get_drag_actions (EAttachmentHandler *handler) +mail_attachment_handler_get_drag_actions (EAttachmentHandler *handler) { return GDK_ACTION_COPY; } static const GtkTargetEntry * -attachment_handler_mail_get_target_table (EAttachmentHandler *handler, +mail_attachment_handler_get_target_table (EAttachmentHandler *handler, guint *n_targets) { if (n_targets != NULL) @@ -474,51 +475,51 @@ attachment_handler_mail_get_target_table (EAttachmentHandler *handler, } static void -attachment_handler_mail_class_init (EAttachmentHandlerMailClass *class) +mail_attachment_handler_class_init (EMailAttachmentHandlerClass *class) { GObjectClass *object_class; EAttachmentHandlerClass *handler_class; parent_class = g_type_class_peek_parent (class); - g_type_class_add_private (class, sizeof (EAttachmentHandlerMailPrivate)); + g_type_class_add_private (class, sizeof (EMailAttachmentHandlerPrivate)); object_class = G_OBJECT_CLASS (class); - object_class->constructed = attachment_handler_mail_constructed; + object_class->constructed = mail_attachment_handler_constructed; handler_class = E_ATTACHMENT_HANDLER_CLASS (class); - handler_class->get_drag_actions = attachment_handler_mail_get_drag_actions; - handler_class->get_target_table = attachment_handler_mail_get_target_table; + handler_class->get_drag_actions = mail_attachment_handler_get_drag_actions; + handler_class->get_target_table = mail_attachment_handler_get_target_table; } static void -attachment_handler_mail_init (EAttachmentHandlerMail *handler) +mail_attachment_handler_init (EMailAttachmentHandler *handler) { - handler->priv = E_ATTACHMENT_HANDLER_MAIL_GET_PRIVATE (handler); + handler->priv = E_MAIL_ATTACHMENT_HANDLER_GET_PRIVATE (handler); } GType -e_attachment_handler_mail_get_type (void) +e_mail_attachment_handler_get_type (void) { - static GType type = 0; - - if (G_UNLIKELY (type == 0)) { - static const GTypeInfo type_info = { - sizeof (EAttachmentHandlerMailClass), - (GBaseInitFunc) NULL, - (GBaseFinalizeFunc) NULL, - (GClassInitFunc) attachment_handler_mail_class_init, - (GClassFinalizeFunc) NULL, - NULL, /* class_data */ - sizeof (EAttachmentHandlerMail), - 0, /* n_preallocs */ - (GInstanceInitFunc) attachment_handler_mail_init, - NULL /* value_table */ - }; - - type = g_type_register_static ( - E_TYPE_ATTACHMENT_HANDLER, - "EAttachmentHandlerMail", &type_info, 0); - } + return mail_attachment_handler_type; +} - return type; +void +e_mail_attachment_handler_register_type (GTypeModule *type_module) +{ + static const GTypeInfo type_info = { + sizeof (EMailAttachmentHandlerClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) mail_attachment_handler_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + sizeof (EMailAttachmentHandler), + 0, /* n_preallocs */ + (GInstanceInitFunc) mail_attachment_handler_init, + NULL /* value_table */ + }; + + mail_attachment_handler_type = g_type_module_register_type ( + type_module, E_TYPE_ATTACHMENT_HANDLER, + "EMailAttachmentHandler", &type_info, 0); } diff --git a/modules/mail/e-mail-attachment-handler.h b/modules/mail/e-mail-attachment-handler.h new file mode 100644 index 0000000000..13032b488c --- /dev/null +++ b/modules/mail/e-mail-attachment-handler.h @@ -0,0 +1,67 @@ +/* + * e-mail-attachment-handler.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/> + * + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifndef E_MAIL_ATTACHMENT_HANDLER_H +#define E_MAIL_ATTACHMENT_HANDLER_H + +#include <widgets/misc/e-attachment-handler.h> + +/* Standard GObject macros */ +#define E_TYPE_MAIL_ATTACHMENT_HANDLER \ + (e_mail_attachment_handler_get_type ()) +#define E_MAIL_ATTACHMENT_HANDLER(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_MAIL_ATTACHMENT_HANDLER, EMailAttachmentHandler)) +#define E_MAIL_ATTACHMENT_HANDLER_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), E_TYPE_MAIL_ATTACHMENT_HANDLER, EMailAttachmentHandlerClass)) +#define E_IS_MAIL_ATTACHMENT_HANDLER(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_MAIL_ATTACHMENT_HANDLER)) +#define E_IS_MAIL_ATTACHMENT_HANDLER_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), E_TYPE_MAIL_ATTACHMENT_HANDLER)) +#define E_MAIL_ATTACHMENT_HANDLER_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), E_TYPE_MAIL_ATTACHMENT_HANDLER, EMailAttachmentHandlerClass)) + +G_BEGIN_DECLS + +typedef struct _EMailAttachmentHandler EMailAttachmentHandler; +typedef struct _EMailAttachmentHandlerClass EMailAttachmentHandlerClass; +typedef struct _EMailAttachmentHandlerPrivate EMailAttachmentHandlerPrivate; + +struct _EMailAttachmentHandler { + EAttachmentHandler parent; + EMailAttachmentHandlerPrivate *priv; +}; + +struct _EMailAttachmentHandlerClass { + EAttachmentHandlerClass parent_class; +}; + +GType e_mail_attachment_handler_get_type (void); +void e_mail_attachment_handler_register_type + (GTypeModule *type_module); + +G_END_DECLS + +#endif /* E_MAIL_ATTACHMENT_HANDLER_H */ diff --git a/modules/mail/e-mail-config-hook.c b/modules/mail/e-mail-config-hook.c new file mode 100644 index 0000000000..4b37a6b171 --- /dev/null +++ b/modules/mail/e-mail-config-hook.c @@ -0,0 +1,69 @@ +/* + * e-mail-config-hook.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/> + * + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#include "e-mail-config-hook.h" + +#include "e-util/e-config.h" +#include "mail/em-config.h" + +static const EConfigHookTargetMask no_masks[] = { + { NULL } +}; + +static const EConfigHookTargetMap targets[] = { + { "folder", EM_CONFIG_TARGET_FOLDER, no_masks }, + { "prefs", EM_CONFIG_TARGET_PREFS, no_masks }, + { "account", EM_CONFIG_TARGET_ACCOUNT, no_masks }, + { NULL } +}; + +static void +mail_config_hook_class_init (EPluginHookClass *class) +{ + gint ii; + + class->id = "org.gnome.evolution.mail.config:1.0"; + + for (ii = 0; targets[ii].type != NULL; ii++) + e_config_hook_class_add_target_map ( + (EConfigHookClass *) class, &targets[ii]); +} + +void +e_mail_config_hook_register_type (GTypeModule *type_module) +{ + const GTypeInfo type_info = { + sizeof (EConfigHookClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) mail_config_hook_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + sizeof (EConfigHook), + 0, /* n_preallocs */ + (GInstanceInitFunc) NULL, + NULL /* value_table */ + }; + + g_type_module_register_type ( + type_module, e_config_hook_get_type (), + "EMailConfigHook", &type_info, 0); +} diff --git a/modules/mail/e-mail-config-hook.h b/modules/mail/e-mail-config-hook.h new file mode 100644 index 0000000000..e54ad81815 --- /dev/null +++ b/modules/mail/e-mail-config-hook.h @@ -0,0 +1,33 @@ +/* + * e-mail-config-hook.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/> + * + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifndef E_MAIL_CONFIG_HOOK_H +#define E_MAIL_CONFIG_HOOK_H + +#include <glib-object.h> + +G_BEGIN_DECLS + +void e_mail_config_hook_register_type (GTypeModule *type_module); + +G_END_DECLS + +#endif /* E_MAIL_CONFIG_HOOK_H */ diff --git a/modules/mail/e-mail-event-hook.c b/modules/mail/e-mail-event-hook.c new file mode 100644 index 0000000000..a6be6d294f --- /dev/null +++ b/modules/mail/e-mail-event-hook.c @@ -0,0 +1,93 @@ +/* + * e-mail-event-hook.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/> + * + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#include "e-mail-event-hook.h" + +#include "e-util/e-event.h" +#include "mail/em-event.h" + +static const EEventHookTargetMask folder_masks[] = { + { "newmail", EM_EVENT_FOLDER_NEWMAIL }, + { NULL } +}; + +static const EEventHookTargetMask composer_masks[] = { + { "sendoption", EM_EVENT_COMPOSER_SEND_OPTION }, + { NULL } +}; + +static const EEventHookTargetMask message_masks[] = { + { "replyall", EM_EVENT_MESSAGE_REPLY_ALL }, + { "reply", EM_EVENT_MESSAGE_REPLY }, + { NULL } +}; + +static const EEventHookTargetMask send_receive_masks[] = { + { "sendreceive", EM_EVENT_SEND_RECEIVE }, + { NULL } +}; + +static const EEventHookTargetMask custom_icon_masks[] = { + { "customicon", EM_EVENT_CUSTOM_ICON }, + { NULL } +}; + +static const EEventHookTargetMap targets[] = { + { "folder", EM_EVENT_TARGET_FOLDER, folder_masks }, + { "message", EM_EVENT_TARGET_MESSAGE, message_masks }, + { "composer", EM_EVENT_TARGET_COMPOSER, composer_masks }, + { "sendreceive", EM_EVENT_TARGET_SEND_RECEIVE, send_receive_masks }, + { "customicon", EM_EVENT_TARGET_CUSTOM_ICON, custom_icon_masks }, + { NULL } +}; + +static void +mail_event_hook_class_init (EPluginHookClass *class) +{ + gint ii; + + class->id = "org.gnome.evolution.mail.events:1.0"; + + for (ii = 0; targets[ii].type != NULL; ii++) + e_event_hook_class_add_target_map ( + (EEventHookClass *) class, &targets[ii]); +} + +void +e_mail_event_hook_register_type (GTypeModule *type_module) +{ + const GTypeInfo type_info = { + sizeof (EEventHookClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) mail_event_hook_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + sizeof (EEventHook), + 0, /* n_preallocs */ + (GInstanceInitFunc) NULL, + NULL /* value_table */ + }; + + g_type_module_register_type ( + type_module, e_event_hook_get_type (), + "EMailEventHook", &type_info, 0); +} diff --git a/modules/mail/e-mail-event-hook.h b/modules/mail/e-mail-event-hook.h new file mode 100644 index 0000000000..9cad43a0c2 --- /dev/null +++ b/modules/mail/e-mail-event-hook.h @@ -0,0 +1,33 @@ +/* + * e-mail-event-hook.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/> + * + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifndef E_MAIL_EVENT_HOOK_H +#define E_MAIL_EVENT_HOOK_H + +#include <glib-object.h> + +G_BEGIN_DECLS + +void e_mail_event_hook_register_type (GTypeModule *type_module); + +G_END_DECLS + +#endif /* E_MAIL_EVENT_HOOK_H */ diff --git a/modules/mail/e-mail-junk-hook.c b/modules/mail/e-mail-junk-hook.c new file mode 100644 index 0000000000..2687223af9 --- /dev/null +++ b/modules/mail/e-mail-junk-hook.c @@ -0,0 +1,323 @@ +/* + * e-mail-junk-hook.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/> + * + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#include "e-mail-junk-hook.h" + +#include <glib/gi18n.h> +#include <camel/camel-junk-plugin.h> + +#include "e-util/e-error.h" +#include "mail/em-junk.h" +#include "mail/em-utils.h" +#include "mail/mail-session.h" + +#define E_MAIL_JUNK_HOOK_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE \ + ((obj), E_TYPE_MAIL_JUNK_HOOK, EMailJunkHookPrivate)) + +struct _EMailJunkHookPrivate { + EMJunkInterface interface; +}; + +struct ErrorData { + const gchar *error_message; + GError *error; +}; + +static gpointer parent_class; +static GType mail_junk_hook_type; + +static gboolean +mail_junk_hook_idle_cb (struct ErrorData *data) +{ + GtkWidget *widget; + + widget = e_error_new ( + NULL, data->error_message, data->error->message, NULL); + em_utils_show_error_silent (widget); + + g_error_free (data->error); + g_slice_free (struct ErrorData, data); + + return FALSE; +} + +static void +mail_junk_hook_error (const gchar *error_message, + GError *error) +{ + struct ErrorData *data; + + g_return_if_fail (error != NULL); + + data = g_slice_new (struct ErrorData); + data->error_message = error_message; + data->error = error; + + g_idle_add ((GSourceFunc) mail_junk_hook_idle_cb, data); +} + +static const gchar * +mail_junk_hook_get_name (CamelJunkPlugin *junk_plugin) +{ + EMJunkInterface *interface; + + interface = (EMJunkInterface *) junk_plugin; + + if (!interface->hook->plugin->enabled) + return _("None"); + + return interface->hook->plugin->name; +} + +static void +mail_junk_hook_plugin_init (CamelJunkPlugin *junk_plugin) +{ + EMJunkInterface *interface; + EPluginClass *class; + + interface = (EMJunkInterface *) junk_plugin; + + class = E_PLUGIN_GET_CLASS (interface->hook->plugin); + g_return_if_fail (class->enable != NULL); + + class->enable (interface->hook->plugin, 1); +} + +static gboolean +mail_junk_hook_check_junk (CamelJunkPlugin *junk_plugin, + CamelMimeMessage *mime_message) +{ + EMJunkTarget target = { mime_message, NULL }; + EMJunkInterface *interface; + gpointer result; + + interface = (EMJunkInterface *) junk_plugin; + + if (!interface->hook->plugin->enabled) + return FALSE; + + result = e_plugin_invoke ( + interface->hook->plugin, + interface->check_junk, &target); + + if (target.error != NULL) + mail_junk_hook_error ("mail:junk-check-error", target.error); + + return (result != NULL); +} + +static void +mail_junk_hook_report_junk (CamelJunkPlugin *junk_plugin, + CamelMimeMessage *mime_message) +{ + EMJunkTarget target = { mime_message, NULL }; + EMJunkInterface *interface; + + interface = (EMJunkInterface *) junk_plugin; + + if (!interface->hook->plugin->enabled) + return; + + e_plugin_invoke ( + interface->hook->plugin, + interface->report_junk, &target); + + if (target.error != NULL) + mail_junk_hook_error ("mail:junk-report-error", target.error); +} + +static void +mail_junk_hook_report_notjunk (CamelJunkPlugin *junk_plugin, + CamelMimeMessage *mime_message) +{ + EMJunkTarget target = { mime_message, NULL }; + EMJunkInterface *interface; + + interface = (EMJunkInterface *) junk_plugin; + + if (!interface->hook->plugin->enabled) + return; + + e_plugin_invoke ( + interface->hook->plugin, + interface->report_notjunk, &target); + + if (target.error != NULL) + mail_junk_hook_error ( + "mail:junk-not-report-error", target.error); +} + +static void +mail_junk_hook_commit_reports (CamelJunkPlugin *junk_plugin) +{ + EMJunkInterface *interface; + + interface = (EMJunkInterface *) junk_plugin; + + if (!interface->hook->plugin->enabled) + return; + + e_plugin_invoke ( + interface->hook->plugin, + interface->commit_reports, NULL); +} + +static void +mail_junk_hook_finalize (GObject *object) +{ + EMailJunkHookPrivate *priv; + + priv = E_MAIL_JUNK_HOOK_GET_PRIVATE (object); + + g_free (priv->interface.check_junk); + g_free (priv->interface.report_junk); + g_free (priv->interface.report_notjunk); + g_free (priv->interface.commit_reports); + g_free (priv->interface.validate_binary); + g_free (priv->interface.plugin_name); + + /* Chain up to parent's finalize() method. */ + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static gint +mail_junk_hook_construct (EPluginHook *hook, + EPlugin *plugin, + xmlNodePtr node) +{ + EMailJunkHookPrivate *priv; + gchar *property; + + priv = E_MAIL_JUNK_HOOK_GET_PRIVATE (hook); + + /* Chain up to parent's construct() method. */ + if (E_PLUGIN_HOOK_CLASS (parent_class)->construct (hook, plugin, node) == -1) + return -1; + + if (!plugin->enabled) + return -1; + + node = xmlFirstElementChild (node); + + if (node == NULL) + return -1; + + if (g_strcmp0 ((gchar *) node->name, "interface") != 0) + return -1; + + property = e_plugin_xml_prop (node, "check_junk"); + priv->interface.check_junk = property; + + property = e_plugin_xml_prop (node, "report_junk"); + priv->interface.report_junk = property; + + property = e_plugin_xml_prop (node, "report_non_junk"); + priv->interface.report_notjunk = property; + + property = e_plugin_xml_prop (node, "commit_reports"); + priv->interface.commit_reports = property; + + property = e_plugin_xml_prop (node, "validate_binary"); + priv->interface.validate_binary = property; + + property = e_plugin_xml_prop (node, "name"); + priv->interface.plugin_name = property; + + if (priv->interface.check_junk == NULL) + return -1; + + if (priv->interface.report_junk == NULL) + return -1; + + if (priv->interface.report_notjunk == NULL) + return -1; + + if (priv->interface.commit_reports == NULL) + return -1; + + mail_session_add_junk_plugin ( + priv->interface.plugin_name, &priv->interface.camel); + + return 0; +} + +static void +mail_junk_hook_class_init (EMailJunkHookClass *class) +{ + GObjectClass *object_class; + EPluginHookClass *plugin_hook_class; + + parent_class = g_type_class_peek_parent (class); + g_type_class_add_private (class, sizeof (EMailJunkHookPrivate)); + + object_class = G_OBJECT_CLASS (class); + object_class->finalize = mail_junk_hook_finalize; + + plugin_hook_class = E_PLUGIN_HOOK_CLASS (class); + plugin_hook_class->construct = mail_junk_hook_construct; + plugin_hook_class->id = "org.gnome.evolution.mail.junk:1.0"; +} + +static void +mail_junk_hook_init (EMailJunkHook *mail_junk_hook) +{ + EMJunkInterface *interface; + + mail_junk_hook->priv = E_MAIL_JUNK_HOOK_GET_PRIVATE (mail_junk_hook); + + interface = &mail_junk_hook->priv->interface; + interface->camel.get_name = mail_junk_hook_get_name; + interface->camel.api_version = 1; + interface->camel.check_junk = mail_junk_hook_check_junk; + interface->camel.report_junk = mail_junk_hook_report_junk; + interface->camel.report_notjunk = mail_junk_hook_report_notjunk; + interface->camel.commit_reports = mail_junk_hook_commit_reports; + interface->camel.init = mail_junk_hook_plugin_init; + interface->hook = E_PLUGIN_HOOK (mail_junk_hook); +} + +GType +e_mail_junk_hook_get_type (void) +{ + return mail_junk_hook_type; +} + +void +e_mail_junk_hook_register_type (GTypeModule *type_module) +{ + const GTypeInfo type_info = { + sizeof (EMailJunkHookClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) mail_junk_hook_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + sizeof (EMailJunkHook), + 0, /* n_preallocs */ + (GInstanceInitFunc) mail_junk_hook_init, + NULL /* value_table */ + }; + + mail_junk_hook_type = g_type_module_register_type ( + type_module, E_TYPE_PLUGIN_HOOK, + "EMailJunkHook", &type_info, 0); +} diff --git a/modules/mail/e-mail-junk-hook.h b/modules/mail/e-mail-junk-hook.h new file mode 100644 index 0000000000..f5882e66b3 --- /dev/null +++ b/modules/mail/e-mail-junk-hook.h @@ -0,0 +1,66 @@ +/* + * e-mail-junk-hook.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/> + * + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifndef E_MAIL_JUNK_HOOK_H +#define E_MAIL_JUNK_HOOK_H + +#include <e-util/e-plugin.h> + +/* Standard GObject macros */ +#define E_TYPE_MAIL_JUNK_HOOK \ + (e_mail_junk_hook_get_type ()) +#define E_MAIL_JUNK_HOOK(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_MAIL_JUNK_HOOK, EMailJunkHook)) +#define E_MAIL_JUNK_HOOK_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), E_TYPE_MAIL_JUNK_HOOK, EMailJunkHookClass)) +#define E_IS_MAIL_JUNK_HOOK(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_MAIL_JUNK_HOOK)) +#define E_IS_MAIL_JUNK_HOOK_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), E_TYPE_MAIL_JUNK_HOOK)) +#define E_MAIL_JUNK_HOOK_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), E_TYPE_MAIL_JUNK_HOOK, EMailJunkHookClass)) + +G_BEGIN_DECLS + +typedef struct _EMailJunkHook EMailJunkHook; +typedef struct _EMailJunkHookClass EMailJunkHookClass; +typedef struct _EMailJunkHookPrivate EMailJunkHookPrivate; + +struct _EMailJunkHook { + EPluginHook parent; + EMailJunkHookPrivate *priv; +}; + +struct _EMailJunkHookClass { + EPluginHookClass parent_class; +}; + +GType e_mail_junk_hook_get_type (void); +void e_mail_junk_hook_register_type (GTypeModule *type_module); + +G_END_DECLS + +#endif /* E_MAIL_JUNK_HOOK_H */ diff --git a/modules/mail/e-mail-shell-backend.c b/modules/mail/e-mail-shell-backend.c index 2d6e1a9779..fd1e7263c4 100644 --- a/modules/mail/e-mail-shell-backend.c +++ b/modules/mail/e-mail-shell-backend.c @@ -42,7 +42,6 @@ #include "e-mail-shell-sidebar.h" #include "e-mail-shell-view.h" -#include "e-attachment-handler-mail.h" #include "e-mail-browser.h" #include "e-mail-local.h" #include "e-mail-reader.h" @@ -51,12 +50,9 @@ #include "em-account-prefs.h" #include "em-composer-prefs.h" #include "em-composer-utils.h" -#include "em-config.h" -#include "em-event.h" #include "em-folder-utils.h" #include "em-format-hook.h" #include "em-format-html-display.h" -#include "em-junk-hook.h" #include "em-mailer-prefs.h" #include "em-network-prefs.h" #include "em-utils.h" @@ -85,22 +81,6 @@ static GType mail_shell_backend_type; extern gint camel_application_is_exiting; static void -mail_shell_backend_init_hooks (void) -{ - e_plugin_hook_register_type (em_config_hook_get_type ()); - e_plugin_hook_register_type (em_event_hook_get_type ()); - e_plugin_hook_register_type (em_junk_hook_get_type ()); - - /* EMFormat classes must be registered before EMFormatHook. */ - em_format_hook_register_type (em_format_get_type ()); - em_format_hook_register_type (em_format_html_get_type ()); - em_format_hook_register_type (em_format_html_display_get_type ()); - e_plugin_hook_register_type (em_format_hook_get_type ()); - - em_junk_hook_register_type (emj_get_type ()); -} - -static void mail_shell_backend_init_importers (void) { EImportClass *import_class; @@ -812,10 +792,15 @@ mail_shell_backend_constructed (GObject *object) /* This also initializes Camel, so it needs to happen early. */ mail_session_init (shell_backend); - mail_shell_backend_init_hooks (); - mail_shell_backend_init_importers (); + /* Register format types for EMFormatHook. */ + em_format_hook_register_type (em_format_get_type ()); + em_format_hook_register_type (em_format_html_get_type ()); + em_format_hook_register_type (em_format_html_display_get_type ()); + + /* Register plugin hook types. */ + em_format_hook_get_type (); - e_attachment_handler_mail_get_type (); + mail_shell_backend_init_importers (); g_signal_connect ( shell, "notify::online", diff --git a/modules/mail/em-mailer-prefs.c b/modules/mail/em-mailer-prefs.c index e2c956e0ff..621dae4ce5 100644 --- a/modules/mail/em-mailer-prefs.c +++ b/modules/mail/em-mailer-prefs.c @@ -47,7 +47,7 @@ #include "e-mail-label-manager.h" #include "mail-config.h" -#include "em-junk-hook.h" +#include "em-junk.h" #include "em-config.h" #include "mail-session.h" @@ -710,17 +710,17 @@ junk_plugin_changed (GtkWidget *combo, EMMailerPrefs *prefs) gconf_client_set_string (prefs->gconf, "/apps/evolution/mail/junk/default_plugin", def_plugin, NULL); while (plugins) { - struct _EMJunkHookItem *item = plugins->data;; + EMJunkInterface *iface = plugins->data; - if (item->plugin_name && def_plugin && !strcmp (item->plugin_name, def_plugin)) { + if (iface->plugin_name && def_plugin && !strcmp (iface->plugin_name, def_plugin)) { gboolean status; - session->junk_plugin = CAMEL_JUNK_PLUGIN (&(item->csp)); - status = e_plugin_invoke (item->hook->hook.plugin, item->validate_binary, NULL) != NULL; + session->junk_plugin = CAMEL_JUNK_PLUGIN (&iface->camel); + status = e_plugin_invoke (iface->hook->plugin, iface->validate_binary, NULL) != NULL; if ((gboolean)status == TRUE) { gchar *text, *html; gtk_image_set_from_stock (prefs->plugin_image, "gtk-dialog-info", GTK_ICON_SIZE_MENU); - text = g_strdup_printf (_("%s plugin is available and the binary is installed."), item->plugin_name); + text = g_strdup_printf (_("%s plugin is available and the binary is installed."), iface->plugin_name); html = g_strdup_printf ("<i>%s</i>", text); gtk_label_set_markup (prefs->plugin_status, html); g_free (html); @@ -728,7 +728,7 @@ junk_plugin_changed (GtkWidget *combo, EMMailerPrefs *prefs) } else { gchar *text, *html; gtk_image_set_from_stock (prefs->plugin_image, "gtk-dialog-warning", GTK_ICON_SIZE_MENU); - text = g_strdup_printf (_("%s plugin is not available. Please check whether the package is installed."), item->plugin_name); + text = g_strdup_printf (_("%s plugin is not available. Please check whether the package is installed."), iface->plugin_name); html = g_strdup_printf ("<i>%s</i>", text); gtk_label_set_markup (prefs->plugin_status, html); g_free (html); @@ -761,20 +761,20 @@ junk_plugin_setup (GtkWidget *combo, EMMailerPrefs *prefs) } while (plugins) { - struct _EMJunkHookItem *item = plugins->data;; + EMJunkInterface *iface = plugins->data; - gtk_combo_box_append_text (GTK_COMBO_BOX (combo), item->plugin_name); - if (!def_set && pdefault && item->plugin_name && !strcmp(pdefault, item->plugin_name)) { + gtk_combo_box_append_text (GTK_COMBO_BOX (combo), iface->plugin_name); + if (!def_set && pdefault && iface->plugin_name && !strcmp(pdefault, iface->plugin_name)) { gboolean status; def_set = TRUE; gtk_combo_box_set_active (GTK_COMBO_BOX (combo), index); - status = e_plugin_invoke (item->hook->hook.plugin, item->validate_binary, NULL) != NULL; + status = e_plugin_invoke (iface->hook->plugin, iface->validate_binary, NULL) != NULL; if (status) { gchar *text, *html; gtk_image_set_from_stock (prefs->plugin_image, "gtk-dialog-info", GTK_ICON_SIZE_MENU); /* May be a better text */ - text = g_strdup_printf (_("%s plugin is available and the binary is installed."), item->plugin_name); + text = g_strdup_printf (_("%s plugin is available and the binary is installed."), iface->plugin_name); html = g_strdup_printf ("<i>%s</i>", text); gtk_label_set_markup (prefs->plugin_status, html); g_free (html); @@ -783,7 +783,7 @@ junk_plugin_setup (GtkWidget *combo, EMMailerPrefs *prefs) gchar *text, *html; gtk_image_set_from_stock (prefs->plugin_image, "gtk-dialog-warning", GTK_ICON_SIZE_MENU); /* May be a better text */ - text = g_strdup_printf (_("%s plugin is not available. Please check whether the package is installed."), item->plugin_name); + text = g_strdup_printf (_("%s plugin is not available. Please check whether the package is installed."), iface->plugin_name); html = g_strdup_printf ("<i>%s</i>", text); gtk_label_set_markup (prefs->plugin_status, html); g_free (html); diff --git a/modules/mail/evolution-module-mail.c b/modules/mail/evolution-module-mail.c index 97bc953c41..1bb58c7742 100644 --- a/modules/mail/evolution-module-mail.c +++ b/modules/mail/evolution-module-mail.c @@ -19,6 +19,12 @@ * */ +#include "e-mail-attachment-handler.h" + +#include "e-mail-config-hook.h" +#include "e-mail-event-hook.h" +#include "e-mail-junk-hook.h" + #include "e-mail-shell-backend.h" #include "e-mail-shell-content.h" #include "e-mail-shell-sidebar.h" @@ -34,6 +40,12 @@ e_module_load (GTypeModule *type_module) { /* Register dynamically loaded types. */ + e_mail_attachment_handler_register_type (type_module); + + e_mail_config_hook_register_type (type_module); + e_mail_event_hook_register_type (type_module); + e_mail_junk_hook_register_type (type_module); + e_mail_shell_backend_register_type (type_module); e_mail_shell_content_register_type (type_module); e_mail_shell_sidebar_register_type (type_module); diff --git a/modules/plugin-lib/Makefile.am b/modules/plugin-lib/Makefile.am new file mode 100644 index 0000000000..cce60902fa --- /dev/null +++ b/modules/plugin-lib/Makefile.am @@ -0,0 +1,20 @@ +AM_CPPFLAGS = \ + -DG_LOG_DOMAIN=\"evolution-plugin-lib\" \ + -I$(top_srcdir) \ + $(E_UTIL_CFLAGS) + +module_LTLIBRARIES = libevolution-module-plugin-lib.la + +libevolution_module_plugin_lib_la_SOURCES = \ + evolution-module-plugin-lib.c \ + e-plugin-lib.c \ + e-plugin-lib.h + +libevolution_module_plugin_lib_la_LIBADD = \ + $(top_builddir)/e-util/libeutil.la \ + $(E_UTIL_LIBS) + +libevolution_module_plugin_lib_la_LDFLAGS = \ + -module -avoid-version $(NO_UNDEFINED) + +-include $(top_srcdir)/git.mk diff --git a/modules/plugin-lib/e-plugin-lib.c b/modules/plugin-lib/e-plugin-lib.c new file mode 100644 index 0000000000..c7a0233bb3 --- /dev/null +++ b/modules/plugin-lib/e-plugin-lib.c @@ -0,0 +1,249 @@ +/* + * e-plugin-lib.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/> + * + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#include "e-plugin-lib.h" + +#include <string.h> + +static gpointer parent_class; +static GType plugin_lib_type; + +/* TODO: + We need some way to manage lifecycle. + We need some way to manage state. + + Maybe just the g module init method will do, or we could add + another which returns context. + + There is also the question of per-instance context, e.g. for config + pages. +*/ + +static gint +plugin_lib_loadmodule (EPlugin *plugin) +{ + EPluginLib *plugin_lib = E_PLUGIN_LIB (plugin); + EPluginLibEnableFunc enable; + + if (plugin_lib->module != NULL) + return 0; + + if (plugin_lib->location == NULL) { + g_warning ("Location not set in plugin '%s'", plugin->name); + return -1; + } + + if ((plugin_lib->module = g_module_open (plugin_lib->location, 0)) == NULL) { + g_warning ("can't load plugin '%s': %s", plugin_lib->location, g_module_error ()); + return -1; + } + + if (g_module_symbol (plugin_lib->module, "e_plugin_lib_enable", (gpointer)&enable)) { + if (enable (plugin_lib, TRUE) != 0) { + plugin->enabled = FALSE; + g_module_close (plugin_lib->module); + plugin_lib->module = NULL; + return -1; + } + } + + return 0; +} + +static gpointer +plugin_lib_invoke (EPlugin *plugin, const gchar *name, gpointer data) +{ + EPluginLib *plugin_lib = E_PLUGIN_LIB (plugin); + EPluginLibFunc cb; + + if (!plugin->enabled) { + g_warning ("trying to invoke '%s' on disabled plugin '%s'", name, plugin->id); + return NULL; + } + + if (plugin_lib_loadmodule (plugin) != 0) + return NULL; + + if (!g_module_symbol (plugin_lib->module, name, (gpointer)&cb)) { + g_warning ("Cannot resolve symbol '%s' in plugin '%s' (not exported?)", name, plugin_lib->location); + return NULL; + } + + return cb (plugin_lib, data); +} + +static gpointer +plugin_lib_get_symbol (EPlugin *plugin, const gchar *name) +{ + EPluginLib *plugin_lib = E_PLUGIN_LIB (plugin); + gpointer symbol; + + if (plugin_lib_loadmodule (plugin) != 0) + return NULL; + + if (!g_module_symbol (plugin_lib->module, name, &symbol)) + return NULL; + + return symbol; +} + +static gint +plugin_lib_construct (EPlugin *plugin, xmlNodePtr root) +{ + EPluginLib *plugin_lib = E_PLUGIN_LIB (plugin); + + /* Set the location before chaining up, as some EPluginHooks + * will cause the module to load during hook construction. */ + + plugin_lib->location = e_plugin_xml_prop (root, "location"); + + if (plugin_lib->location == NULL) { + g_warning ("Library plugin '%s' has no location", plugin->id); + return -1; + } +#ifdef G_OS_WIN32 + { + gchar *mapped_location = + e_util_rplugin_libace_prefix (EVOLUTION_PREFIX, + e_util_get_prefix (), + plugin_lib->location); + g_free (plugin_lib->location); + plugin_lib->location = mapped_location; + } +#endif + + /* Chain up to parent's construct() method. */ + if (E_PLUGIN_CLASS (parent_class)->construct (plugin, root) == -1) + return -1; + + /* If we're enabled, check for the load-on-startup property */ + if (plugin->enabled) { + xmlChar *tmp; + + tmp = xmlGetProp (root, (const guchar *)"load-on-startup"); + if (tmp) { + if (plugin_lib_loadmodule (plugin) != 0) { + xmlFree (tmp); + return -1; + } + xmlFree (tmp); + } + } + + return 0; +} + +static GtkWidget * +plugin_lib_get_configure_widget (EPlugin *plugin) +{ + EPluginLib *plugin_lib = E_PLUGIN_LIB (plugin); + EPluginLibGetConfigureWidgetFunc get_configure_widget; + + if (plugin_lib_loadmodule (plugin) != 0) { + return NULL; + } + + if (g_module_symbol (plugin_lib->module, "e_plugin_lib_get_configure_widget", (gpointer)&get_configure_widget)) { + return (GtkWidget*) get_configure_widget (plugin_lib); + } + return NULL; +} + +static void +plugin_lib_enable (EPlugin *plugin, gint state) +{ + EPluginLib *plugin_lib = E_PLUGIN_LIB (plugin); + EPluginLibEnableFunc enable; + + E_PLUGIN_CLASS (parent_class)->enable (plugin, state); + + /* if we're disabling and it isn't loaded, nothing to do */ + if (!state && plugin_lib->module == NULL) + return; + + /* this will noop if we're disabling since we tested it above */ + if (plugin_lib_loadmodule (plugin) != 0) + return; + + if (g_module_symbol (plugin_lib->module, "e_plugin_lib_enable", (gpointer) &enable)) { + if (enable (plugin_lib, state) != 0) + return; + } +} + +static void +plugin_lib_finalize (GObject *object) +{ + EPluginLib *plugin_lib = E_PLUGIN_LIB (object); + + g_free (plugin_lib->location); + + if (plugin_lib->module) + g_module_close (plugin_lib->module); + + /* Chain up to parent's finalize() method. */ + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +plugin_lib_class_init (EPluginClass *class) +{ + GObjectClass *object_class; + + parent_class = g_type_class_peek_parent (class); + + object_class = G_OBJECT_CLASS (class); + object_class->finalize = plugin_lib_finalize; + + class->construct = plugin_lib_construct; + class->invoke = plugin_lib_invoke; + class->get_symbol = plugin_lib_get_symbol; + class->enable = plugin_lib_enable; + class->get_configure_widget = plugin_lib_get_configure_widget; + class->type = "shlib"; +} + +GType +e_plugin_lib_get_type (void) +{ + return plugin_lib_type; +} + +void +e_plugin_lib_register_type (GTypeModule *type_module) +{ + static const GTypeInfo type_info = { + sizeof (EPluginLibClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) plugin_lib_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + sizeof (EPluginLib), + 0, /* n_preallocs */ + (GInstanceInitFunc) NULL, + NULL /* value_table */ + }; + + plugin_lib_type = g_type_module_register_type ( + type_module, E_TYPE_PLUGIN, + "EPluginLib", &type_info, 0); +} diff --git a/modules/plugin-lib/e-plugin-lib.h b/modules/plugin-lib/e-plugin-lib.h new file mode 100644 index 0000000000..b485d9625e --- /dev/null +++ b/modules/plugin-lib/e-plugin-lib.h @@ -0,0 +1,92 @@ +/* + * e-plugin-lib.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/> + * + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifndef E_PLUGIN_LIB_H +#define E_PLUGIN_LIB_H + +#include <gmodule.h> +#include <e-util/e-plugin.h> + +/* Standard GObject macros */ +#define E_TYPE_PLUGIN_LIB \ + (e_plugin_lib_get_type ()) +#define E_PLUGIN_LIB(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_PLUGIN_LIB, EPluginLib)) +#define E_PLUGIN_LIB_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), E_TYPE_PLUGIN_LIB, EPluginLibClass)) +#define E_IS_PLUGIN_LIB(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_PLUGIN_LIB)) +#define E_IS_PLUGIN_LIB_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), E_TYPE_PLUGIN_LIB)) +#define E_PLUGIN_LIB_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), E_TYPE_PLUGIN_LIB, EPluginLibClass)) + +G_BEGIN_DECLS + +typedef struct _EPluginLib EPluginLib; +typedef struct _EPluginLibClass EPluginLibClass; + +/* The callback signature used for epluginlib methods */ +typedef gpointer (*EPluginLibFunc) (EPluginLib *ep, gpointer data); + +/* The setup method, this will be called when the plugin is + * initialized. In the future it may also be called when the plugin + * is disabled. */ +typedef gint (*EPluginLibEnableFunc) (EPluginLib *ep, gint enable); + +typedef gpointer (*EPluginLibGetConfigureWidgetFunc) (EPluginLib *ep); + +/** + * struct _EPluginLib - + * + * @plugin: Superclass. + * @location: The filename of the shared object. + * @module: The GModule once it is loaded. + * + * This is a concrete EPlugin class. It loads and invokes dynamically + * loaded libraries using GModule. The shared object isn't loaded + * until the first callback is invoked. + * + * When the plugin is loaded, and if it exists, "e_plugin_lib_enable" + * will be invoked to initialize the plugin. + **/ +struct _EPluginLib { + EPlugin parent; + + gchar *location; + GModule *module; +}; + +struct _EPluginLibClass { + EPluginClass parent_class; +}; + +GType e_plugin_lib_get_type (void); +void e_plugin_lib_register_type (GTypeModule *type_module); + +G_END_DECLS + +#endif /* E_PLUGIN_LIB_H */ diff --git a/modules/plugin-lib/evolution-module-plugin-lib.c b/modules/plugin-lib/evolution-module-plugin-lib.c new file mode 100644 index 0000000000..833ca5906d --- /dev/null +++ b/modules/plugin-lib/evolution-module-plugin-lib.c @@ -0,0 +1,41 @@ +/* + * evolution-module-plugin-lib.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/> + * + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#include <config.h> + +#include "e-plugin-lib.h" + +/* Module Entry Points */ +void e_module_load (GTypeModule *type_module); +void e_module_unload (GTypeModule *type_module); + +G_MODULE_EXPORT void +e_module_load (GTypeModule *type_module) +{ + /* Register dynamically loaded types. */ + + e_plugin_lib_register_type (type_module); +} + +G_MODULE_EXPORT void +e_module_unload (GTypeModule *type_module) +{ +} diff --git a/modules/plugin-mono/Camel.cs b/modules/plugin-mono/Camel.cs new file mode 100644 index 0000000000..4ad80e7012 --- /dev/null +++ b/modules/plugin-mono/Camel.cs @@ -0,0 +1,1278 @@ + +using System; +using System.Collections; +using System.ComponentModel; +using System.Runtime.InteropServices; + +namespace Camel { + [StructLayout (LayoutKind.Sequential)] + public struct CamelException { + public int id; + public string desc; + } + + public class Arg { + public enum Tag : uint { + END = 0, + IGNORE = 1, + FIRST = 1024, + + TYPE = 0xf0000000, /* type field for tags */ + TAG = 0x0fffffff, /* tag field for args */ + + OBJ = 0x00000000, /* object */ + INT = 0x10000000, /* int */ + DBL = 0x20000000, /* double */ + STR = 0x30000000, /* c string */ + PTR = 0x40000000, /* ptr */ + BOO = 0x50000000 /* bool */ + } + } + + public class Exception : System.ApplicationException { + public enum Type { + NONE = 0, + SYSTEM = 1 + } + + public Type id; + public string desc; + + public Exception(CamelException ex) { + id = (Type)ex.id; + desc = ex.desc; + } + + public Exception(Type _id, string _desc) { + id = _id; + desc = _desc; + } + } + + public class Util { + [DllImport("camel-1.2")] static extern int camel_init(string certdir, bool nss); + + public static void Init(string certdir, bool nss) { + if (camel_init(certdir, nss) != 0) + throw new Exception(Exception.Type.SYSTEM, "Init failure"); + } + + public static string [] getUIDArray(IntPtr o) { + GPtrArray pa = (GPtrArray)Marshal.PtrToStructure(o, typeof(GPtrArray)); + string [] uids = new string[pa.len]; + + for (int i=0;i<pa.len;i++) { + IntPtr x = Marshal.ReadIntPtr(pa.pdata, i * Marshal.SizeOf(typeof(IntPtr))); + uids[i] = Marshal.PtrToStringAuto(x); + } + + return uids; + } +/* + public static IntPtr setUIDs(string [] uids) { + + } +*/ + public struct UIDArray { + public string [] uids; + public int len; + + public UIDArray(string [] _uids) { + uids = _uids; + len = _uids.Length; + } + + public UIDArray(IntPtr raw) { + uids = new string[0]; + len = 0; + Marshal.PtrToStructure(raw, this); + } + } + } + + public class Object { + // should be library scope + public IntPtr cobject; + private int finaliseID = -1; + + protected EventHandlerList events = new EventHandlerList(); + + // reffing & wrapping stuff. + struct CamelObject { + public IntPtr klass; + } + + struct CamelObjectClass { + public IntPtr parent; + int magic; + IntPtr next; + IntPtr prev; + public string name; + }; + + private static Hashtable types = new Hashtable(); + private static Hashtable objects = new Hashtable(); + + [DllImport("camel-1.2")] static extern void camel_object_ref(IntPtr raw); + [DllImport("camel-1.2")] static extern void camel_object_unref(IntPtr raw); + + public Object(IntPtr raw) { + // ok this is a hack around c# crap to do with unargumented constructors. + // we can bypass to a null raw so we can properly instantiate new types + if (raw != (IntPtr)0) { + cobject = raw; + toCamel(this); + } + } + + public Object() { + // this is invalid? + } + + ~Object() { + System.Console.WriteLine("object disposed " + cobject + " type " + this); + + // well we can never get a finalised event anyway ... + if (finalise_id != -1) + camel_object_remove_event(cobject, finalise_id); + if (meta_changed_id != -1) + camel_object_remove_event(cobject, meta_changed_id); + + objects.Remove(cobject); + camel_object_remove_event(cobject, finaliseID); + finaliseID = -1; + camel_object_unref(cobject); + cobject = (IntPtr)0; + + // FIXME: remove any event hooks too + } + + static Object() { + types.Add("CamelObject", typeof(Camel.Object)); + types.Add("CamelSession", typeof(Camel.Session)); + types.Add("CamelFolder", typeof(Camel.Folder)); + types.Add("CamelDataWrapper", typeof(Camel.DataWrapper)); + types.Add("CamelMedium", typeof(Camel.Medium)); + types.Add("CamelMimeMessage", typeof(Camel.MimeMessage)); + types.Add("CamelMimePart", typeof(Camel.MimePart)); + types.Add("CamelMultipart", typeof(Camel.Multipart)); + + types.Add("CamelStore", typeof(Camel.Store)); + types.Add("CamelTransport", typeof(Camel.Transport)); + types.Add("CamelAddress", typeof(Camel.Address)); + types.Add("CamelInternetAddress", typeof(Camel.InternetAddress)); + types.Add("CamelStream", typeof(Camel.Stream)); + types.Add("CamelStreamMem", typeof(Camel.StreamMem)); + types.Add("CamelStreamFs", typeof(Camel.StreamFS)); + } + + public static void objectFinalised(IntPtr o, IntPtr info, IntPtr data) { + System.Console.WriteLine("object finalised " + o); + objects.Remove(o); + } + + public static Object fromCamel(IntPtr raw) { + CamelObject o; + CamelObjectClass klass; + WeakReference weak = (WeakReference)objects[raw]; + + System.Console.WriteLine("object from camel " + raw); + + if (weak != null) + return (Object)weak.Target; + + o = (CamelObject)Marshal.PtrToStructure(raw, typeof(CamelObject)); + if ((object)o == null) + return null; + + klass = (CamelObjectClass)Marshal.PtrToStructure(o.klass, typeof(CamelObjectClass)); + while ((object)klass != null) { + Console.WriteLine(" checking is " + klass.name); + if (types.ContainsKey(klass.name)) { + Console.WriteLine(" yep!"); + camel_object_ref(raw); + return (Camel.Object)Activator.CreateInstance((Type)types[klass.name], new object [] { raw }); + } + + klass = (CamelObjectClass)Marshal.PtrToStructure(klass.parent, typeof(CamelObjectClass)); + } + + Console.WriteLine(" unknown type?"); + camel_object_unref(raw); + return null; + } + + /* this just registers an object created on the cil side */ + public static void toCamel(Object res) { + System.Console.WriteLine("object to camel " + res.cobject); + + objects.Add(res.cobject, new WeakReference(res)); + res.finaliseID = camel_object_hook_event(res.cobject, "finalize", (CamelEventFunc)objectFinalised, (IntPtr)0); + } + + // Camel event Wrapper and helpers + public delegate void CamelEventFunc(IntPtr o, IntPtr info, IntPtr data); + + [DllImport("camel-1.2")] public static extern int camel_object_hook_event(IntPtr raw, string name, CamelEventFunc func, IntPtr data); + [DllImport("camel-1.2")] public static extern void camel_object_remove_event(IntPtr raw, int id); + + protected void addEvent(String name, ref int hookid, CamelEventFunc hook, Delegate value) { + if (hookid == -1) + hookid = camel_object_hook_event(cobject, name, hook, (IntPtr)0); + events.AddHandler(name, value); + } + + protected void removeEvent(String name, ref int hookid, Delegate value) { + events.RemoveHandler(name, value); + if (events[name] == null) { + camel_object_remove_event(cobject, hookid); + hookid = -1; + } + } + + // object events + public delegate void FinaliseEvent(Camel.Object o); + public delegate void MetaChangedEvent(Camel.Object o, String name); + + // how to remove these, at dispose time? + private int finalise_id = -1; + private int meta_changed_id = -1; + + private static void finaliseHook(IntPtr co, IntPtr info, IntPtr data) { + Object o = fromCamel(co); + FinaliseEvent f; + + if (o != null + && (f = (FinaliseEvent)o.events["finalize"]) != null) + f(o); + } + + private static void metaChangedHook(IntPtr co, IntPtr info, IntPtr data) { + Object o = fromCamel(co); + MetaChangedEvent f; + + if (o != null + && (f = (MetaChangedEvent)o.events["finalize"]) != null) + f(o, Marshal.PtrToStringAnsi(info)); + } + + public event FinaliseEvent Finalise { + add { addEvent("finalize", ref finalise_id, (CamelEventFunc)finaliseHook, value); } + remove { removeEvent("finalize", ref finalise_id, value); } + } + + public event MetaChangedEvent MetaChanged { + add { addEvent("meta_changed", ref meta_changed_id, (CamelEventFunc)metaChangedHook, value); } + remove { removeEvent("meta_changed", ref meta_changed_id, value); } + } + + [DllImport("camel-1.2")] static extern IntPtr camel_object_get_ptr(IntPtr raw, ref CamelException ex, int tag); + [DllImport("camel-1.2")] static extern void camel_object_free(IntPtr raw, int tag, IntPtr val); + [DllImport("camel-1.2")] static extern int camel_object_get_int(IntPtr raw, ref CamelException ex, int tag); + + // maybe we want an indexer class to get properties? + // e.g. name = folder.properties[Folder.Tag.NAME] + public String getString(int type) { + String s; + IntPtr o; + CamelException ex = new CamelException(); + + o = camel_object_get_ptr(cobject, ref ex, type); + if (ex.id != 0) + throw new Camel.Exception(ex); + + s = Marshal.PtrToStringAuto(o); + camel_object_free(cobject, type, o); + + return s; + } + + public Camel.Object getObject(int type) { + IntPtr o; + Camel.Object co; + CamelException ex = new CamelException(); + + o = camel_object_get_ptr(cobject, ref ex, type); + if (ex.id != 0) + throw new Camel.Exception(ex); + + co = fromCamel(o); + camel_object_free(cobject, type, o); + + return co; + } + + public int getInt(int type) { + int r; + CamelException ex = new CamelException(); + + r = camel_object_get_int(cobject, ref ex, type); + if (ex.id != 0) + throw new Camel.Exception(ex); + + return r; + } + + // meta-data + [DllImport("camel-1.2")] static extern String camel_object_meta_get(IntPtr raw, string name); + [DllImport("camel-1.2")] static extern bool camel_object_meta_set(IntPtr raw, string name, string value); + + public String metaGet(String name) { + return camel_object_meta_get(cobject, name); + } + + public bool metaSet(String name, String value) { + return camel_object_meta_set(cobject, name, value); + } + } + + public class Provider { + public enum Type { + STORE = 0, + TRANSPORT = 1 + } + } + + public class Session : Object { + public Session(IntPtr raw) : base(raw) { } + + [DllImport("camel-provider-1.2")] static extern IntPtr camel_session_get_service(IntPtr o, string uri, int type, ref CamelException ex); + [DllImport("camel-provider-1.2")] static extern IntPtr camel_session_get_service_connected(IntPtr o, string uri, int type, ref CamelException ex); + + public Service getService(string uri, Provider.Type type) { + IntPtr s; + CamelException ex = new CamelException(); + + s = camel_session_get_service(cobject, uri, (int)type, ref ex); + if (ex.id != 0) + throw new Camel.Exception(ex); + + return (Service)fromCamel(s); + } + } + + public class Service : Object { + public Service(IntPtr raw) : base(raw) { } + // wrap service shit + } + + public class Store : Service { + public Store(IntPtr raw) : base(raw) { } + + [DllImport("camel-provider-1.2")] + static extern IntPtr camel_store_get_folder(IntPtr o, string name, int flags, ref CamelException ex); + + Folder getFolder(string name, int flags) { + IntPtr s; + CamelException ex = new CamelException(); + + s = camel_store_get_folder(cobject, name, flags, ref ex); + if (ex.id != 0) + throw new Camel.Exception(ex); + + return (Folder)fromCamel(s); + } + + void createFolder(string name) { + } + } + + public class Transport : Service { + public Transport(IntPtr raw) : base(raw) { } + + // send to (message, from, reciepients); + } + + public class Folder : Camel.Object { + public Folder(IntPtr raw) : base(raw) { } + + ~Folder() { + if (changed_id != -1) + camel_object_remove_event(cobject, changed_id); + } + + public enum Tag { + NAME = (int) (0x1400 + Arg.Tag.STR), + FULL_NAME = (int) (0x1401 + Arg.Tag.STR), + STORE = (int) (0x1402 + Arg.Tag.OBJ), + PERMANENTFLAGS = (int) (0x1403 + Arg.Tag.INT), + TOTAL = (int) (0x1404 + Arg.Tag.INT), + UNREAD = (int) (0x1405 + Arg.Tag.INT), + DELETED = (int) (0x1406 + Arg.Tag.INT), + JUNKED = (int) (0x1407 + Arg.Tag.INT), + VISIBLE = (int) (0x1408 + Arg.Tag.INT), + UID_ARRAY = (int) (0x1409 + Arg.Tag.PTR), + INFO_ARRAY = (int) (0x140a + Arg.Tag.PTR), // GPtrArray + PROPERTIES = (int) (0x140b + Arg.Tag.PTR), // GSList of properties + } + + [DllImport("camel-provider-1.2")] static extern IntPtr camel_folder_get_message(IntPtr o, string uid, ref CamelException ex); + [DllImport("camel-provider-1.2")] static extern IntPtr camel_folder_get_uids(IntPtr o); + [DllImport("camel-provider-1.2")] static extern void camel_folder_free_uids(IntPtr o, IntPtr uids); + [DllImport("camel-provider-1.2")] static extern IntPtr camel_folder_search_by_expression(IntPtr o, string expr, ref CamelException ex); + [DllImport("camel-provider-1.2")] static extern IntPtr camel_folder_search_by_uids(IntPtr o, string expr, ref Util.UIDArray uids, ref CamelException ex); + [DllImport("camel-provider-1.2")] static extern void camel_folder_search_free(IntPtr o, IntPtr uids); + + [DllImport("camel-provider-1.2")] static extern IntPtr camel_folder_get_message_info(IntPtr raw, String uid); + + public MimeMessage getMessage(string uid) { + CamelException ex = new CamelException(); + IntPtr o = camel_folder_get_message(cobject, uid, ref ex); + + if (ex.id != 0) + throw new Camel.Exception(ex); + + return (MimeMessage)fromCamel(o); + } + + public MessageInfo getMessageInfo(string uid) { + IntPtr o = camel_folder_get_message_info(cobject, uid); + + if (o == (IntPtr)0) + return null; + else + return new MessageInfo(o); + } + + public string [] getUIDs() { + IntPtr o = camel_folder_get_uids(cobject); + Util.UIDArray uids = new Util.UIDArray(o); + + camel_folder_free_uids(cobject, o); + + return uids.uids; + } + + public string [] search(string expr) { + CamelException ex = new CamelException(); + IntPtr o = camel_folder_search_by_expression(cobject, expr, ref ex); + Util.UIDArray uids; + + if (ex.id != 0) + throw new Camel.Exception(ex); + + uids = new Util.UIDArray(o); + camel_folder_search_free(cobject, o); + + return uids.uids; + } + + public string [] searchUIDs(string expr, string [] sub) { + CamelException ex = new CamelException(); + Util.UIDArray uids = new Util.UIDArray(sub); + IntPtr o = camel_folder_search_by_uids(cobject, expr, ref uids, ref ex); + + if (ex.id != 0) + throw new Camel.Exception(ex); + + uids = new Util.UIDArray(o); + camel_folder_search_free(cobject, o); + + return uids.uids; + } + + public String name { + get { return getString((int)Folder.Tag.NAME); } + } + + public String fullName { + get { return getString((int)Folder.Tag.FULL_NAME); } + } + + public Camel.Store store { + get { return (Camel.Store)getObject((int)Folder.Tag.STORE); } + } + + // Folder events + public delegate void ChangedEvent(Camel.Folder f); + + private int changed_id = -1; + + private static void changedHook(IntPtr co, IntPtr info, IntPtr data) { + Camel.Folder o = (Camel.Folder)fromCamel(co); + ChangedEvent f; + + Console.WriteLine("changed hook called for: " + o.cobject); + + if (o != null + && (f = (ChangedEvent)o.events["folder_changed"]) != null) + f(o); + } + + public event ChangedEvent Changed { + add { addEvent("folder_changed", ref changed_id, (CamelEventFunc)changedHook, value); } + remove { removeEvent("folder_changed", ref changed_id, value); } + } + } + + public class DataWrapper : Camel.Object { + public DataWrapper(IntPtr raw) : base(raw) { } + + [DllImport("camel-1.2")] static extern int camel_data_wrapper_write_to_stream(IntPtr o, IntPtr s); + [DllImport("camel-1.2")] static extern int camel_data_wrapper_decode_to_stream(IntPtr o, IntPtr s); + [DllImport("camel-1.2")] static extern int camel_data_wrapper_construct_from_stream(IntPtr o, IntPtr s); + [DllImport("camel-1.2")] static extern IntPtr camel_data_wrapper_get_mime_type_field(IntPtr o); + + public void writeToStream(Camel.Stream stream) { + int res; + + res = camel_data_wrapper_write_to_stream(cobject, stream.cobject); + if (res == -1) + throw new Exception(Exception.Type.SYSTEM, "IO Error"); + } + + public void decodeToStream(Camel.Stream stream) { + int res; + + res = camel_data_wrapper_decode_to_stream(cobject, stream.cobject); + if (res == -1) + throw new Exception(Exception.Type.SYSTEM, "IO Error"); + } + + public void constructFromStream(Camel.Stream stream) { + int res; + + res = camel_data_wrapper_construct_from_stream(cobject, stream.cobject); + if (res == -1) + throw new Exception(Exception.Type.SYSTEM, "IO Error"); + } + + public ContentType mimeType { get { return new ContentType(camel_data_wrapper_get_mime_type_field(cobject)); } } + } + + public class Medium : Camel.DataWrapper { + public Medium(IntPtr raw) : base(raw) { } + + [DllImport("camel-1.2")] static extern IntPtr camel_medium_get_content_object(IntPtr o); + [DllImport("camel-1.2")] static extern void camel_medium_set_content_object(IntPtr o, IntPtr s); + + public DataWrapper content { + get { + IntPtr o = camel_medium_get_content_object(cobject); + + if (o != (IntPtr)0) + return (DataWrapper)Object.fromCamel(o); + else + return null; + } + set { + camel_medium_set_content_object(cobject, value.cobject); + } + } + } + + public class Multipart : Camel.DataWrapper { + [DllImport("camel-1.2")] static extern IntPtr camel_multipart_new(); + [DllImport("camel-1.2")] static extern void camel_multipart_add_part(IntPtr o, IntPtr p); + [DllImport("camel-1.2")] static extern void camel_multipart_remove_part(IntPtr o, IntPtr p); + [DllImport("camel-1.2")] static extern IntPtr camel_multipart_get_part(IntPtr o, int index); + [DllImport("camel-1.2")] static extern int camel_multipart_get_number(IntPtr o); + + public Multipart(IntPtr raw) : base(raw) { } + + public void addPart(MimePart part) { + camel_multipart_add_part(cobject, part.cobject); + } + + public void removePart(MimePart part) { + camel_multipart_add_part(cobject, part.cobject); + } + + public MimePart getPart(int index) { + IntPtr o; + + o = camel_multipart_get_part(cobject, index); + if (o != (IntPtr)0) + return (MimePart)Object.fromCamel(o); + else + return null; + } + + public int getNumber() { + return camel_multipart_get_number(cobject); + } + + // FIXME: finish + } + + public class MimePart : Camel.Medium { + [DllImport("camel-1.2")] static extern IntPtr camel_mime_part_new(); + [DllImport("camel-1.2")] static extern IntPtr camel_mime_part_get_description(IntPtr o); + [DllImport("camel-1.2")] static extern void camel_mime_part_set_description(IntPtr o, string s); + [DllImport("camel-1.2")] static extern IntPtr camel_mime_part_get_disposition(IntPtr o); + [DllImport("camel-1.2")] static extern void camel_mime_part_set_disposition(IntPtr o, string s); + [DllImport("camel-1.2")] static extern IntPtr camel_mime_part_get_filename(IntPtr o); + [DllImport("camel-1.2")] static extern void camel_mime_part_set_filename(IntPtr o, string s); + + public MimePart(IntPtr raw) : base(raw) { } + + public string description { + get { return Marshal.PtrToStringAuto(camel_mime_part_get_description(cobject)); } + set { camel_mime_part_set_description(cobject, value); } + } + + public string disposition { + get { return Marshal.PtrToStringAuto(camel_mime_part_get_disposition(cobject)); } + set { camel_mime_part_set_disposition(cobject, value); } + } + + public string filename { + get { return Marshal.PtrToStringAuto(camel_mime_part_get_filename(cobject)); } + set { camel_mime_part_set_filename(cobject, value); } + } + + // FIXME: finish + } + + public class MimeMessage : Camel.MimePart { + [DllImport("camel-1.2")] static extern IntPtr camel_mime_message_new(); + [DllImport("camel-1.2")] static extern IntPtr camel_mime_message_get_subject(IntPtr o); + [DllImport("camel-1.2")] static extern void camel_mime_message_set_subject(IntPtr o, string s); + [DllImport("camel-1.2")] static extern IntPtr camel_mime_message_get_from(IntPtr o); + [DllImport("camel-1.2")] static extern void camel_mime_message_set_from(IntPtr o, IntPtr s); + [DllImport("camel-1.2")] static extern IntPtr camel_mime_message_get_recipients(IntPtr o, string type); + [DllImport("camel-1.2")] static extern void camel_mime_message_set_recipients(IntPtr o, string type, IntPtr s); + + public MimeMessage(IntPtr raw) : base(raw) { } + + /* We need to use factories to create new objects otherwise the parent will instantiate an instance + of itself instead during the constructor setup */ + public MimeMessage() : base((IntPtr)0) { + cobject = camel_mime_message_new(); + toCamel(this); + } + + public string subject { + get { return Marshal.PtrToStringAuto(camel_mime_message_get_subject(cobject)); } + set { camel_mime_message_set_subject(cobject, value); } + } + + public InternetAddress from { + get { return new InternetAddress(camel_mime_message_get_from(cobject)); } + set { camel_mime_message_set_from(cobject, value.cobject); } + } + + public InternetAddress to { + get { return new InternetAddress(camel_mime_message_get_recipients(cobject, "to")); } + set { camel_mime_message_set_recipients(cobject, "to", value.cobject); } + } + + public InternetAddress cc { + get { return new InternetAddress(camel_mime_message_get_recipients(cobject, "cc")); } + set { camel_mime_message_set_recipients(cobject, "cc", value.cobject); } + } + + public InternetAddress bcc { + get { return new InternetAddress(camel_mime_message_get_recipients(cobject, "bcc")); } + set { camel_mime_message_set_recipients(cobject, "bcc", value.cobject); } + } + + public InternetAddress resentTO { + get { return new InternetAddress(camel_mime_message_get_recipients(cobject, "resent-to")); } + set { camel_mime_message_set_recipients(cobject, "resent-to", value.cobject); } + } + + public InternetAddress resentCC { + get { return new InternetAddress(camel_mime_message_get_recipients(cobject, "resent-cc")); } + set { camel_mime_message_set_recipients(cobject, "resent-cc", value.cobject); } + } + + public InternetAddress resentBCC { + get { return new InternetAddress(camel_mime_message_get_recipients(cobject, "resent-bcc")); } + set { camel_mime_message_set_recipients(cobject, "resent-bcc", value.cobject); } + } + } + + // subclass real streams? or real stream interfaces? + public class Stream : Camel.Object { + public Stream(IntPtr raw) : base(raw) { } + + [DllImport("camel-1.2")] static extern int camel_stream_write(IntPtr o, byte [] data, int len); + [DllImport("camel-1.2")] static extern int camel_stream_read(IntPtr o, byte [] data, int len); + [DllImport("camel-1.2")] static extern int camel_stream_eos(IntPtr o); + [DllImport("camel-1.2")] static extern int camel_stream_close(IntPtr o); + [DllImport("camel-1.2")] static extern int camel_stream_flush(IntPtr o); + [DllImport("camel-1.2")] static extern int camel_stream_reset(IntPtr o); + + public int write(byte [] data, int len) { + int ret; + + ret = camel_stream_write(cobject, data, len); + if (ret == -1) + throw new Exception(Exception.Type.SYSTEM, "IO write Error"); + + return ret; + } + + public int write(string value) { + int ret; + byte [] data; + System.Text.UTF8Encoding enc = new System.Text.UTF8Encoding(); + + data = enc.GetBytes(value); + ret = camel_stream_write(cobject, data, data.Length); + if (ret == -1) + throw new Exception(Exception.Type.SYSTEM, "IO write Error"); + + return ret; + } + + + public int read(byte [] data, int len) { + int ret; + + ret = camel_stream_read(cobject, data, len); + if (ret == -1) + throw new Exception(Exception.Type.SYSTEM, "IO read Error"); + + return ret; + } + + public void close() { + if (camel_stream_close(cobject) == -1) + throw new Exception(Exception.Type.SYSTEM, "IO close Error"); + } + + public void reset() { + if (camel_stream_reset(cobject) == -1) + throw new Exception(Exception.Type.SYSTEM, "IO reset Error"); + } + + public void flush() { + if (camel_stream_flush(cobject) == -1) + throw new Exception(Exception.Type.SYSTEM, "IO close Error"); + } + + public bool eos() { + return (camel_stream_eos(cobject) != 0); + } + } + + public class SeekableStream : Camel.Stream { + public SeekableStream(IntPtr raw) : base(raw) { } + } + + public class StreamFS : Camel.SeekableStream { + public enum Flags { + O_RDONLY = 00, + O_WRONLY = 01, + O_RDWR = 02, + O_CREAT = 0100, + O_EXCL = 0200, + O_TRUNC = 01000, + O_APPEND = 02000 + } + + public static int STDIN_FILENO = 0; + public static int STDOUT_FILENO = 1; + public static int STDERR_FILENO = 2; + + public StreamFS(IntPtr raw) : base(raw) { } + + [DllImport("camel-1.2")] static extern IntPtr camel_stream_fs_new_with_name(string name, int flags, int mode); + [DllImport("camel-1.2")] static extern IntPtr camel_stream_fs_new_with_fd(int fd); + + public StreamFS(string name, Flags flags, int mode) : base((IntPtr)0) { + cobject = camel_stream_fs_new_with_name(name, (int)flags, mode); + toCamel(this); + } + + public StreamFS(int fd) : base((IntPtr)0) { + cobject = camel_stream_fs_new_with_fd(fd); + toCamel(this); + } + } + + // this should obviously be extracted at build time + [StructLayout (LayoutKind.Explicit)] + struct CamelStreamMem { + [FieldOffset(44)] public IntPtr buffer; + } + + struct GByteArray { + public IntPtr data; + public int len; + } + + struct GPtrArray { + public IntPtr pdata; + public int len; + } + + public class StreamMem : Camel.SeekableStream { + public StreamMem(IntPtr raw) : base(raw) { } + + [DllImport("camel-1.2")] + static extern IntPtr camel_stream_mem_new(); + + /* stupid c# */ + public StreamMem() : base((IntPtr)0) { + cobject = camel_stream_mem_new(); + toCamel(this); + } + + // should probably have some sort of interface for incremental/range gets too + public Byte[] getBuffer() { + CamelStreamMem mem = (CamelStreamMem)Marshal.PtrToStructure(cobject, typeof(CamelStreamMem)); + GByteArray ba = (GByteArray)Marshal.PtrToStructure(mem.buffer, typeof(GByteArray)); + Byte[] res = new Byte[ba.len]; + + Marshal.Copy(ba.data, res, 0, ba.len); + + return res; + } + } + + // should do iterators etc? + public class Address : Camel.Object { + public Address(IntPtr raw) : base (raw) { } + + [DllImport("camel-1.2")] static extern IntPtr camel_address_new(); + [DllImport("camel-1.2")] static extern int camel_address_length(IntPtr raw); + [DllImport("camel-1.2")] static extern int camel_address_decode(IntPtr raw, string addr); + [DllImport("camel-1.2")] static extern string camel_address_encode(IntPtr raw); + [DllImport("camel-1.2")] static extern int camel_address_unformat(IntPtr raw, string addr); + [DllImport("camel-1.2")] static extern string camel_address_format(IntPtr raw); + [DllImport("camel-1.2")] static extern int camel_address_cat(IntPtr raw, IntPtr src); + [DllImport("camel-1.2")] static extern int camel_address_copy(IntPtr raw, IntPtr src); + [DllImport("camel-1.2")] static extern void camel_address_remove(IntPtr raw, int index); + + public Address() : base((IntPtr)0) { + cobject = camel_address_new(); + toCamel(this); + } + + public int length() { + return camel_address_length(cobject); + } + + public void decode(string addr) { + if (camel_address_decode(cobject, addr) == -1) + throw new Exception(Exception.Type.SYSTEM, "Invalid address: " + addr); + } + + public string encode() { + return camel_address_encode(cobject); + } + + public void unformat(string addr) { + if (camel_address_unformat(cobject, addr) == -1) + throw new Exception(Exception.Type.SYSTEM, "Invalid address: " + addr); + } + + public string format() { + return camel_address_format(cobject); + } + + public void cat(Address from) { + camel_address_cat(cobject, from.cobject); + } + + public void copy(Address from) { + camel_address_copy(cobject, from.cobject); + } + } + + public class InternetAddress : Camel.Address { + public InternetAddress(IntPtr raw) : base (raw) { } + + [DllImport("camel-1.2")] static extern IntPtr camel_internet_address_new(); + [DllImport("camel-1.2")] static extern int camel_internet_address_add(IntPtr raw, string name, string addr); + [DllImport("camel-1.2")] static extern bool camel_internet_address_get(IntPtr raw, out string name, out string addr); + [DllImport("camel-1.2")] static extern int camel_internet_address_find_name(IntPtr raw, string name, out string addr); + [DllImport("camel-1.2")] static extern int camel_internet_address_find_address(IntPtr raw, string addr, out string name); + [DllImport("camel-1.2")] static extern string camel_internet_address_encode_address(out int len, string name, string addr); + [DllImport("camel-1.2")] static extern string camel_internet_address_format_address(string name, string addr); + + public InternetAddress() : base((IntPtr)0) { + cobject = camel_internet_address_new(); + toCamel(this); + } + + public void add(string name, string addr) { + camel_internet_address_add(cobject, name, addr); + } + + public bool get(out string name, out string addr) { + name = null; + addr = null; + return camel_internet_address_get(cobject, out name, out addr); + } + + // this is a weird arsed interface ... + public int findName(string name, out string addr) { + addr = null; + // FIXME: addr is const, need to marshal to local + return camel_internet_address_find_name(cobject, name, out addr); + } + + public int findAddress(string addr, out string name) { + name = null; + return camel_internet_address_find_name(cobject, addr, out name); + } + + public static string encode(string name, string addr) { + int len = 0; + // another weird-arsed interface + return camel_internet_address_encode_address(out len, name, addr); + } + + public static string format(string name, string addr) { + return camel_internet_address_format_address(name, addr); + } + } + + public class ContentType { + public IntPtr cobject; + + public ContentType(IntPtr raw) { + cobject = raw; + } + + [DllImport("camel-1.2")] static extern bool camel_content_type_is(IntPtr raw, string type, string subtype); + + ~ContentType() { + } + + public bool isType(string type, string subtype) { + return camel_content_type_is(cobject, type, subtype); + } + } + + public class MessageInfo { + public IntPtr cobject; + private Tags user_tags; + private Flags user_flags; + + private enum Type { + SUBJECT, + FROM, + TO, + CC, + MLIST, + + FLAGS, + SIZE, + + DATE_SENT, + DATE_RECEIVED, + + MESSAGE_ID, + REFERENCES, + + USER_FLAGS, + USER_TAGS, + + LAST, + } + + public class Tags { + private MessageInfo mi; + + [DllImport("camel-provider-1.2")] static extern IntPtr camel_message_info_user_tag(IntPtr mi, String name); + [DllImport("camel-provider-1.2")] static extern bool camel_message_info_set_user_tag(IntPtr mi, String name, String value); + + public Tags(MessageInfo raw) { + mi = raw; + } + + public String this [String tag] { + get { + return Marshal.PtrToStringAnsi(camel_message_info_user_tag(mi.cobject, tag)); + } + set { + camel_message_info_set_user_tag(mi.cobject, tag, value); + } + } + } + + public class Flags { + private MessageInfo mi; + + [DllImport("camel-provider-1.2")] static extern bool camel_message_info_user_flag(IntPtr miptr, String name); + [DllImport("camel-provider-1.2")] static extern bool camel_message_info_set_user_flag(IntPtr miptr, String name, bool value); + + // note raw is a pointer to a pointer of tags + public Flags(MessageInfo raw) { + mi = raw; + } + + public bool this [String tag] { + get { + return camel_message_info_user_flag(mi.cobject, tag); + } + set { + camel_message_info_set_user_flag(mi.cobject, tag, value); + } + } + } + + // only used to calculate offsets + private struct CamelMessageInfo { + IntPtr summary; + uint refcount; + string uid; + }; + + public MessageInfo(IntPtr raw) { + cobject = raw; + } + + [DllImport("camel-provider-1.2")] static extern void camel_folder_free_message_info(IntPtr raw, IntPtr info); + [DllImport("camel-provider-1.2")] static extern void camel_message_info_free(IntPtr info); + + ~MessageInfo() { + camel_message_info_free(cobject); + } + + [DllImport("camel-provider-1.2")] static extern IntPtr camel_message_info_ptr(IntPtr raw, int type); + [DllImport("camel-provider-1.2")] static extern uint camel_message_info_uint32(IntPtr raw, int type); + [DllImport("camel-provider-1.2")] static extern uint camel_message_info_time(IntPtr raw, int type); + + public String uid { get { return Marshal.PtrToStringAuto(Marshal.ReadIntPtr(cobject, (int)Marshal.OffsetOf(typeof(CamelMessageInfo), "uid"))); } } + + public String subject { get { return Marshal.PtrToStringAnsi(camel_message_info_ptr(cobject, (int)Type.SUBJECT)); } } + public String from { get { return Marshal.PtrToStringAnsi(camel_message_info_ptr(cobject, (int)Type.FROM)); } } + public String to { get { return Marshal.PtrToStringAnsi(camel_message_info_ptr(cobject, (int)Type.TO)); } } + public String cc { get { return Marshal.PtrToStringAnsi(camel_message_info_ptr(cobject, (int)Type.CC)); } } + public String mlist { get { return Marshal.PtrToStringAnsi(camel_message_info_ptr(cobject, (int)Type.MLIST)); } } + + public uint flags { get { return camel_message_info_uint32(cobject, (int)Type.FLAGS); } } + public uint size { get { return camel_message_info_uint32(cobject, (int)Type.SIZE); } } + + public Tags userTags { + get { + if (user_tags == null) + user_tags = new Tags(this); + return user_tags; + } + } + + public Flags userFlags { + get { + if (user_flags == null) + user_flags = new Flags(this); + return user_flags; + } + } + } + + public class URL { + public IntPtr cobject; + internal Params param_list; + + // we never instantiate this, we just use it to describe the layout + internal struct CamelURL { + internal IntPtr protocol; + internal IntPtr user; + internal IntPtr authmech; + internal IntPtr passwd; + internal IntPtr host; + internal int port; + internal IntPtr path; + internal IntPtr pparams; + internal IntPtr query; + internal IntPtr fragment; + }; + + public class Params { + private URL parent; + + internal Params(URL _parent) { + parent = _parent; + } + + public string this[string name] { + set { camel_url_set_param(parent.cobject, name, value); } + get { return Marshal.PtrToStringAnsi(camel_url_get_param(parent.cobject, name)); } + } + } + + [DllImport("camel-1.2")] static extern IntPtr camel_url_new_with_base(IntPtr bbase, string url); + [DllImport("camel-1.2")] static extern IntPtr camel_url_new(string url, ref CamelException ex); + [DllImport("camel-1.2")] static extern string camel_url_to_string(IntPtr url, int flags); + [DllImport("camel-1.2")] static extern void camel_url_free(IntPtr url); + + // this is a shit to wrap, needs accessors or other pain + [DllImport("camel-1.2")] static extern void camel_url_set_protocol(IntPtr url, string s); + [DllImport("camel-1.2")] static extern void camel_url_set_user(IntPtr url, string s); + [DllImport("camel-1.2")] static extern void camel_url_set_authmech(IntPtr url, string s); + [DllImport("camel-1.2")] static extern void camel_url_set_passwd(IntPtr url, string s); + [DllImport("camel-1.2")] static extern void camel_url_set_host(IntPtr url, string s); + [DllImport("camel-1.2")] static extern void camel_url_set_port(IntPtr url, int p); + [DllImport("camel-1.2")] static extern void camel_url_set_path(IntPtr url, string s); + [DllImport("camel-1.2")] static extern void camel_url_set_param(IntPtr url, string s, string v); + [DllImport("camel-1.2")] static extern void camel_url_set_query(IntPtr url, string s); + [DllImport("camel-1.2")] static extern void camel_url_set_fragment(IntPtr url, string s); + + [DllImport("camel-1.2")] static extern IntPtr camel_url_get_param(IntPtr url, string s); + + [DllImport("camel-1.2")] static extern string camel_url_encode(string url, string escape); + // ugh we can't do this, it writes to its result?? + // -> use StringBuilder + [DllImport("camel-1.2")] static extern IntPtr camel_url_decode(ref string url); + + public URL(string uri) { + CamelException ex = new CamelException(); + + cobject = camel_url_new(uri, ref ex); + if (ex.id != 0) + throw new Exception(ex); + } + + public URL(URL bbase, string uri) { + cobject = camel_url_new_with_base(bbase.cobject, uri); + } + + ~URL() { + camel_url_free(cobject); + } + + /* its ugly but it works */ + private string field(string name) { + return Marshal.PtrToStringAuto(Marshal.ReadIntPtr(cobject, (int)Marshal.OffsetOf(typeof(CamelURL), name))); + } + + public string protocol { + set { camel_url_set_protocol(cobject, value); } + get { return field("protocol"); } + } + + public string user { + set { camel_url_set_user(cobject, value); } + get { return field("user"); } + } + + public string authmech { + set { camel_url_set_authmech(cobject, value); } + get { return field("authmech"); } + } + + public string passwd { + set { camel_url_set_passwd(cobject, value); } + get { return field("passwd"); } + } + + public string host { + set { camel_url_set_host(cobject, value); } + get { return field("host"); } + } + + public int port { + set { camel_url_set_port(cobject, value); } + get { return (int)Marshal.ReadIntPtr(cobject, (int)Marshal.OffsetOf(typeof(CamelURL), "port")); } + } + + public string path { + set { camel_url_set_path(cobject, value); } + get { return field("path"); } + } + + public string query { + set { camel_url_set_query(cobject, value); } + get { return field("query"); } + } + + public string fragment { + set { camel_url_set_fragment(cobject, value); } + get { return field("fragment"); } + } + + public Params paramlist { + get { + if (param_list == null) + param_list = new Params(this); + return param_list; + } + } + + public override string ToString() { + return camel_url_to_string(cobject, 0); + } + + public static string encode(string val) { + return camel_url_encode(val, null); + } + + public static string encode(string val, string escape) { + return camel_url_encode(val, escape); + } + } +} + +namespace Camel.Hash { + public class Stream : System.IO.Stream { + protected Camel.Stream substream; + + public Stream(Camel.Stream sub) { + substream = sub; + } + + public override bool CanSeek { get { return false; } } + public override bool CanRead { get { return true; } } + public override bool CanWrite { get { return true; } } + public override long Length { + get { + throw new System.IO.IOException("Cannot get stream length"); + } + } + public override long Position { + get { + throw new System.IO.IOException("Cannot get stream position"); + } + set { + if (value == 0) { + substream.reset(); + } else { + throw new System.IO.IOException("Cannot set stream position"); + } + } + } + + public override int Read(byte[] buffer, int offset, int count) { + // FIXME: how to add the offset to the buffer? + return substream.read(buffer, count); + } + + public override void Write(byte[] buffer, int offset, int count) { + // FIXME: how to add the offset to the buffer? + substream.write(buffer, count); + } + + public override void Flush() { + substream.flush(); + } + + public override long Seek(long offset, System.IO.SeekOrigin seek) { + throw new System.IO.IOException("Seeking not supported"); + } + + public override void SetLength(long len) { + throw new System.IO.IOException("Cannot set stream length"); + } + } +} + +/* +namespace Evolution.Mail { + class Component : GLib.Object { + public Component(IntPtr raw) : base(raw) {} + public Component() : base() {} + + ~Component() { + Dispose(); + } + + [DllImport("libevolution-mail.so")] static extern IntPtr mail_component_peek(); + [DllImport("libevolution-mail.so")] static extern IntPtr mail_component_peek_base_directory(IntPtr component); + [DllImport("libevolution-mail.so")] static extern IntPtr mail_component_peek(); + + public static Component peek() { + return new Component(mail_component_peek()); + } + + public String baseDirectory { + get {} + } +} +*/ diff --git a/modules/plugin-mono/Evolution.cs b/modules/plugin-mono/Evolution.cs new file mode 100644 index 0000000000..0db54405b3 --- /dev/null +++ b/modules/plugin-mono/Evolution.cs @@ -0,0 +1,158 @@ +using System; +using System.Runtime.InteropServices; +using System.Reflection; + +using Camel; + +namespace Evolution { + [StructLayout (LayoutKind.Sequential)] + public class PopupTarget { + public IntPtr popup; + public IntPtr widget; + public int type; + public int mask; + }; + + [StructLayout (LayoutKind.Sequential)] + public class MenuTarget { + public IntPtr menu; + public IntPtr widget; + public int type; + public int mask; + }; + + [StructLayout (LayoutKind.Sequential)] + public class EventTarget { + public IntPtr aevent; + public int type; + public int mask; + }; +}; + +namespace Evolution { + public class Error { + // can we marshal varags from c#? + [DllImport("eutil")] static extern int e_error_run(IntPtr parent, string tag, IntPtr end); + [DllImport("eutil")] static extern int e_error_run(IntPtr parent, string tag, string arg0, IntPtr end); + [DllImport("eutil")] static extern int e_error_run(IntPtr parent, string tag, string arg0, string arg1, IntPtr end); + [DllImport("eutil")] static extern int e_error_run(IntPtr parent, string tag, string arg0, string arg1, string arg2, IntPtr end); + + public static int run(IntPtr parent, string tag) { + return e_error_run(parent, tag, (IntPtr)0); + } + public static int run(IntPtr parent, string tag, string arg0) { + return e_error_run(parent, tag, arg0, (IntPtr)0); + } + public static int run(IntPtr parent, string tag, string arg0, string arg1) { + return e_error_run(parent, tag, arg0, arg1, (IntPtr)0); + } + public static int run(IntPtr parent, string tag, string arg0, string arg1, string arg2) { + return e_error_run(parent, tag, arg0, arg1, arg2, (IntPtr)0); + } + } +} + +namespace Evolution.Mail { + /* ********************************************************************** */ + [StructLayout (LayoutKind.Sequential)] + public class PopupTargetSelect : PopupTarget { + public IntPtr _folder; + public string uri; + public IntPtr _uids; + + public static PopupTargetSelect get(IntPtr o) { + return (PopupTargetSelect)Marshal.PtrToStructure(o, typeof(PopupTargetSelect)); + } + + public Camel.Folder folder { + get { return (Camel.Folder)Camel.Object.fromCamel(_folder); } + } + + public string [] uids { + get { return Camel.Util.getUIDArray(_uids); } + } + } + + [StructLayout (LayoutKind.Sequential)] + public class PopupTargetURI : Evolution.PopupTarget { + public string uri; + + public static PopupTargetURI get(IntPtr o) { + return (PopupTargetURI)Marshal.PtrToStructure(o, typeof(PopupTargetURI)); + } + } + + [StructLayout (LayoutKind.Sequential)] + public class PopupTargetPart : PopupTarget { + public string mimeType; + public IntPtr _part; + + public static PopupTargetPart get(IntPtr o) { + return (PopupTargetPart)Marshal.PtrToStructure(o, typeof(PopupTargetPart)); + } + + public Camel.Object part { + get { return (Camel.Object)Camel.Object.fromCamel(_part); } + } + } + + [StructLayout (LayoutKind.Sequential)] + public struct PopupTargetFolder { + public Evolution.PopupTarget target; + public string uri; + + public static PopupTargetFolder get(IntPtr o) { + return (PopupTargetFolder)Marshal.PtrToStructure(o, typeof(PopupTargetFolder)); + } + } + + /* ********************************************************************** */ + [StructLayout (LayoutKind.Sequential)] + public class MenuTargetSelect : MenuTarget { + public IntPtr _folder; + public string uri; + public IntPtr _uids; + + public static MenuTargetSelect get(IntPtr o) { + return (MenuTargetSelect)Marshal.PtrToStructure(o, typeof(MenuTargetSelect)); + } + + public Camel.Folder folder { + get { return (Camel.Folder)Camel.Object.fromCamel(_folder); } + } + + public string [] uids { + get { return Camel.Util.getUIDArray(_uids); } + } + } + + /* ********************************************************************** */ + [StructLayout (LayoutKind.Sequential)] + public class EventTargetFolder : EventTarget { + public string uri; + + public static EventTargetFolder get(IntPtr o) { + return (EventTargetFolder)Marshal.PtrToStructure(o, typeof(EventTargetFolder)); + } + } + + [StructLayout (LayoutKind.Sequential)] + public class EventTargetMessage : EventTarget { + public IntPtr _folder; + public string uid; + public IntPtr _message; + + public static EventTargetMessage get(IntPtr o) { + return (EventTargetMessage)Marshal.PtrToStructure(o, typeof(EventTargetMessage)); + } + + public Camel.Folder folder { + get { return (Camel.Folder)Camel.Object.fromCamel(_folder); } + } + + public Camel.MimeMessage message { + get { return (Camel.MimeMessage)Camel.Object.fromCamel(_message); } + } + + } +}; diff --git a/modules/plugin-mono/Makefile.am b/modules/plugin-mono/Makefile.am new file mode 100644 index 0000000000..f4f436ae66 --- /dev/null +++ b/modules/plugin-mono/Makefile.am @@ -0,0 +1,22 @@ +AM_CPPFLAGS = \ + -DG_LOG_DOMAIN=\"evolution-plugin-mono\" \ + -I$(top_srcdir) \ + $(E_UTIL_CFLAGS) \ + $(MONO_CFLAGS) + +module_LTLIBRARIES = libevolution-module-plugin-mono.la + +libevolution_module_plugin_mono_la_SOURCES = \ + evolution-module-plugin-mono.c \ + e-plugin-mono.c \ + e-plugin-mono.h + +libevolution_module_plugin_mono_la_LIBADD = \ + $(top_builddir)/e-util/libeutil.la \ + $(E_UTIL_LIBS) \ + $(MONO_LIBS) + +libevolution_module_plugin_mono_la_LDFLAGS = \ + -module -avoid-version $(NO_UNDEFINED) + +-include $(top_srcdir)/git.mk diff --git a/modules/plugin-mono/e-plugin-mono.c b/modules/plugin-mono/e-plugin-mono.c new file mode 100644 index 0000000000..1c43fb9d56 --- /dev/null +++ b/modules/plugin-mono/e-plugin-mono.c @@ -0,0 +1,261 @@ +/* + * e-plugin-mono.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/> + * + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#include "e-plugin-mono.h" + +#include <sys/types.h> +#include <string.h> + +#include "e-plugin-mono.h" + +#include <mono/metadata/debug-helpers.h> +#include <mono/metadata/object.h> +#include <mono/metadata/appdomain.h> +#include <mono/metadata/assembly.h> +#include <mono/metadata/threads.h> +#include <mono/metadata/mono-config.h> +#include <mono/jit/jit.h> + +#define E_PLUGIN_MONO_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE \ + ((obj), E_TYPE_PLUGIN_MONO, EPluginMonoPrivate)) + +struct _EPluginMonoPrivate { + MonoAssembly *assembly; + MonoClass *class; + MonoObject *plugin; + GHashTable *methods; +}; + +static MonoDomain *domain; +static gpointer parent_class; +static GType plugin_mono_type; + +static gchar * +get_xml_prop (xmlNodePtr node, const gchar *id) +{ + xmlChar *prop; + gchar *out = NULL; + + prop = xmlGetProp (node, (xmlChar *) id); + + if (prop != NULL) { + out = g_strdup ((gchar *) prop); + xmlFree (prop); + } + + return out; +} + +static void +plugin_mono_finalize (GObject *object) +{ + EPluginMono *plugin_mono; + + plugin_mono = E_PLUGIN_MONO (object); + + g_free (plugin_mono->location); + g_free (plugin_mono->handler); + + g_hash_table_destroy (plugin_mono->priv->methods); + + /* Chain up to parent's finalize() method. */ + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static gint +plugin_mono_construct (EPlugin *plugin, xmlNodePtr root) +{ + EPluginMono *plugin_mono; + + /* Chain up to parent's construct() method. */ + if (E_PLUGIN_CLASS (parent_class)->construct (plugin, root) == -1) + return -1; + + plugin_mono = E_PLUGIN_MONO (plugin); + plugin_mono->location = get_xml_prop (root, "location"); + plugin_mono->handler = get_xml_prop (root, "handler"); + + return (plugin_mono->location != NULL) ? 0 : -1; +} + +/* + Two approaches: + You can have a Evolution.Plugin implementation which has every + callback as methods on it. Or you can just use static methods + for everything. + + All methods take a single (structured) argument. +*/ + +static gpointer +plugin_mono_invoke (EPlugin *plugin, + const gchar *name, + gpointer data) +{ + EPluginMono *plugin_mono; + EPluginMonoPrivate *priv; + MonoMethodDesc *d; + MonoMethod *m; + MonoObject *x = NULL, *res; + gpointer *params; + + plugin_mono = E_PLUGIN_MONO (plugin); + priv = plugin_mono->priv; + + /* we need to do this every time since we may be called from any thread for some uses */ + mono_thread_attach (domain); + + if (priv->assembly == NULL) { + priv->assembly = mono_domain_assembly_open ( + domain, plugin_mono->location); + if (priv->assembly == NULL) { + g_warning ( + "Can't load assembly '%s'", + plugin_mono->location); + return NULL; + } + + if (plugin_mono->handler == NULL + || (priv->class = mono_class_from_name (mono_assembly_get_image (priv->assembly), "", plugin_mono->handler)) == NULL) { + } else { + priv->plugin = mono_object_new (domain, priv->class); + /* could conceivably init with some context too */ + mono_runtime_object_init (priv->plugin); + } + } + + m = g_hash_table_lookup (priv->methods, name); + if (m == NULL) { + if (priv->class) { + /* class method */ + MonoMethod* mono_method; + gpointer iter = NULL; + + d = mono_method_desc_new (name, FALSE); + /*if (d == NULL) { + g_warning ("Can't create method descriptor for '%s'", name); + return NULL; + }*/ + + while ((mono_method = mono_class_get_methods (priv->class, &iter))) { + g_print ("\n\a Method name is : <%s>\n\a", mono_method_get_name (mono_method)); + } +//mono_class_get_method_from_name + m = mono_class_get_method_from_name (priv->class, name, -1); + if (m == NULL) { + g_warning ("Can't find method callback '%s'", name); + return NULL; + } + } else { + /* static method */ + d = mono_method_desc_new (name, FALSE); + if (d == NULL) { + g_warning ("Can't create method descriptor for '%s'", name); + return NULL; + } + + m = mono_method_desc_search_in_image (d, mono_assembly_get_image (priv->assembly)); + if (m == NULL) { + g_warning ("Can't find method callback '%s'", name); + return NULL; + } + } + + g_hash_table_insert (priv->methods, g_strdup (name), m); + } + + params = g_malloc0(sizeof (*params)*1); + params[0] = &data; + res = mono_runtime_invoke (m, priv->plugin, params, &x); + /* do i need to free params?? */ + + if (x) + mono_print_unhandled_exception (x); + + if (res) { + gpointer *p = mono_object_unbox (res); + return *p; + } else + return NULL; +} + +static void +plugin_mono_class_init (EPluginMonoClass *class) +{ + GObjectClass *object_class; + EPluginClass *plugin_class; + + parent_class = g_type_class_peek_parent (class); + g_type_class_add_private (class, sizeof (EPluginMonoPrivate)); + + object_class = G_OBJECT_CLASS (class); + object_class->finalize = plugin_mono_finalize; + + plugin_class = E_PLUGIN_CLASS (class); + plugin_class->construct = plugin_mono_construct; + plugin_class->invoke = plugin_mono_invoke; + plugin_class->type = "mono"; +} + +static void +plugin_mono_init (EPluginMono *plugin_mono) +{ + GHashTable *methods; + + methods = g_hash_table_new_full ( + g_str_hash, g_str_equal, + (GDestroyNotify) g_free, + (GDestroyNotify) NULL); + + plugin_mono->priv = E_PLUGIN_MONO_GET_PRIVATE (plugin_mono); + plugin_mono->priv->methods = methods; +} + +GType +e_plugin_mono_get_type (void) +{ + return plugin_mono_type; +} + +void +e_plugin_mono_register_type (GTypeModule *type_module) +{ + static const GTypeInfo type_info = { + sizeof (EPluginMonoClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) plugin_mono_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + sizeof (EPluginMono), + 0, /* n_preallocs */ + (GInstanceInitFunc) plugin_mono_init, + NULL /* value_table */ + }; + + plugin_mono_type = g_type_module_register_type ( + type_module, E_TYPE_PLUGIN, + "EPluginMono", &type_info, 0); + + domain = mono_jit_init ("Evolution"); + mono_thread_attach (domain); +} diff --git a/modules/plugin-mono/e-plugin-mono.h b/modules/plugin-mono/e-plugin-mono.h new file mode 100644 index 0000000000..a4ed2d42ec --- /dev/null +++ b/modules/plugin-mono/e-plugin-mono.h @@ -0,0 +1,69 @@ +/* + * e-plugin-mono.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/> + * + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifndef E_PLUGIN_MONO_H +#define E_PLUGIN_MONO_H + +#include <e-util/e-plugin.h> + +/* Standard GObject macros */ +#define E_TYPE_PLUGIN_MONO \ + (e_plugin_mono_get_type ()) +#define E_PLUGIN_MONO(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_PLUGIN_MONO, EPluginMono)) +#define E_PLUGIN_MONO_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), E_TYPE_PLUGIN_MONO, EPluginMonoClass)) +#define E_IS_PLUGIN_MONO(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_PLUGIN_MONO)) +#define E_IS_PLUGIN_MONO_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), E_TYPE_PLUGIN_MONO)) +#define E_PLUGIN_MONO_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), E_TYPE_PLUGIN_MONO, EPluginMonoClass)) + +G_BEGIN_DECLS + +typedef struct _EPluginMono EPluginMono; +typedef struct _EPluginMonoClass EPluginMonoClass; +typedef struct _EPluginMonoPrivate EPluginMonoPrivate; + +struct _EPluginMono { + EPlugin parent; + EPluginMonoPrivate *priv; + + gchar *location; + gchar *handler; +}; + +struct _EPluginMonoClass { + EPluginClass parent_class; +}; + +GType e_plugin_mono_get_type (void); +void e_plugin_mono_register_type (GTypeModule *type_module); + +G_END_DECLS + +#endif /* E_PLUGIN_MONO_H */ diff --git a/modules/plugin-mono/evolution-module-plugin-mono.c b/modules/plugin-mono/evolution-module-plugin-mono.c new file mode 100644 index 0000000000..75ad534a47 --- /dev/null +++ b/modules/plugin-mono/evolution-module-plugin-mono.c @@ -0,0 +1,41 @@ +/* + * evolution-module-plugin-mono.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/> + * + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#include <config.h> + +#include "e-plugin-mono.h" + +/* Module Entry Points */ +void e_module_load (GTypeModule *type_module); +void e_module_unload (GTypeModule *type_module); + +G_MODULE_EXPORT void +e_module_load (GTypeModule *type_module) +{ + /* Register dynamically loaded types. */ + + e_plugin_mono_register_type (type_module); +} + +G_MODULE_EXPORT void +e_module_unload (GTypeModule *type_module) +{ +} diff --git a/modules/plugin-python/Makefile.am b/modules/plugin-python/Makefile.am new file mode 100644 index 0000000000..e6a32c3c83 --- /dev/null +++ b/modules/plugin-python/Makefile.am @@ -0,0 +1,31 @@ +AM_CPPFLAGS = \ + -DG_LOG_DOMAIN=\"evolution-plugin-python\" \ + -I$(top_srcdir) \ + $(E_UTIL_CFLAGS) \ + $(PY_INCLUDES) + +module_LTLIBRARIES = libevolution-module-plugin-python.la + +libevolution_module_plugin_python_la_SOURCES = \ + evolution-module-plugin-python.c \ + e-plugin-python.c \ + e-plugin-python.h + +libevolution_module_plugin_python_la_LIBADD = \ + -lpthread -ldl -lutil -lm \ + $(top_builddir)/e-util/libeutil.la \ + $(E_UTIL_LIBS) \ + $(PY_LIBS) + +libevolution_module_plugin_python_la_LDFLAGS = \ + -module -avoid-version $(NO_UNDEFINED) + +example_sources = \ + example/hello_python.py \ + example/org-gnome-hello-python-ui.xml \ + example/org-gnome-hello-python.eplug.xml \ + example/Makefile.am + +EXTRA_DIST = $(example_sources) + +-include $(top_srcdir)/git.mk diff --git a/modules/plugin-python/e-plugin-python.c b/modules/plugin-python/e-plugin-python.c new file mode 100644 index 0000000000..747ba57bac --- /dev/null +++ b/modules/plugin-python/e-plugin-python.c @@ -0,0 +1,230 @@ +/* + * e-plugin-python.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/> + * + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +/* Include <Python.h> first to avoid: + * warning: "_POSIX_C_SOURCE" redefined */ +#include <Python.h> + +#include "e-plugin-python.h" + +#include <sys/types.h> +#include <string.h> + +#define E_PLUGIN_PYTHON_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE \ + ((obj), E_TYPE_PLUGIN_PYTHON, EPluginPythonPrivate)) + +struct _EPluginPythonPrivate { + PyObject *pModule; + PyObject *pClass; + PyObject *pFunc; + PyObject *pDict; + GHashTable *methods; +}; + +static gpointer parent_class; +static GType plugin_python_type; + +static gchar * +get_xml_prop (xmlNodePtr node, const gchar *id) +{ + xmlChar *prop; + gchar *out = NULL; + + prop = xmlGetProp (node, (xmlChar *) id); + + if (prop != NULL) { + out = g_strdup ((gchar *) prop); + xmlFree (prop); + } + + return out; +} + +static void +plugin_python_finalize (GObject *object) +{ + EPluginPython *plugin_python; + + plugin_python = E_PLUGIN_PYTHON (object); + + g_free (plugin_python->location); + g_free (plugin_python->module_name); + g_free (plugin_python->pClass); + + g_hash_table_destroy (plugin_python->priv->methods); + + /* Chain up to parent's finalize() method. */ + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static gint +plugin_python_construct (EPlugin *plugin, xmlNodePtr root) +{ + EPluginPython *plugin_python; + + /* Chain up to parent's construct() method. */ + if (E_PLUGIN_CLASS (parent_class)->construct (plugin, root) == -1) + return -1; + + plugin_python = E_PLUGIN_PYTHON (plugin); + plugin_python->location = get_xml_prop (root, "location"); + plugin_python->module_name = get_xml_prop (root, "module_name"); + plugin_python->pClass = get_xml_prop (root, "pClass"); + + return (plugin_python->location != NULL) ? 0 : -1; +} + +static gpointer +plugin_python_invoke (EPlugin *plugin, + const gchar *name, + gpointer data) +{ + EPluginPython *plugin_python; + EPluginPythonPrivate *priv; + PyObject *pModuleName, *pFunc; + PyObject *pInstance, *pValue = NULL; + + plugin_python = E_PLUGIN_PYTHON (plugin); + priv = plugin_python->priv; + + /* We need to do this every time since we may be called + * from any thread for some uses. */ + Py_Initialize (); + + if (priv->pModule == NULL) { + gchar *string; + + pModuleName = PyString_FromString (plugin_python->module_name); + + string = g_strdup_printf ( + "import sys; " + "sys.path.insert(0, '%s')", + plugin_python->location); + PyRun_SimpleString (string); + g_free (string); + + priv->pModule = PyImport_Import (pModuleName); + + Py_DECREF (pModuleName); //Free + + if (priv->pModule == NULL) { + PyErr_Print (); + g_warning ( + "Can't load python module '%s'", + plugin_python->location); + return NULL; + } + + priv->pDict = PyModule_GetDict (priv->pModule); + + if (plugin_python->pClass != NULL) { + priv->pClass = PyDict_GetItemString ( + priv->pDict, plugin_python->pClass); + } + } + + if (priv->pClass) { + + if (PyCallable_Check (priv->pClass)) + pInstance = PyObject_CallObject (priv->pClass, NULL); + + pValue = PyObject_CallMethod (pInstance, (gchar *) name, NULL); + + } else { + + pFunc = PyDict_GetItemString (priv->pDict, name); + + if (pFunc && PyCallable_Check (pFunc)) + pValue = PyObject_CallObject (pFunc, NULL); + else + PyErr_Print (); + } + + if (pValue) { + Py_DECREF(pValue); + /* Fixme */ + return NULL; + } else + return NULL; +} + +static void +plugin_python_class_init (EPluginPythonClass *class) +{ + GObjectClass *object_class; + EPluginClass *plugin_class; + + parent_class = g_type_class_peek_parent (class); + g_type_class_add_private (class, sizeof (EPluginPythonPrivate)); + + object_class = G_OBJECT_CLASS (class); + object_class->finalize = plugin_python_finalize; + + plugin_class = E_PLUGIN_CLASS (class); + plugin_class->construct = plugin_python_construct; + plugin_class->invoke = plugin_python_invoke; + plugin_class->type = "python"; +} + +static void +plugin_python_init (EPluginPython *plugin_python) +{ + GHashTable *methods; + + methods = g_hash_table_new_full ( + g_str_hash, g_str_equal, + (GDestroyNotify) g_free, + (GDestroyNotify) NULL); + + plugin_python->priv = E_PLUGIN_PYTHON_GET_PRIVATE (plugin_python); + plugin_python->priv->methods = methods; +} + +GType +e_plugin_python_get_type (void) +{ + return plugin_python_type; +} + +void +e_plugin_python_register_type (GTypeModule *type_module) +{ + static const GTypeInfo type_info = { + sizeof (EPluginPythonClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) plugin_python_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + sizeof (EPluginPython), + 0, /* n_preallocs */ + (GInstanceInitFunc) plugin_python_init, + NULL /* value_table */ + }; + + plugin_python_type = g_type_module_register_type ( + type_module, E_TYPE_PLUGIN, + "EPluginPython", &type_info, 0); + + /* TODO Does this mean I can cache the instance of pyobjects? */ + Py_Initialize (); +} diff --git a/modules/plugin-python/e-plugin-python.h b/modules/plugin-python/e-plugin-python.h new file mode 100644 index 0000000000..9ee780c76c --- /dev/null +++ b/modules/plugin-python/e-plugin-python.h @@ -0,0 +1,70 @@ +/* + * e-plugin-python.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/> + * + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifndef E_PLUGIN_PYTHON_H +#define E_PLUGIN_PYTHON_H + +#include <e-util/e-plugin.h> + +/* Standard GObject macros */ +#define E_TYPE_PLUGIN_PYTHON \ + (e_plugin_python_get_type ()) +#define E_PLUGIN_PYTHON(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_PLUGIN_PYTHON, EPluginPython)) +#define E_PLUGIN_PYTHON_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), E_TYPE_PLUGIN_PYTHON, EPluginPythonClass)) +#define E_IS_PLUGIN_PYTHON(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_PLUGIN_PYTHON)) +#define E_IS_PLUGIN_PYTHON_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), E_TYPE_PLUGIN_PYTHON)) +#define E_PLUGIN_PYTHON_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), E_TYPE_PLUGIN_PYTHON, EPluginPythonClass)) + +G_BEGIN_DECLS + +typedef struct _EPluginPython EPluginPython; +typedef struct _EPluginPythonClass EPluginPythonClass; +typedef struct _EPluginPythonPrivate EPluginPythonPrivate; + +struct _EPluginPython { + EPlugin parent; + EPluginPythonPrivate *priv; + + gchar *location; + gchar *pClass; + gchar *module_name; +}; + +struct _EPluginPythonClass { + EPluginClass parent_class; +}; + +GType e_plugin_python_get_type (void); +void e_plugin_python_register_type (GTypeModule *type_module); + +G_END_DECLS + +#endif /* E_PLUGIN_PYTHON_H */ diff --git a/modules/plugin-python/evolution-module-plugin-python.c b/modules/plugin-python/evolution-module-plugin-python.c new file mode 100644 index 0000000000..84ab3b3e8c --- /dev/null +++ b/modules/plugin-python/evolution-module-plugin-python.c @@ -0,0 +1,41 @@ +/* + * evolution-module-plugin-python.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/> + * + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#include <config.h> + +#include "e-plugin-python.h" + +/* Module Entry Points */ +void e_module_load (GTypeModule *type_module); +void e_module_unload (GTypeModule *type_module); + +G_MODULE_EXPORT void +e_module_load (GTypeModule *type_module) +{ + /* Register dynamically loaded types. */ + + e_plugin_python_register_type (type_module); +} + +G_MODULE_EXPORT void +e_module_unload (GTypeModule *type_module) +{ +} diff --git a/modules/plugin-python/example/Makefile.am b/modules/plugin-python/example/Makefile.am new file mode 100644 index 0000000000..cc14dc94d9 --- /dev/null +++ b/modules/plugin-python/example/Makefile.am @@ -0,0 +1,29 @@ +AM_CPPFLAGS = \ + -DEVOLUTION_GLADEDIR=\""$(gladedir)"\" \ + -DEVOLUTION_IMAGESDIR=\""$(imagesdir)"\" + +@EVO_PLUGIN_RULE@ + +plugin_DATA = \ + hello_python.py \ + org-gnome-hello-python-ui.xml \ + org-gnome-hello-python.eplug + +liborg_gnome_py_plug_test_la_LDFLAGS = -module -avoid-version $(NO_UNDEFINED) + +errordir = $(privdatadir)/errors + +BUILDME = org-gnome-hello-python.eplug \ +$(error_i18n) + +BUILT_SOURCES = \ + $(BUILDME) + +EXTRA_DIST = \ + hello_python.py \ + org-gnome-hello-python-ui.xml \ + org-gnome-hello-python.eplug.xml + +CLEANFILES = $(BUILT_SOURCES) + +-include $(top_srcdir)/git.mk diff --git a/modules/plugin-python/example/hello_python.py b/modules/plugin-python/example/hello_python.py new file mode 100644 index 0000000000..16dc2a12f8 --- /dev/null +++ b/modules/plugin-python/example/hello_python.py @@ -0,0 +1,5 @@ +'''hello_python.py - Python source designed to ''' +'''demonstrate the use of python Eplugins''' + +def say_hello(): + print 'Hello ! From python' diff --git a/modules/plugin-python/example/org-gnome-hello-python-ui.xml b/modules/plugin-python/example/org-gnome-hello-python-ui.xml new file mode 100644 index 0000000000..074960e84d --- /dev/null +++ b/modules/plugin-python/example/org-gnome-hello-python-ui.xml @@ -0,0 +1,16 @@ +<Root> + <commands> + <cmd name="HelloPy" _label="Hello Python" + _tip="Python Plugin Loader tests" + /> + </commands> + + <menu> + <placeholder name="MessagePlaceholder"> + <submenu name="Message"> + <separator f="" name="sep"/> + <menuitem name="HelloPy" verb=""/> + </submenu> + </placeholder> + </menu> +</Root> diff --git a/modules/plugin-python/example/org-gnome-hello-python.eplug.xml b/modules/plugin-python/example/org-gnome-hello-python.eplug.xml new file mode 100644 index 0000000000..8f77d5ba01 --- /dev/null +++ b/modules/plugin-python/example/org-gnome-hello-python.eplug.xml @@ -0,0 +1,20 @@ +<?xml version="1.0"?> +<e-plugin-list> + <e-plugin id="org.gnome.evolution.hello_python" type="python" _name="Python Test Plugin" location="@PLUGINDIR@" module_name="hello_python"> + + <author name="Johnny Jacob" email="jjohnny@novell.com"/> + + <_description> + Test Plugin for Python EPlugin loader. + </_description> + + <hook class="org.gnome.evolution.mail.bonobomenu:1.0"> + <menu id="org.gnome.evolution.mail.browser" target="select"> + <!-- the path to the bonobo menu description. Any UI items on Evolution should come here --> + <ui file="@PLUGINDIR@/org-gnome-hello-python-ui.xml"/> + <item type="item" verb="HelloPy" path="/commands/HelloPy" enable="one" activate="say_hello"/> + </menu> + </hook> + + </e-plugin> +</e-plugin-list> |