Sylpheed Plugin Specification
=============================

The following is the architecture of plugin system of Sylpheed.

 +----------+    +----------------------+     +-----------+
 | Sylpheed |----| libsylpheed-plugin-0 |--+--| Plug-in A |
 +----------+    +----------------------+  |  +-----------+
   Sylpheed         Plug-in interface      |   Plug-in DLL
                    library             +--+
        |        +------------+         |  |  +-----------+
        +--------| libsylph-0 |---------+  +--| Plug-in B |
                 +------------+               +-----------+
                 LibSylph mail library

Sylpheed loads the plug-in DLLs installed in the plug-in directory on
startup.

Plug-in can only access the functions of Sylpheed through the APIs provided
with libsylpheed-plugin-0 and libsylph-0 library.

There are two kinds of plug-in API. One is called directly from plug-ins,
another one utilizes the signal mechanism of GObject and calls the callback
functions on specific events.

The plug-in system is implemented in libsylph/sylmain.[ch] and
src/plugin.[ch].


Plug-in API
===========

Functions used by Sylpheed
--------------------------

-------------------------------------------------------------------------
void syl_plugin_signal_connect  (const gchar *name, GCallback callback,
                                 gpointer data);

Connects to signals available with SylPlugin object (obtained inside library).
The specification of callback functions that receive signals is similar to
that of normal GObject.
Refer to the signals list for available signals.
-------------------------------------------------------------------------
void syl_plugin_signal_disconnect(gpointer func, gpointer data);

Disconnects signals connected by syl_plugin_signal_connect().
-------------------------------------------------------------------------
void syl_plugin_signal_emit(const gchar *name, ...);

Emits SylPlugin object signals.
-------------------------------------------------------------------------
gint syl_plugin_init_lib        (void);

Initializes the libsylpheed-plugin-0 library.
-------------------------------------------------------------------------
gint syl_plugin_load            (const gchar *file);

Loads plug-in DLL files into memory.
-------------------------------------------------------------------------
gint syl_plugin_load_all        (const gchar *dir);

Loads plug-in DLL files in the specified directory into memory.
-------------------------------------------------------------------------
void syl_plugin_unload_all      (void);

Unloads all loaded plug-ins.
-------------------------------------------------------------------------
GSList *syl_plugin_get_module_list      (void);

Obtains the list of plug-ins loaded into memory.
It returns the list of pointers to GModule struct.
The list is obtained by the library internally, so it must not be freed.
-------------------------------------------------------------------------
SylPluginInfo *syl_plugin_get_info      (GModule *module);

Obtains plug-in information. The information is returned as SylPluginInfo
struct.
-------------------------------------------------------------------------
gboolean syl_plugin_check_version       (GModule *module);

Compares plug-in interface versions and checks if the plug-in is compatible.
Returns TRUE if the version matches, FALSE otherwise.
-------------------------------------------------------------------------
gint syl_plugin_add_symbol              (const gchar *name, gpointer sym);

Registers symbol name and pointer value related to it to the library.
-------------------------------------------------------------------------
gpointer syl_plugin_lookup_symbol       (const gchar *name);

Searches symbol registered by syl_plugin_add_symbol() and returns its
pointer value.
-------------------------------------------------------------------------


Functions which must be implemented by plug-ins
-----------------------------------------------

-------------------------------------------------------------------------
void plugin_load(void)

Called from Sylpheed on plug-in load.
Do initialization of plug-in etc. here.
-------------------------------------------------------------------------
void plugin_unload(void)

Called from Sylpheed on plug-in unload.
Do finalization of plug-in etc. here.
-------------------------------------------------------------------------
SylPluginInfo *plugin_info(void)

Fuction to return struct which stores plug-in information to Sylpheed.
It normally returns pointer to static struct.
-------------------------------------------------------------------------
gint plugin_interface_version(void)

Function to return plug-in API interface version to Sylpheed.
A plug-in normally returns constant value SYL_PLUGIN_INTERFACE_VERSION.
Sylpheed compares this value with its own value and checks if it is
compatible. Sylpheed's plug-in interface version must be equal to or greater
than the plug-in's plug-in interface verson. If the major versions of the
interface version differ, they are treated as incompatible.

Ex.1: Sylpheed plug-in interface version: 0x0102
      A plug-in plug-in interface version: 0x0100: OK
Ex.2: Sylpheed plug-in interface version: 0x0102
      A plug-in plug-in interface version: 0x0103: NG
-------------------------------------------------------------------------


Functions used by plug-ins
--------------------------

Refer to the header file plugin.h for the functions list.


Signals list
------------

* libsylpheed-plugin-0

Call syl_plugin_signal_connect() to use the following signals.

Example:
  syl_plugin_signal_connect("plugin-load", G_CALLBACK(plugin_load_cb), data);

-------------------------------------------------------------------------
void (* plugin_load)    (GObject *obj, GModule *module);

Emitted on plug-in loading by syl_plugin_load().
-------------------------------------------------------------------------
void (* plugin_unload)  (GObject *obj, GModule *module);

Emitted on plug-in unloading by syl_plugin_unload_all().
-------------------------------------------------------------------------
void (* folderview_menu_popup)  (GObject *obj, gpointer ifactory);

Emitted on popup of the context menu of FolderView.
-------------------------------------------------------------------------
void (* summaryview_menu_popup)  (GObject *obj, gpointer ifactory);

Emitted on popup of the context menu of SummaryView.
-------------------------------------------------------------------------
void (* compose_created)        (GObject *obj, gpointer compose);

Emitted on creating 'Compose' message composition window.
-------------------------------------------------------------------------
void (* compose_destroy)        (GObject *obj, gpointer compose);

Emitted just before 'Compose' message composition window is destroyed.
-------------------------------------------------------------------------
void (* textview_menu_popup)    (GObject *obj,
                                 GtkMenu *menu,
                                 GtkTextView *textview,
                                 const gchar *uri,
                                 const gchar *selected_text,
                                 MsgInfo *msginfo);

Emitted on popup of the context menu of TextView.
You can add any menu items to the passed GtkMenu.
The menu object will be created on open and destroyed on close, so menu items
must be added each time.

menu: context menu object
textview: GtkTextView object
uri: URI string if the menu popups on an URI
selected_text: string if a string is selected on the text view
msginfo: the MsgInfo message object displayed in the text view
-------------------------------------------------------------------------
gboolean (* compose_send)       (GObject        *obj,
                                 gpointer        compose,
                                 gint            compose_mode,
                                 gint            send_mode,
                                 const gchar    *msg_file,
                                 GSList         *to_list);

Emitted on a composed message is being sent.
If FALSE is returned, the message is sent normally.
If TRUE is returned, sending is cancelled.

compose: the Compose object
compose_mode: ComposeMode enum
send_mode: 0: send immediately 1: queue and send later
msg_file: path to the created message file
to_list: list of recipients
-------------------------------------------------------------------------
void (* messageview_show)       (GObject        *obj,
                                 gpointer        msgview,
                                 MsgInfo        *msginfo,
                                 gboolean        all_headers);

Emitted on displaying a message.

msgview: the MessageView object
msginfo: the MsgInfo message object displayed
all_headers: TRUE if all headers are displayed. FALSE if not.
-------------------------------------------------------------------------
void (* inc_mail_start)         (GObject        *obj,
                                 PrefsAccount   *account);

Emitted on the start of receiving.

account: receive target account (PrefsAccount)
-------------------------------------------------------------------------
void (* inc_mail_finished)      (GObject        *obj,
                                 gint            new_messages);

Emitted on the end of receiving.

new_messages: number of received messages
-------------------------------------------------------------------------
void (* prefs_common_open)      (GObject        *obj,
                                 GtkWidget      *window);

Emitted on opening common preferences dialog.

window: dialog window (GtkWindow)
-------------------------------------------------------------------------
void (* prefs_account_open)     (GObject        *obj,
                                 PrefsAccount   *account,
                                 GtkWidget      *window);

Emitted on opening account preferences dialog.

window: dialog window (GtkWindow)
-------------------------------------------------------------------------
void (* prefs_filter_open)      (GObject        *obj,
                                 GtkWidget      *window);

Emitted on opening filter rule preferences dialog.

window: dialog window (GtkWindow)
-------------------------------------------------------------------------
void (* prefs_filter_edit_open) (GObject        *obj,
                                 FilterRule     *rule,
                                 const gchar    *header,
                                 const gchar    *key,
                                 GtkWidget      *window);

Emitted on opening filter rule edit dialog.

window: dialog window (GtkWindow)
-------------------------------------------------------------------------
void (* prefs_template_open)    (GObject        *obj,
                                 GtkWidget      *window);

Emitted on opening template dialog.

window: dialog window (GtkWindow)
-------------------------------------------------------------------------
void (* plugin_manager_open)    (GObject        *obj,
                                 GtkWidget      *window);

Emitted on opening plug-in manager dialog.

window: dialog window (GtkWindow)
-------------------------------------------------------------------------
void (* main_window_toolbar_changed) (GObject *obj);

Emitted on toolbar change of main window.
Use syl_plugin_main_window_get_toolbar() to get main window toolbar object.
-------------------------------------------------------------------------
void (* compose_toolbar_changed)     (GObject *obj, gpointer compose);

Emitted on toolbar change of compose window.
Use syl_plugin_compose_get_toolbar() to get compose toolbar object.

compose: Compose object
-------------------------------------------------------------------------
void (* compose_attach_changed)     (GObject *obj, gpointer compose);

Emitted when attachments in compose window are changed.
Use syl_plugin_get_attach_list() to get the list of current attachments.

compose: Compose object
-------------------------------------------------------------------------

* libsylph-0

The following signals can be used by passing GObject obtained by
syl_app_get() to the first argument of g_signal_connect().

Example:

void init_done_cb(GObject *obj, gpointer data)
{
    ...
}

    g_signal_connect(syl_app_get(), "init-done", G_CALLBACK(init_done_cb),
                     data);

-------------------------------------------------------------------------
void (* init_done) (GObject *obj)

Emitted when the initialization of application completes.
-------------------------------------------------------------------------
void (* app_exit) (GObject *obj)

Emitted when application exits.
-------------------------------------------------------------------------
void (* app_force_exit) (GObject *obj)

Emitted when application is forced to exit (no confirmation).
(ex: sylpheed --exit)
-------------------------------------------------------------------------
void (* add_msg) (GObject *obj, FolderItem *item, const gchar *file, guint num)

Emitted when a message (number num) is added into folder item.
-------------------------------------------------------------------------
void (* remove_msg) (GObject *obj, FolderItem *item, const gchar *file,
                     guint num)

Emitted when a message (number num) is removed from folder item.
-------------------------------------------------------------------------
void (* remove_all_msg) (GObject *obj, FolderItem *item)

Emitted when all messages are removed from folder item.
-------------------------------------------------------------------------
void (* remove_folder) (GObject *obj, FolderItem *item)

Emitted when folder item is removed.
-------------------------------------------------------------------------
void (* move_folder) (GObject *obj, FolderItem *item, const gchar *old_id,
                      const gchar *new_id)

Emitted when folder item is moved (renamed) from old_id to new_id.
old_id and new_id are folder identifier strings.
-------------------------------------------------------------------------
void (* folderlist_updated) (GObject *obj)

Emitted when folder information is modified and folderlist.xml, which
contains folder list, is updated.
-------------------------------------------------------------------------
void (* account_updated) (GObject *obj)

Emitted on the update of account information.
It will not be emitted if it is locked by account_update_lock(), though.
-------------------------------------------------------------------------


Sample plug-ins
===============

There is sample plug-ins under the 'plugin' directory.
These plug-ins will not be installed with 'make install'.
It is required to enter the directory plugin/* and run
'make install-plugin'.

Test Plug-in
------------

The 'test' plug-in has the basic structure of Sylpheed plug-in and the
following process:

- Output string "test plug-in loaded!" to stdout on load
- Get folder list and output to stdout
- Get Sylpheed version string and output to stdout
- Get the main window and put it in front
- Add sub widget under the folder view
- Add 'Plugin test' menu item on the 'Tools' menu
- When 'Plugin test' menu is selected, a window with a button named
  'Click this button' is displayed. When it is clicked, a message is displayed
- Capture the following events and show messages: application initialization
  and exiting, folder view context menu popup, creating and destroying compose
  window, sending messages
- Capture the text view context menu popup event and add a menu item

Attachment Tool Plug-in
-----------------------

This is a plug-in for handling messages with attached files.

See plugin/attachment_tool/README for the details.


About license
=============

It is required that a plug-in DLL dynamically loaded by Sylpheed is GPL or
GPL-compatible license (ex. modified BSD license) based on the GPL clause
because the license of Sylpheed itself is GPL.

If you want to apply non-GPL license like proprietary license to your plug-in,
you must make the module an independent executable file, and make it work with
inter-process communication with a DLL.
