aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorhiro <hiro@ee746299-78ed-0310-b773-934348b2243d>2009-06-10 08:11:08 +0000
committerhiro <hiro@ee746299-78ed-0310-b773-934348b2243d>2009-06-10 08:11:08 +0000
commitca06cd994b09cbb500b35af30c8bd75dc3e0e5b7 (patch)
tree3474db42cb4b1c42007cfb84ec24ca8331b50dba /src
parent81f0f7394f9c47a30314f2884be6d4bdae302673 (diff)
merged plugin-test branch into trunk.
git-svn-id: svn://sylpheed.sraoss.jp/sylpheed/trunk@2164 ee746299-78ed-0310-b773-934348b2243d
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am30
-rw-r--r--src/about.c4
-rw-r--r--src/folderview.c15
-rw-r--r--src/libsylpheed-plugin-0.def41
-rw-r--r--src/main.c196
-rw-r--r--src/mainwindow.c24
-rw-r--r--src/manage_window.c5
-rw-r--r--src/manage_window.h1
-rw-r--r--src/plugin.c644
-rw-r--r--src/plugin.h175
-rw-r--r--src/plugin_manager.c227
-rw-r--r--src/plugin_manager.h29
-rw-r--r--src/prefs_common_dialog.c69
-rw-r--r--src/update_check.c255
-rw-r--r--src/update_check.h29
-rw-r--r--src/version.h.in6
16 files changed, 1642 insertions, 108 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index bc25307e..bfe67d2d 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -89,6 +89,8 @@ sylpheed_SOURCES = \
trayicon.c trayicon.h \
printing.c printing.h \
sslmanager.c sslmanager.h \
+ plugin_manager.c plugin_manager.h \
+ update_check.c update_check.h \
quote_fmt_lex.l quote_fmt_lex.h \
quote_fmt_parse.y quote_fmt.h \
sylpheed-marshal.c sylpheed-marshal.h
@@ -100,11 +102,33 @@ BUILT_SOURCES = \
sylpheed-marshal.c \
sylpheed-marshal.h
+lib_LTLIBRARIES = libsylpheed-plugin-0.la
+
+libsylpheed_plugin_0_la_SOURCES = \
+ plugin.c
+
+libsylpheed_plugin_0includedir=$(includedir)/sylpheed
+libsylpheed_plugin_0include_HEADERS = \
+ plugin.h
+
+if NATIVE_WIN32
+no_undefined = -no-undefined
+export_symbols = -export-symbols libsylpheed-plugin-0.def
+endif
+
+libsylpheed_plugin_0_la_LDFLAGS = \
+ -export-dynamic $(no_undefined) $(export_symbols)
+
+libsylpheed_plugin_0_la_LIBADD = \
+ $(GTK_LIBS) \
+ ../libsylph/libsylph-0.la
+
EXTRA_DIST = \
quote_fmt_parse.h \
sylpheed-marshal.list \
version.h.in \
- sylpheed.rc.in
+ sylpheed.rc.in \
+ libsylpheed-plugin-0.def
INCLUDES = \
-DG_LOG_DOMAIN=\"Sylpheed\" \
@@ -128,13 +152,15 @@ sylpheed_LDADD = \
$(GPGME_LIBS) \
$(LDAP_LIBS) \
$(LIBICONV) \
- ../libsylph/libsylph.la \
+ libsylpheed-plugin-0.la \
+ ../libsylph/libsylph-0.la \
$(SYLPHEED_RES)
AM_CPPFLAGS = \
-DLOCALEDIR=\""$(localedir)"\" \
-DMANUALDIR=\""$(manualdir)"\" \
-DFAQDIR=\""$(faqdir)"\" \
+ -DPLUGINDIR=\""$(plugindir)"\" \
-DTARGET_ALIAS=\""$(target_triplet)"\" \
-DSYSCONFDIR=\""$(sysconfdir)"\"
diff --git a/src/about.c b/src/about.c
index 6e22e9b2..01e7a24d 100644
--- a/src/about.c
+++ b/src/about.c
@@ -1,6 +1,6 @@
/*
* Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 1999-2008 Hiroyuki Yamamoto
+ * Copyright (C) 1999-2009 Hiroyuki Yamamoto
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -175,7 +175,7 @@ static void about_create(void)
gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
label = gtk_label_new
- ("Copyright (C) 1999-2008 Hiroyuki Yamamoto <hiro-y@kcn.ne.jp>");
+ ("Copyright (C) 1999-2009 Hiroyuki Yamamoto <hiro-y@kcn.ne.jp>");
gtk_label_set_selectable(GTK_LABEL(label), TRUE);
gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
diff --git a/src/folderview.c b/src/folderview.c
index 17272447..1c0aeb7a 100644
--- a/src/folderview.c
+++ b/src/folderview.c
@@ -69,6 +69,7 @@
#include "inc.h"
#include "send_message.h"
#include "virtual.h"
+#include "plugin.h"
enum
{
@@ -1773,10 +1774,11 @@ static gboolean folderview_menu_popup(FolderView *folderview,
SET_VISIBILITY(ifactory, "/Edit search condition...",
item->stype == F_VIRTUAL);
-
#undef SET_SENS
#undef SET_VISIBILITY
+ syl_plugin_signal_emit("folderview-menu-popup", ifactory);
+
gtk_menu_popup(GTK_MENU(popup), NULL, NULL, NULL, NULL,
event->button, event->time);
@@ -2282,6 +2284,16 @@ static void folderview_new_folder_cb(FolderView *folderview, guint action,
if (!new_folder) return;
AUTORELEASE_STR(new_folder, {g_free(new_folder); return;});
+#ifdef G_OS_WIN32
+ p = strpbrk(new_folder, "\\/:*?\"<>|");
+ if ((p && FOLDER_TYPE(item->folder) != F_IMAP) || (p && *p != '/') ||
+ (p && p == '/' &&
+ FOLDER_TYPE(item->folder) == F_IMAP && *(p + 1) != '\0')) {
+ alertpanel_error(_("`%c' can't be included in folder name."),
+ *p);
+ return;
+ }
+#else
p = strchr(new_folder, G_DIR_SEPARATOR);
if ((p && FOLDER_TYPE(item->folder) != F_IMAP) ||
(p && FOLDER_TYPE(item->folder) == F_IMAP && *(p + 1) != '\0')) {
@@ -2289,6 +2301,7 @@ static void folderview_new_folder_cb(FolderView *folderview, guint action,
G_DIR_SEPARATOR);
return;
}
+#endif
name = trim_string(new_folder, 32);
AUTORELEASE_STR(name, {g_free(name); return;});
diff --git a/src/libsylpheed-plugin-0.def b/src/libsylpheed-plugin-0.def
new file mode 100644
index 00000000..af7f91cd
--- /dev/null
+++ b/src/libsylpheed-plugin-0.def
@@ -0,0 +1,41 @@
+; c:\MinGW\bin\dlltool.exe -z libsylpheed-plugin-0.def --export-all-symbols .libs/plugin.o
+EXPORTS
+ syl_plugin_add_factory_item @ 1
+ syl_plugin_add_menuitem @ 2
+ syl_plugin_add_symbol @ 3
+ syl_plugin_app_will_exit @ 4
+ syl_plugin_folder_sel @ 5
+ syl_plugin_folder_sel_full @ 6
+ syl_plugin_folderview_get @ 7
+ syl_plugin_folderview_get_selected_item @ 8
+ syl_plugin_get_prog_version @ 9
+ syl_plugin_get_type @ 10
+ syl_plugin_inc_lock @ 11
+ syl_plugin_inc_mail @ 12
+ syl_plugin_inc_unlock @ 13
+ syl_plugin_init_lib @ 14
+ syl_plugin_input_dialog @ 15
+ syl_plugin_input_dialog_with_invisible @ 16
+ syl_plugin_load @ 17
+ syl_plugin_load_all @ 18
+ syl_plugin_main_window_get @ 19
+ syl_plugin_main_window_popup @ 20
+ syl_plugin_manage_window_set_transient @ 21
+ syl_plugin_manage_window_signals_connect @ 22
+ syl_plugin_messageview_create_with_new_window @ 23
+ syl_plugin_open_message @ 24
+ syl_plugin_open_message_by_new_window @ 25
+ syl_plugin_signal_connect @ 26
+ syl_plugin_signal_disconnect @ 27
+ syl_plugin_signal_emit @ 28
+ syl_plugin_sumary_select_by_msgnum @ 29
+ syl_plugin_summary_select_by_msginfo @ 30
+ syl_plugin_summary_view_get @ 31
+ syl_plugin_unload_all @ 32
+ syl_plugin_get_module_list @ 33
+ syl_plugin_get_info @ 34
+ syl_plugin_check_version @ 35
+ syl_plugin_menu_set_sensitive @ 36
+ syl_plugin_menu_set_sensitive_all @ 37
+ syl_plugin_menu_set_active @ 38
+ syl_plugin_manage_window_get_focus_window @ 39
diff --git a/src/main.c b/src/main.c
index 8c934f44..50e7cc0a 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1,6 +1,6 @@
/*
* Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 1999-2008 Hiroyuki Yamamoto
+ * Copyright (C) 1999-2009 Hiroyuki Yamamoto
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -75,11 +75,16 @@
#include "logwindow.h"
#include "folder.h"
#include "setup.h"
+#include "sylmain.h"
#include "utils.h"
#include "gtkutils.h"
#include "socket.h"
#include "stock_pixmap.h"
#include "trayicon.h"
+#include "plugin.h"
+#include "plugin_manager.h"
+#include "foldersel.h"
+#include "update_check.h"
#if USE_GPGME
# include "rfc2015.h"
@@ -136,6 +141,7 @@ static void setup_rc_dir (void);
static void check_gpg (void);
static void set_log_handlers (gboolean enable);
static void register_system_events (void);
+static void plugin_init (void);
static gchar *get_socket_name (void);
static gint prohibit_duplicate_launch (void);
@@ -174,6 +180,10 @@ static void send_queue (void);
exit(val); \
}
+static void load_cb(GObject *obj, GModule *module, gpointer data)
+{
+ g_print("load_cb: %p (%s), %p\n", module, module ? g_module_name(module) : "(null)", data);
+}
int main(int argc, char *argv[])
{
@@ -183,15 +193,11 @@ int main(int argc, char *argv[])
#ifdef G_OS_WIN32
GList *iconlist = NULL;
#endif
+ GObject *syl_app;
app_init();
parse_cmd_opt(argc, argv);
- sock_init();
-#if USE_SSL
- ssl_init();
-#endif
-
/* check and create (unix domain) socket for remote operation */
lock_socket = prohibit_duplicate_launch();
if (lock_socket < 0) return 0;
@@ -205,6 +211,8 @@ int main(int argc, char *argv[])
gtk_set_locale();
gtk_init(&argc, &argv);
+ syl_app = syl_app_create();
+
gdk_rgb_init();
gtk_widget_set_default_colormap(gdk_rgb_get_cmap());
gtk_widget_set_default_visual(gdk_rgb_get_visual());
@@ -324,7 +332,13 @@ int main(int argc, char *argv[])
inc_autocheck_timer_init(mainwin);
+ plugin_init();
+
+ g_signal_emit_by_name(syl_app, "init-done");
+
remote_command_exec();
+ if (prefs_common.auto_update_check)
+ update_check(FALSE);
gtk_main();
@@ -568,70 +582,9 @@ static gint get_queued_message_num(void)
static void app_init(void)
{
-#ifdef G_OS_WIN32
- gchar *newpath;
- const gchar *lang_env;
-
- /* disable locale variable such as "LANG=1041" */
-
-#define DISABLE_DIGIT_LOCALE(envstr) \
-{ \
- lang_env = g_getenv(envstr); \
- if (lang_env && g_ascii_isdigit(lang_env[0])) \
- g_unsetenv(envstr); \
-}
-
- DISABLE_DIGIT_LOCALE("LC_ALL");
- DISABLE_DIGIT_LOCALE("LANG");
- DISABLE_DIGIT_LOCALE("LC_CTYPE");
- DISABLE_DIGIT_LOCALE("LC_MESSAGES");
-
-#undef DISABLE_DIGIT_LOCALE
-
- g_unsetenv("LANGUAGE");
-#endif
-
-#ifdef HAVE_LOCALE_H
- setlocale(LC_ALL, "");
-#endif
+ syl_init();
prog_version = PROG_VERSION;
- set_startup_dir();
-
-#ifdef G_OS_WIN32
- /* include startup directory into %PATH% for GSpawn */
- newpath = g_strconcat(get_startup_dir(), ";", g_getenv("PATH"), NULL);
- g_setenv("PATH", newpath, TRUE);
- g_free(newpath);
-#endif
-
-#ifdef ENABLE_NLS
- if (g_path_is_absolute(LOCALEDIR))
- bindtextdomain(PACKAGE, LOCALEDIR);
- else {
- gchar *locale_dir;
-
- locale_dir = g_strconcat(get_startup_dir(), G_DIR_SEPARATOR_S,
- LOCALEDIR, NULL);
-#ifdef G_OS_WIN32
- {
- gchar *locale_dir_;
-
- locale_dir_ = g_locale_from_utf8(locale_dir, -1,
- NULL, NULL, NULL);
- if (locale_dir_) {
- g_free(locale_dir);
- locale_dir = locale_dir_;
- }
- }
-#endif /* G_OS_WIN32 */
- bindtextdomain(PACKAGE, locale_dir);
- g_free(locale_dir);
- }
-
- bind_textdomain_codeset(PACKAGE, CS_UTF_8);
- textdomain(PACKAGE);
-#endif /* ENABLE_NLS */
#ifdef G_OS_WIN32
read_ini_file();
@@ -704,24 +657,7 @@ static void setup_rc_dir(void)
}
#endif /* !G_OS_WIN32 */
- if (!is_dir_exist(get_rc_dir())) {
- if (make_dir_hier(get_rc_dir()) < 0)
- exit(1);
- }
-
- MAKE_DIR_IF_NOT_EXIST(get_mail_base_dir());
-
- CHDIR_EXIT_IF_FAIL(get_rc_dir(), 1);
-
- MAKE_DIR_IF_NOT_EXIST(get_imap_cache_dir());
- MAKE_DIR_IF_NOT_EXIST(get_news_cache_dir());
- MAKE_DIR_IF_NOT_EXIST(get_mime_tmp_dir());
- MAKE_DIR_IF_NOT_EXIST(get_tmp_dir());
- MAKE_DIR_IF_NOT_EXIST(UIDL_DIR);
-
- /* remove temporary files */
- remove_all_files(get_tmp_dir());
- remove_all_files(get_mime_tmp_dir());
+ syl_setup_rc_dir();
}
void app_will_exit(gboolean force)
@@ -760,6 +696,8 @@ void app_will_exit(gboolean force)
manage_window_focus_in(mainwin->window, NULL, NULL);
}
+ g_signal_emit_by_name(syl_app_get(), "app-exit");
+
inc_autocheck_timer_remove();
if (prefs_common.clean_on_exit)
@@ -773,36 +711,26 @@ void app_will_exit(gboolean force)
procmsg_remove_all_cached_messages(FOLDER(ac->folder));
}
+ syl_plugin_unload_all();
+
trayicon_destroy(mainwin->tray_icon);
/* save all state before exiting */
- folder_write_list();
summary_write_cache(mainwin->summaryview);
-
main_window_get_size(mainwin);
main_window_get_position(mainwin);
- prefs_common_write_config();
- filter_write_config();
- account_write_config_all();
+ syl_save_all_state();
addressbook_export_to_file();
filename = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, MENU_RC, NULL);
gtk_accel_map_save(filename);
g_free(filename);
- /* remove temporary files */
- remove_all_files(get_tmp_dir());
- remove_all_files(get_mime_tmp_dir());
-
- set_log_handlers(FALSE);
- close_log_file();
+ /* remove temporary files, close log file, socket cleanup */
+ syl_cleanup();
lock_socket_remove();
-#if USE_SSL
- ssl_done();
-#endif
cleanup_console();
- sock_cleanup();
if (gtk_main_level() > 0)
gtk_main_quit();
@@ -1080,6 +1008,72 @@ static void register_system_events(void)
}
#endif
+static void plugin_init(void)
+{
+ MainWindow *mainwin;
+
+ mainwin = main_window_get();
+
+ if (syl_plugin_init_lib() != 0)
+ return;
+
+ syl_plugin_add_symbol("prog_version", prog_version);
+ syl_plugin_add_symbol("main_window_get", main_window_get);
+ syl_plugin_add_symbol("main_window_popup", main_window_popup);
+ syl_plugin_add_symbol("app_will_exit", app_will_exit);
+ syl_plugin_add_symbol("main_window_menu_factory",
+ mainwin->menu_factory);
+
+ syl_plugin_add_symbol("folderview", mainwin->folderview);
+ syl_plugin_add_symbol("folderview_get_selected_item",
+ folderview_get_selected_item);
+ syl_plugin_add_symbol("folderview_mail_popup_factory",
+ mainwin->folderview->mail_factory);
+
+ syl_plugin_add_symbol("summaryview", mainwin->summaryview);
+ syl_plugin_add_symbol("summary_select_by_msgnum",
+ summary_select_by_msgnum);
+ syl_plugin_add_symbol("summary_select_by_msginfo",
+ summary_select_by_msginfo);
+
+ syl_plugin_add_symbol("messageview_create_with_new_window",
+ messageview_create_with_new_window);
+ syl_plugin_add_symbol("messageview_show", messageview_show);
+
+ syl_plugin_add_symbol("foldersel_folder_sel",
+ foldersel_folder_sel);
+ syl_plugin_add_symbol("foldersel_folder_sel_full",
+ foldersel_folder_sel_full);
+ syl_plugin_add_symbol("input_dialog", input_dialog);
+ syl_plugin_add_symbol("input_dialog_with_invisible",
+ input_dialog_with_invisible);
+
+ syl_plugin_add_symbol("manage_window_set_transient",
+ manage_window_set_transient);
+ syl_plugin_add_symbol("manage_window_signals_connect",
+ manage_window_signals_connect);
+ syl_plugin_add_symbol("manage_window_get_focus_window",
+ manage_window_get_focus_window);
+
+ syl_plugin_add_symbol("inc_mail", inc_mail);
+ syl_plugin_add_symbol("inc_lock", inc_lock);
+ syl_plugin_add_symbol("inc_unlock", inc_unlock);
+
+ syl_plugin_signal_connect("plugin-load", G_CALLBACK(load_cb), NULL);
+
+#ifdef G_OS_WIN32
+ {
+ gchar *path;
+ path = g_strconcat(get_startup_dir(), G_DIR_SEPARATOR_S,
+ "plugins", NULL);
+ syl_plugin_load_all(path);
+ g_free(path);
+ }
+#else
+ syl_plugin_load_all(PLUGINDIR);
+#endif
+}
+
static gchar *get_socket_name(void)
{
static gchar *filename = NULL;
diff --git a/src/mainwindow.c b/src/mainwindow.c
index e0a43dd8..7d9736c7 100644
--- a/src/mainwindow.c
+++ b/src/mainwindow.c
@@ -79,6 +79,7 @@
#include "prefs_template.h"
#include "prefs_search_folder.h"
#include "prefs_toolbar.h"
+#include "plugin_manager.h"
#include "action.h"
#include "account.h"
#include "account_dialog.h"
@@ -95,6 +96,7 @@
#include "codeconv.h"
#include "about.h"
#include "manual.h"
+#include "update_check.h"
#include "version.h"
#define AC_LABEL_WIDTH 240
@@ -495,6 +497,9 @@ static void prefs_filter_open_cb (MainWindow *mainwin,
static void prefs_template_open_cb (MainWindow *mainwin,
guint action,
GtkWidget *widget);
+static void plugin_manager_open_cb (MainWindow *mainwin,
+ guint action,
+ GtkWidget *widget);
#ifndef G_OS_WIN32
static void prefs_actions_open_cb (MainWindow *mainwin,
guint action,
@@ -522,6 +527,9 @@ static void faq_open_cb (MainWindow *mainwin,
static void help_cmdline_cb (MainWindow *mainwin,
guint action,
GtkWidget *widget);
+static void update_check_cb (MainWindow *mainwin,
+ guint action,
+ GtkWidget *widget);
static void scan_tree_func (Folder *folder,
FolderItem *item,
@@ -857,6 +865,8 @@ static GtkItemFactoryEntry mainwin_entries[] =
#ifndef G_OS_WIN32
{N_("/_Configuration/_Actions..."), NULL, prefs_actions_open_cb, 0, NULL},
#endif
+ {N_("/_Configuration/Plug-in _manager..."),
+ NULL, plugin_manager_open_cb, 0, NULL},
{N_("/_Configuration/---"), NULL, NULL, 0, "<Separator>"},
{N_("/_Configuration/_Preferences for current account..."),
NULL, prefs_account_open_cb, 0, NULL},
@@ -879,6 +889,8 @@ static GtkItemFactoryEntry mainwin_entries[] =
{N_("/_Help/_FAQ/_Italian"), NULL, faq_open_cb, MANUAL_LANG_IT, NULL},
{N_("/_Help/_Command line options"), NULL, help_cmdline_cb, 0, NULL},
{N_("/_Help/---"), NULL, NULL, 0, "<Separator>"},
+ {N_("/_Help/_Update check..."), NULL, update_check_cb, 0, NULL},
+ {N_("/_Help/---"), NULL, NULL, 0, "<Separator>"},
{N_("/_Help/_About"), NULL, about_show, 0, NULL}
};
@@ -3852,6 +3864,12 @@ static void prefs_template_open_cb(MainWindow *mainwin, guint action,
prefs_template_open();
}
+static void plugin_manager_open_cb(MainWindow *mainwin, guint action,
+ GtkWidget *widget)
+{
+ plugin_manager_open();
+}
+
#ifndef G_OS_WIN32
static void prefs_actions_open_cb(MainWindow *mainwin, guint action,
GtkWidget *widget)
@@ -4027,6 +4045,12 @@ static void help_cmdline_cb(MainWindow *mainwin, guint action,
help_command_line_show();
}
+static void update_check_cb(MainWindow *mainwin, guint action,
+ GtkWidget *widget)
+{
+ update_check(TRUE);
+}
+
static void scan_tree_func(Folder *folder, FolderItem *item, gpointer data)
{
MainWindow *mainwin = (MainWindow *)data;
diff --git a/src/manage_window.c b/src/manage_window.c
index fe9f2b86..b21a3b22 100644
--- a/src/manage_window.c
+++ b/src/manage_window.c
@@ -92,6 +92,11 @@ void manage_window_set_transient(GtkWindow *window)
}
}
+void manage_window_signals_connect(GtkWindow *window)
+{
+ MANAGE_WINDOW_SIGNALS_CONNECT(window);
+}
+
GtkWidget *manage_window_get_focus_window(void)
{
return focus_window;
diff --git a/src/manage_window.h b/src/manage_window.h
index 64d48617..61369d1e 100644
--- a/src/manage_window.h
+++ b/src/manage_window.h
@@ -52,6 +52,7 @@ void manage_window_destroy (GtkWidget *widget,
gpointer data);
void manage_window_set_transient (GtkWindow *window);
+void manage_window_signals_connect (GtkWindow *window);
GtkWidget *manage_window_get_focus_window (void);
diff --git a/src/plugin.c b/src/plugin.c
new file mode 100644
index 00000000..062200ff
--- /dev/null
+++ b/src/plugin.c
@@ -0,0 +1,644 @@
+/*
+ * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 1999-2009 Hiroyuki Yamamoto
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <glib.h>
+#include <gmodule.h>
+#include <gtk/gtk.h>
+
+#include "plugin.h"
+#include "utils.h"
+#include "folder.h"
+
+G_DEFINE_TYPE(SylPlugin, syl_plugin, G_TYPE_OBJECT);
+
+enum {
+ PLUGIN_LOAD,
+ PLUGIN_UNLOAD,
+ FOLDERVIEW_MENU_POPUP,
+ LAST_SIGNAL
+};
+
+#define syl_plugin_lookup_symbol(name) g_hash_table_lookup(sym_table, name)
+
+#define SAFE_CALL(func_ptr) { if (func_ptr) func_ptr(); }
+#define SAFE_CALL_RET(func_ptr) (func_ptr ? func_ptr() : NULL)
+#define SAFE_CALL_ARG1(func_ptr, arg1) { if (func_ptr) func_ptr(arg1); }
+#define SAFE_CALL_ARG1_RET(func_ptr, arg1) \
+ (func_ptr ? func_ptr(arg1) : NULL)
+#define SAFE_CALL_ARG2(func_ptr, arg1, arg2) \
+ { if (func_ptr) func_ptr(arg1, arg2); }
+#define SAFE_CALL_ARG2_RET(func_ptr, arg1, arg2) \
+ (func_ptr ? func_ptr(arg1, arg2) : NULL)
+#define SAFE_CALL_ARG2_RET_VAL(func_ptr, arg1, arg2, retval) \
+ (func_ptr ? func_ptr(arg1, arg2) : retval)
+#define SAFE_CALL_ARG3(func_ptr, arg1, arg2, arg3) \
+ { if (func_ptr) func_ptr(arg1, arg2, arg3); }
+#define SAFE_CALL_ARG3_RET(func_ptr, arg1, arg2, arg3) \
+ (func_ptr ? func_ptr(arg1, arg2, arg3) : NULL)
+#define SAFE_CALL_ARG4(func_ptr, arg1, arg2, arg3, arg4) \
+ { if (func_ptr) func_ptr(arg1, arg2, arg3); }
+#define SAFE_CALL_ARG4_RET(func_ptr, arg1, arg2, arg3, arg4) \
+ (func_ptr ? func_ptr(arg1, arg2, arg3, arg4) : NULL)
+
+static guint plugin_signals[LAST_SIGNAL] = { 0 };
+
+static GHashTable *sym_table = NULL;
+static GSList *module_list = NULL;
+static GObject *plugin_obj = NULL;
+
+static void syl_plugin_init(SylPlugin *self)
+{
+}
+
+static void syl_plugin_class_init(SylPluginClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
+
+ plugin_signals[PLUGIN_LOAD] =
+ g_signal_new("plugin-load",
+ G_TYPE_FROM_CLASS(gobject_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET(SylPluginClass, plugin_load),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__POINTER,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_POINTER);
+ plugin_signals[PLUGIN_UNLOAD] =
+ g_signal_new("plugin-unload",
+ G_TYPE_FROM_CLASS(gobject_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET(SylPluginClass, plugin_unload),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__POINTER,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_POINTER);
+ plugin_signals[FOLDERVIEW_MENU_POPUP] =
+ g_signal_new("folderview-menu-popup",
+ G_TYPE_FROM_CLASS(gobject_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET(SylPluginClass,
+ folderview_menu_popup),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__POINTER,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_POINTER);
+}
+
+void syl_plugin_signal_connect(const gchar *name, GCallback callback,
+ gpointer data)
+{
+ g_signal_connect(plugin_obj, name, callback, data);
+}
+
+void syl_plugin_signal_disconnect(gpointer func, gpointer data)
+{
+ g_signal_handlers_disconnect_by_func(plugin_obj, func, data);
+}
+
+void syl_plugin_signal_emit(const gchar *name, ...)
+{
+ guint signal_id;
+
+ if (g_signal_parse_name(name, G_TYPE_FROM_INSTANCE(plugin_obj), &signal_id, NULL, FALSE)) {
+ va_list var_args;
+ va_start(var_args, name);
+ g_signal_emit_valist(plugin_obj, signal_id, 0, var_args);
+ va_end(var_args);
+ } else
+ g_warning("%s: signal '%s' not found", G_STRLOC, name);
+}
+
+gint syl_plugin_init_lib(void)
+{
+ if (!g_module_supported()) {
+ g_warning("Plug-in is not supported.");
+ return -1;
+ }
+
+ if (!sym_table) {
+ sym_table = g_hash_table_new(g_str_hash, g_str_equal);
+ }
+
+ if (!plugin_obj) {
+ plugin_obj = g_object_new(SYL_TYPE_PLUGIN, NULL);
+ }
+
+ return 0;
+}
+
+gint syl_plugin_load(const gchar *name)
+{
+ GModule *module;
+ SylPluginLoadFunc load_func = NULL;
+ gchar *file;
+
+ g_return_val_if_fail(name != NULL, -1);
+
+ debug_print("syl_plugin_load: loading %s\n", name);
+
+ if (!g_path_is_absolute(name))
+ file = g_strconcat(PLUGINDIR, G_DIR_SEPARATOR_S, name, NULL);
+ else
+ file = g_strdup(name);
+
+ module = g_module_open(file, G_MODULE_BIND_LAZY);
+ if (!module) {
+ g_warning("Cannot open module: %s: %s", name, g_module_error());
+ g_free(file);
+ return -1;
+ }
+ if (g_slist_find(module_list, module)) {
+ g_warning("Module %s is already loaded", name);
+ g_free(file);
+ return -1;
+ }
+
+ if (g_module_symbol(module, "plugin_load", (gpointer *)&load_func)) {
+ if (!syl_plugin_check_version(module)) {
+#if 0
+ g_warning("Version check failed. Skipping: %s", name);
+ g_module_close(module);
+ g_free(file);
+ return -1;
+#endif
+ }
+
+ debug_print("calling plugin_load() in %s\n",
+ g_module_name(module));
+ load_func();
+ module_list = g_slist_prepend(module_list, module);
+ g_signal_emit(plugin_obj, plugin_signals[PLUGIN_LOAD], 0, module);
+ } else {
+ g_warning("Cannot get symbol: %s: %s", name, g_module_error());
+ g_module_close(module);
+ g_free(file);
+ return -1;
+ }
+
+ g_free(file);
+
+ return 0;
+}
+
+gint syl_plugin_load_all(const gchar *dir)
+{
+ GDir *d;
+ const gchar *dir_name;
+ gchar *path;
+ gint count = 0;
+
+ if ((d = g_dir_open(dir, 0, NULL)) == NULL) {
+ g_warning("failed to open directory: %s", dir);
+ return -1;
+ }
+
+ while ((dir_name = g_dir_read_name(d)) != NULL) {
+ if (!g_str_has_suffix(dir_name, "." G_MODULE_SUFFIX))
+ continue;
+ path = g_strconcat(dir, G_DIR_SEPARATOR_S, dir_name, NULL);
+ if (syl_plugin_load(path) == 0)
+ count++;
+ g_free(path);
+ }
+
+ g_dir_close(d);
+
+ return count;
+}
+
+void syl_plugin_unload_all(void)
+{
+ GSList *cur;
+
+ for (cur = module_list; cur != NULL; cur = cur->next) {
+ GModule *module = (GModule *)cur->data;
+ SylPluginUnloadFunc unload_func = NULL;
+
+ if (g_module_symbol(module, "plugin_unload",
+ (gpointer *)&unload_func)) {
+ g_signal_emit(plugin_obj, plugin_signals[PLUGIN_UNLOAD],
+ 0, module);
+ debug_print("calling plugin_unload() in %s\n",
+ g_module_name(module));
+ unload_func();
+ } else {
+ g_warning("Cannot get symbol: %s", g_module_error());
+ }
+ if (!g_module_close(module)) {
+ g_warning("Module unload failed: %s", g_module_error());
+ }
+ }
+
+ g_slist_free(module_list);
+ module_list = NULL;
+}
+
+GSList *syl_plugin_get_module_list(void)
+{
+ return module_list;
+}
+
+SylPluginInfo *syl_plugin_get_info(GModule *module)
+{
+ SylPluginInfo * (*plugin_info_func)(void);
+
+ g_return_val_if_fail(module != NULL, NULL);
+
+ debug_print("getting plugin information of %s\n",
+ g_module_name(module));
+
+ if (g_module_symbol(module, "plugin_info",
+ (gpointer *)&plugin_info_func)) {
+ debug_print("calling plugin_info() in %s\n",
+ g_module_name(module));
+ return plugin_info_func();
+ } else {
+ g_warning("Cannot get symbol: %s: %s", g_module_name(module),
+ g_module_error());
+ return NULL;
+ }
+}
+
+gboolean syl_plugin_check_version(GModule *module)
+{
+ gint (*version_func)(void);
+ gint ver;
+
+ g_return_val_if_fail(module != NULL, FALSE);
+
+ if (g_module_symbol(module, "plugin_interface_version",
+ (gpointer *)&version_func)) {
+ debug_print("calling plugin_interface_version() in %s\n",
+ g_module_name(module));
+ ver = version_func();
+ } else {
+ g_warning("Cannot get symbol: %s: %s", g_module_name(module),
+ g_module_error());
+ return FALSE;
+ }
+
+ if (ver == SYL_PLUGIN_INTERFACE_VERSION) {
+ debug_print("Version OK: plugin: %d, app: %d\n",
+ ver, SYL_PLUGIN_INTERFACE_VERSION);
+ return TRUE;
+ } else {
+ g_warning("Plugin interface version mismatch: plugin: %d, app: %d", ver, SYL_PLUGIN_INTERFACE_VERSION);
+ return FALSE;
+ }
+}
+
+gint syl_plugin_add_symbol(const gchar *name, gpointer sym)
+{
+ g_hash_table_insert(sym_table, (gpointer)name, sym);
+ return 0;
+}
+
+const gchar *syl_plugin_get_prog_version(void)
+{
+ gpointer sym;
+
+ sym = syl_plugin_lookup_symbol("prog_version");
+ return (gchar *)sym;
+}
+
+gpointer syl_plugin_main_window_get(void)
+{
+ gpointer (*func)(void);
+
+ func = syl_plugin_lookup_symbol("main_window_get");
+ return SAFE_CALL_RET(func);
+}
+
+void syl_plugin_main_window_popup(gpointer mainwin)
+{
+ void (*func)(gpointer);
+
+ func = syl_plugin_lookup_symbol("main_window_popup");
+ SAFE_CALL_ARG1(func, mainwin);
+}
+
+void syl_plugin_app_will_exit(gboolean force)
+{
+ void (*func)(gboolean);
+
+ func = syl_plugin_lookup_symbol("app_will_exit");
+ SAFE_CALL_ARG1(func, force);
+}
+
+static GtkItemFactory *get_item_factory(const gchar *path)
+{
+ GtkItemFactory *ifactory;
+
+ if (!path)
+ return NULL;
+
+ if (strncmp(path, "<Main>", 6) == 0)
+ ifactory = syl_plugin_lookup_symbol("main_window_menu_factory");
+ else if (strncmp(path, "<MailFolder>", 12) == 0)
+ ifactory = syl_plugin_lookup_symbol("folderview_mail_popup_factory");
+ else
+ ifactory = syl_plugin_lookup_symbol("main_window_menu_factory");
+
+ return ifactory;
+}
+
+gint syl_plugin_add_menuitem(const gchar *parent, const gchar *label,
+ SylPluginCallbackFunc func, gpointer data)
+{
+ GtkItemFactory *ifactory;
+ GtkWidget *menu;
+ GtkWidget *menuitem;
+
+ if (!parent)
+ return -1;
+
+ ifactory = get_item_factory(parent);
+ if (!ifactory)
+ return -1;
+
+ menu = gtk_item_factory_get_widget(ifactory, parent);
+ if (!menu)
+ return -1;
+
+ if (label)
+ menuitem = gtk_menu_item_new_with_label(label);
+ else {
+ menuitem = gtk_menu_item_new();
+ gtk_widget_set_sensitive(menuitem, FALSE);
+ }
+ gtk_widget_show(menuitem);
+ gtk_menu_append(GTK_MENU(menu), menuitem);
+ if (func)
+ g_signal_connect(G_OBJECT(menuitem), "activate",
+ G_CALLBACK(func), data);
+
+ return 0;
+}
+
+gint syl_plugin_add_factory_item(const gchar *parent, const gchar *label,
+ SylPluginCallbackFunc func, gpointer data)
+{
+ GtkItemFactory *ifactory;
+ GtkItemFactoryEntry entry = {NULL, NULL, NULL, 0, NULL};
+
+ if (!parent)
+ return -1;
+
+ ifactory = get_item_factory(parent);
+ if (!ifactory)
+ return -1;
+
+ if (label) {
+ entry.path = (gchar *)label;
+ if (g_str_has_suffix(label, "/---"))
+ entry.item_type = "<Separator>";
+ else
+ entry.item_type = NULL;
+ } else {
+ entry.path = "/---";
+ entry.item_type = "<Separator>";
+ }
+ entry.callback = func;
+ g_print("entry.path = %s\n", entry.path);
+
+ gtk_item_factory_create_item(ifactory, &entry, data, 2);
+
+ return 0;
+}
+
+void syl_plugin_menu_set_sensitive(const gchar *path, gboolean sensitive)
+{
+ GtkItemFactory *ifactory;
+ GtkWidget *widget;
+
+ g_return_if_fail(path != NULL);
+
+ ifactory = get_item_factory(path);
+ if (!ifactory)
+ return;
+
+ widget = gtk_item_factory_get_item(ifactory, path);
+ gtk_widget_set_sensitive(widget, sensitive);
+}
+
+void syl_plugin_menu_set_sensitive_all(GtkMenuShell *menu_shell,
+ gboolean sensitive)
+{
+ GList *cur;
+
+ for (cur = menu_shell->children; cur != NULL; cur = cur->next)
+ gtk_widget_set_sensitive(GTK_WIDGET(cur->data), sensitive);
+}
+
+void syl_plugin_menu_set_active(const gchar *path, gboolean is_active)
+{
+ GtkItemFactory *ifactory;
+ GtkWidget *widget;
+
+ g_return_if_fail(path != NULL);
+
+ ifactory = get_item_factory(path);
+ if (!ifactory)
+ return;
+
+ widget = gtk_item_factory_get_item(ifactory, path);
+ gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(widget), is_active);
+}
+
+gpointer syl_plugin_folderview_get(void)
+{
+ gpointer sym;
+
+ sym = syl_plugin_lookup_symbol("folderview");
+ return sym;
+}
+
+FolderItem *syl_plugin_folderview_get_selected_item(void)
+{
+ FolderItem * (*func)(gpointer);
+ gpointer folderview;
+
+ folderview = syl_plugin_folderview_get();
+ if (folderview) {
+ func = syl_plugin_lookup_symbol("folderview_get_selected_item");
+ return SAFE_CALL_ARG1_RET(func, folderview);
+ }
+
+ return NULL;
+}
+
+gpointer syl_plugin_summary_view_get(void)
+{
+ gpointer sym;
+
+ sym = syl_plugin_lookup_symbol("summaryview");
+ return sym;
+}
+
+void syl_plugin_sumary_select_by_msgnum(guint msgnum)
+{
+ void (*func)(gpointer, guint);
+ gpointer summary;
+
+ summary = syl_plugin_summary_view_get();
+ if (summary) {
+ func = syl_plugin_lookup_symbol("summary_select_by_msgnum");
+ SAFE_CALL_ARG2(func, summary, msgnum);
+ }
+}
+
+gboolean syl_plugin_summary_select_by_msginfo(MsgInfo *msginfo)
+{
+ gboolean (*func)(gpointer, MsgInfo *);
+ gpointer summary;
+
+ summary = syl_plugin_summary_view_get();
+ if (summary) {
+ func = syl_plugin_lookup_symbol("summary_select_by_msginfo");
+ return SAFE_CALL_ARG2_RET_VAL(func, summary, msginfo, FALSE);
+ }
+
+ return FALSE;
+}
+
+void syl_plugin_open_message(const gchar *folder_id, guint msgnum)
+{
+ FolderItem *item;
+ MsgInfo *msginfo;
+
+ item = folder_find_item_from_identifier(folder_id);
+ msginfo = folder_item_get_msginfo(item, msgnum);
+
+ if (msginfo) {
+ if (!syl_plugin_summary_select_by_msginfo(msginfo)) {
+ syl_plugin_open_message_by_new_window(msginfo);
+ }
+ procmsg_msginfo_free(msginfo);
+ }
+}
+
+gpointer syl_plugin_messageview_create_with_new_window(void)
+{
+ gpointer (*func)(void);
+
+ func = syl_plugin_lookup_symbol("messageview_create_with_new_window");
+ return SAFE_CALL_RET(func);
+}
+
+void syl_plugin_open_message_by_new_window(MsgInfo *msginfo)
+{
+ gpointer msgview;
+ gpointer (*func)(gpointer, MsgInfo *, gboolean);
+
+ msgview = syl_plugin_messageview_create_with_new_window();
+ if (msgview) {
+ func = syl_plugin_lookup_symbol("messageview_show");
+ SAFE_CALL_ARG3(func, msgview, msginfo, FALSE);
+ }
+}
+
+FolderItem *syl_plugin_folder_sel(Folder *cur_folder, gint sel_type,
+ const gchar *default_folder)
+{
+ FolderItem * (*func)(Folder *, gint, const gchar *);
+
+ func = syl_plugin_lookup_symbol("foldersel_folder_sel");
+ return SAFE_CALL_ARG3_RET(func, cur_folder, sel_type, default_folder);
+}
+
+FolderItem *syl_plugin_folder_sel_full(Folder *cur_folder, gint sel_type,
+ const gchar *default_folder,
+ const gchar *message)
+{
+ FolderItem * (*func)(Folder *, gint, const gchar *, const gchar *);
+
+ func = syl_plugin_lookup_symbol("foldersel_folder_sel_full");
+ return SAFE_CALL_ARG4_RET(func, cur_folder, sel_type, default_folder,
+ message);
+}
+
+gchar *syl_plugin_input_dialog(const gchar *title, const gchar *message,
+ const gchar *default_string)
+{
+ gchar * (*func)(const gchar *, const gchar *, const gchar *);
+
+ func = syl_plugin_lookup_symbol("input_dialog");
+ return SAFE_CALL_ARG3_RET(func, title, message, default_string);
+}
+
+gchar *syl_plugin_input_dialog_with_invisible(const gchar *title,
+ const gchar *message,
+ const gchar *default_string)
+{
+ gchar * (*func)(const gchar *, const gchar *, const gchar *);
+
+ func = syl_plugin_lookup_symbol("input_dialog_with_invisible");
+ return SAFE_CALL_ARG3_RET(func, title, message, default_string);
+}
+
+void syl_plugin_manage_window_set_transient(GtkWindow *window)
+{
+ void (*func)(GtkWindow *);
+
+ func = syl_plugin_lookup_symbol("manage_window_set_transient");
+ SAFE_CALL_ARG1(func, window);
+}
+
+void syl_plugin_manage_window_signals_connect(GtkWindow *window)
+{
+ void (*func)(GtkWindow *);
+
+ func = syl_plugin_lookup_symbol("manage_window_signals_connect");
+ SAFE_CALL_ARG1(func, window);
+}
+
+GtkWidget *syl_plugin_manage_window_get_focus_window(void)
+{
+ GtkWidget * (*func)(void);
+
+ func = syl_plugin_lookup_symbol("manage_window_get_focus_window");
+ return SAFE_CALL_RET(func);
+}
+
+void syl_plugin_inc_mail(void)
+{
+ void (*func)(gpointer);
+
+ func = syl_plugin_lookup_symbol("inc_mail");
+ SAFE_CALL_ARG1(func, syl_plugin_main_window_get());
+}
+
+void syl_plugin_inc_lock(void)
+{
+ void (*func)(void);
+
+ func = syl_plugin_lookup_symbol("inc_lock");
+ SAFE_CALL(func);
+}
+
+void syl_plugin_inc_unlock(void)
+{
+ void (*func)(void);
+
+ func = syl_plugin_lookup_symbol("inc_unlock");
+ SAFE_CALL(func);
+}
diff --git a/src/plugin.h b/src/plugin.h
new file mode 100644
index 00000000..6a120731
--- /dev/null
+++ b/src/plugin.h
@@ -0,0 +1,175 @@
+/*
+ * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 1999-2009 Hiroyuki Yamamoto
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __PLUGIN_H__
+#define __PLUGIN_H__
+
+#include <glib.h>
+#include <glib-object.h>
+#include <gmodule.h>
+#include <gtk/gtk.h>
+
+#include "procmsg.h"
+#include "folder.h"
+
+/* SylPlugin object */
+
+#define SYL_TYPE_PLUGIN (syl_plugin_get_type())
+#define SYL_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SYL_TYPE_PLUGIN, SylPlugin))
+#define SYL_IS_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SYL_TYPE_PLUGIN))
+#define SYL_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SYL_TYPE_PLUGIN, SylPluginClass))
+#define SYL_IS_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SYL_TYPE_PLUGIN))
+#define SYL_PLUGIN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), SYL_TYPE_PLUGIN, SylPluginClass))
+
+typedef struct _SylPlugin SylPlugin;
+typedef struct _SylPluginClass SylPluginClass;
+typedef struct _SylPluginInfo SylPluginInfo;
+
+typedef void (*SylPluginLoadFunc) (void);
+typedef void (*SylPluginUnloadFunc) (void);
+typedef void (*SylPluginCallbackFunc) (void);
+
+#define SYL_PLUGIN_INTERFACE_VERSION 0x0100
+
+struct _SylPlugin
+{
+ GObject parent_instance;
+};
+
+struct _SylPluginClass
+{
+ GObjectClass parent_class;
+
+ void (* plugin_load) (GObject *obj, GModule *module);
+ void (* plugin_unload) (GObject *obj, GModule *module);
+ void (* folderview_menu_popup) (GObject *obj, gpointer ifactory);
+};
+
+struct _SylPluginInfo
+{
+ gchar *name;
+ gchar *version;
+ gchar *author;
+ gchar *description;
+
+ gpointer pad1;
+ gpointer pad2;
+ gpointer pad3;
+ gpointer pad4;
+};
+
+GType syl_plugin_get_type (void);
+
+void syl_plugin_signal_connect (const gchar *name, GCallback callback,
+ gpointer data);
+void syl_plugin_signal_disconnect (gpointer func, gpointer data);
+void syl_plugin_signal_emit (const gchar *name, ...);
+
+/* Used by Sylpheed */
+
+gint syl_plugin_init_lib (void);
+
+gint syl_plugin_load (const gchar *file);
+gint syl_plugin_load_all (const gchar *dir);
+void syl_plugin_unload_all (void);
+
+GSList *syl_plugin_get_module_list (void);
+SylPluginInfo *syl_plugin_get_info (GModule *module);
+gboolean syl_plugin_check_version (GModule *module);
+
+gint syl_plugin_add_symbol (const gchar *name, gpointer sym);
+
+/* Interfaces which should be implemented by plug-ins
+ void plugin_load(void);
+ void plugin_unload(void);
+ SylPluginInfo *plugin_info(void);
+ gint plugin_interface_version(void);
+ */
+
+/* Plug-in API (used by plug-ins) */
+
+const gchar *syl_plugin_get_prog_version (void);
+
+gpointer syl_plugin_main_window_get (void);
+void syl_plugin_main_window_popup (gpointer mainwin);
+
+void syl_plugin_app_will_exit (gboolean force);
+
+/* Menu */
+gint syl_plugin_add_menuitem (const gchar *parent,
+ const gchar *label,
+ SylPluginCallbackFunc func,
+ gpointer data);
+gint syl_plugin_add_factory_item (const gchar *menu,
+ const gchar *label,
+ SylPluginCallbackFunc func,
+ gpointer data);
+
+void syl_plugin_menu_set_sensitive (const gchar *path,
+ gboolean sensitive);
+void syl_plugin_menu_set_sensitive_all (GtkMenuShell *menu_shell,
+ gboolean sensitive);
+void syl_plugin_menu_set_active (const gchar *path,
+ gboolean is_active);
+
+
+/* FolderView */
+gpointer syl_plugin_folderview_get (void);
+FolderItem *syl_plugin_folderview_get_selected_item
+ (void);
+
+/* SummaryView */
+gpointer syl_plugin_summary_view_get (void);
+void syl_plugin_sumary_select_by_msgnum (guint msgnum);
+gboolean syl_plugin_summary_select_by_msginfo (MsgInfo *msginfo);
+
+void syl_plugin_open_message (const gchar *folder_id,
+ guint msgnum);
+
+/* MessageView */
+gpointer syl_plugin_messageview_create_with_new_window
+ (void);
+void syl_plugin_open_message_by_new_window (MsgInfo *msginfo);
+
+/* Others */
+FolderItem *syl_plugin_folder_sel (Folder *cur_folder,
+ gint sel_type,
+ const gchar *default_folder);
+FolderItem *syl_plugin_folder_sel_full (Folder *cur_folder,
+ gint sel_type,
+ const gchar *default_folder,
+ const gchar *message);
+
+gchar *syl_plugin_input_dialog (const gchar *title,
+ const gchar *message,
+ const gchar *default_string);
+gchar *syl_plugin_input_dialog_with_invisible (const gchar *title,
+ const gchar *message,
+ const gchar *default_string);
+
+void syl_plugin_manage_window_set_transient (GtkWindow *window);
+void syl_plugin_manage_window_signals_connect (GtkWindow *window);
+GtkWidget *syl_plugin_manage_window_get_focus_window
+ (void);
+
+void syl_plugin_inc_mail (void);
+void syl_plugin_inc_lock (void);
+void syl_plugin_inc_unlock (void);
+
+#endif /* __PLUGIN_H__ */
diff --git a/src/plugin_manager.c b/src/plugin_manager.c
new file mode 100644
index 00000000..53195fe9
--- /dev/null
+++ b/src/plugin_manager.c
@@ -0,0 +1,227 @@
+/*
+ * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 1999-2009 Hiroyuki Yamamoto
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "defs.h"
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <gdk/gdkkeysyms.h>
+#include <gtk/gtk.h>
+
+#include "plugin.h"
+#include "plugin_manager.h"
+#include "manage_window.h"
+#include "gtkutils.h"
+
+static struct PluginManagerWindow {
+ GtkWidget *window;
+ GtkWidget *close_btn;
+
+ GtkWidget *treeview;
+ GtkListStore *store;
+ GtkTreeSelection *selection;
+} pm_window;
+
+enum {
+ COL_INFO,
+ N_COLS
+};
+
+static void plugin_manager_create (void);
+static void plugin_manager_set_list_row (GtkTreeIter *iter,
+ SylPluginInfo *info,
+ const gchar *filename);
+static gint plugin_manager_deleted (GtkWidget *widget,
+ GdkEventAny *event,
+ gpointer data);
+static gboolean key_pressed (GtkWidget *widget,
+ GdkEventKey *event,
+ gpointer data);
+
+void plugin_manager_open(void)
+{
+ GSList *list, *cur;
+ SylPluginInfo *info;
+ GModule *module;
+ const gchar *filename;
+
+ if (!pm_window.window)
+ plugin_manager_create();
+ else
+ gtk_window_present(GTK_WINDOW(pm_window.window));
+
+ list = syl_plugin_get_module_list();
+
+ gtk_list_store_clear(pm_window.store);
+
+ for (cur = list; cur != NULL; cur = cur->next) {
+ module = (GModule *)cur->data;
+
+ filename = g_module_name(module);
+ info = syl_plugin_get_info(module);
+ if (info) {
+ debug_print("------------------------------\n");
+ debug_print("filename : %s\n", filename);
+ debug_print("plugin name : %s\n", info->name);
+ debug_print("plugin version: %s\n", info->version);
+ debug_print("plugin author : %s\n", info->author);
+ debug_print("description : %s\n", info->description ? info->description : "");
+ debug_print("------------------------------\n");
+ plugin_manager_set_list_row(NULL, info, filename);
+ } else {
+ debug_print("info not found: %s\n", filename);
+ }
+ }
+
+ gtk_widget_show(pm_window.window);
+ manage_window_focus_in(pm_window.window, NULL, NULL);
+}
+
+static void plugin_manager_create(void)
+{
+ GtkWidget *window;
+ GtkWidget *vbox;
+ GtkWidget *close_btn;
+ GtkWidget *confirm_area;
+
+ GtkWidget *scrolledwin;
+ GtkWidget *treeview;
+ GtkListStore *store;
+ GtkTreeSelection *selection;
+ GtkTreeViewColumn *column;
+ GtkCellRenderer *renderer;
+
+ window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+ gtk_window_set_title(GTK_WINDOW(window), _("Plug-in manager"));
+ gtk_widget_set_size_request(window, 600, 400);
+ gtk_window_set_policy(GTK_WINDOW(window), FALSE, TRUE, TRUE);
+ gtk_container_set_border_width(GTK_CONTAINER(window), 8);
+
+ vbox = gtk_vbox_new(FALSE, 6);
+ gtk_widget_show(vbox);
+ gtk_container_add(GTK_CONTAINER(window), vbox);
+
+ gtkut_stock_button_set_create(&confirm_area,
+ &close_btn, GTK_STOCK_CLOSE,
+ NULL, NULL, NULL, NULL);
+ gtk_widget_show(confirm_area);
+ gtk_box_pack_end(GTK_BOX(vbox), confirm_area, FALSE, FALSE, 0);
+ gtk_widget_grab_default(close_btn);
+
+ g_signal_connect(G_OBJECT(window), "delete_event",
+ G_CALLBACK(plugin_manager_deleted), NULL);
+ g_signal_connect(G_OBJECT(window), "key_press_event",
+ G_CALLBACK(key_pressed), NULL);
+ g_signal_connect(G_OBJECT(close_btn), "clicked",
+ G_CALLBACK(plugin_manager_deleted), NULL);
+
+ scrolledwin = gtk_scrolled_window_new(NULL, NULL);
+ gtk_widget_show(scrolledwin);
+ gtk_widget_set_size_request(scrolledwin, -1, -1);
+ gtk_box_pack_start(GTK_BOX(vbox), scrolledwin, TRUE, TRUE, 0);
+ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwin),
+ GTK_POLICY_AUTOMATIC,
+ GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolledwin),
+ GTK_SHADOW_IN);
+
+ store = gtk_list_store_new(N_COLS, G_TYPE_STRING);
+
+ treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
+ g_object_unref(G_OBJECT(store));
+ gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview), TRUE);
+ gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(treeview), TRUE);
+ gtk_tree_view_set_search_column(GTK_TREE_VIEW(treeview), COL_INFO);
+#if GTK_CHECK_VERSION(2, 10, 0)
+ gtk_tree_view_set_grid_lines(GTK_TREE_VIEW(treeview),
+ GTK_TREE_VIEW_GRID_LINES_HORIZONTAL);
+#endif
+
+ selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview));
+ gtk_tree_selection_set_mode(selection, GTK_SELECTION_BROWSE);
+
+ renderer = gtk_cell_renderer_text_new();
+ column = gtk_tree_view_column_new_with_attributes
+ (_("Plug-in information"), renderer, "text", COL_INFO, NULL);
+ gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
+ gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
+
+ gtk_widget_show(treeview);
+ gtk_container_add(GTK_CONTAINER(scrolledwin), treeview);
+
+ gtk_widget_show_all(window);
+
+ pm_window.window = window;
+ pm_window.close_btn = close_btn;
+
+ pm_window.treeview = treeview;
+ pm_window.store = store;
+ pm_window.selection = selection;
+}
+
+static void plugin_manager_set_list_row(GtkTreeIter *iter, SylPluginInfo *info,
+ const gchar *filename)
+{
+ GtkListStore *store = pm_window.store;
+ GtkTreeIter iter_;
+ gchar *plugin_info;
+
+ g_return_if_fail(info != NULL);
+ g_return_if_fail(filename != NULL);
+
+ plugin_info = g_strconcat(info->name ? info->name : _("(Unknown)"),
+ " ", info->version ? info->version : "", "\n",
+ _("Author: "), info->author ? info->author : _("(Unknown)"), "\n",
+ _("File: "), filename ? filename : _("(Unknown)"),
+ info->description ? "\n" : "",
+ info->description ? _("Description: ") : "",
+ info->description ? info->description : "",
+ NULL);
+
+ if (iter)
+ iter_ = *iter;
+ else
+ gtk_list_store_append(store, &iter_);
+
+ gtk_list_store_set(store, &iter_, COL_INFO, plugin_info, -1);
+
+ g_free(plugin_info);
+}
+
+static gint plugin_manager_deleted(GtkWidget *widget, GdkEventAny *event,
+ gpointer data)
+{
+ gtk_widget_hide(pm_window.window);
+ return TRUE;
+}
+
+static gboolean key_pressed(GtkWidget *widget, GdkEventKey *event,
+ gpointer data)
+{
+ if (event && event->keyval == GDK_Escape) {
+ gtk_widget_hide(pm_window.window);
+ return TRUE;
+ }
+
+ return FALSE;
+}
diff --git a/src/plugin_manager.h b/src/plugin_manager.h
new file mode 100644
index 00000000..c139de2f
--- /dev/null
+++ b/src/plugin_manager.h
@@ -0,0 +1,29 @@
+/*
+ * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 1999-2009 Hiroyuki Yamamoto
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __PLUGIN_MANAGER_H__
+#define __PLUGIN_MANAGER_H__
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+void plugin_manager_open(void);
+
+#endif /* __PLUGIN_MANAGER_H__ */
diff --git a/src/prefs_common_dialog.c b/src/prefs_common_dialog.c
index eeedc28b..88da4d17 100644
--- a/src/prefs_common_dialog.c
+++ b/src/prefs_common_dialog.c
@@ -1,6 +1,6 @@
/*
* Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 1999-2008 Hiroyuki Yamamoto
+ * Copyright (C) 1999-2009 Hiroyuki Yamamoto
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -233,6 +233,12 @@ static struct Extcmd {
GtkWidget *button_extsend;
} extcmd;
+static struct UpdateCheck {
+ GtkWidget *checkbtn_autoupdate;
+ GtkWidget *checkbtn_useproxy;
+ GtkWidget *entry_proxyhost;
+} update_check;
+
static struct Advanced {
GtkWidget *checkbtn_strict_cache_check;
@@ -540,6 +546,14 @@ static PrefsUIData ui_data[] = {
{"ext_sendmail_cmd", &extcmd.entry_extsend,
prefs_set_data_from_entry, prefs_set_entry},
+ /* Update check */
+ {"auto_update_check", &update_check.checkbtn_autoupdate,
+ prefs_set_data_from_toggle, prefs_set_toggle},
+ {"use_http_proxy", &update_check.checkbtn_useproxy,
+ prefs_set_data_from_toggle, prefs_set_toggle},
+ {"http_proxy_host", &update_check.entry_proxyhost,
+ prefs_set_data_from_entry, prefs_set_entry},
+
/* Advanced */
{"strict_cache_check", &advanced.checkbtn_strict_cache_check,
prefs_set_data_from_toggle, prefs_set_toggle},
@@ -567,6 +581,7 @@ static void prefs_privacy_create (void);
static void prefs_details_create (void);
static GtkWidget *prefs_other_create (void);
static GtkWidget *prefs_extcmd_create (void);
+static GtkWidget *prefs_update_create (void);
static GtkWidget *prefs_advanced_create (void);
static void prefs_common_set_encoding_optmenu (GtkOptionMenu *optmenu,
@@ -2168,6 +2183,7 @@ static void prefs_details_create(void)
GtkWidget *other_wid;
GtkWidget *extcmd_wid;
+ GtkWidget *update_wid;
GtkWidget *advanced_wid;
vbox1 = gtk_vbox_new (FALSE, VSPACING);
@@ -2268,6 +2284,10 @@ static void prefs_details_create(void)
extcmd_wid = prefs_extcmd_create();
gtk_box_pack_start(GTK_BOX(vbox_tab), extcmd_wid, FALSE, FALSE, 0);
+ APPEND_SUB_NOTEBOOK(notebook, vbox_tab, _("Update"));
+ update_wid = prefs_update_create();
+ gtk_box_pack_start(GTK_BOX(vbox_tab), update_wid, FALSE, FALSE, 0);
+
APPEND_SUB_NOTEBOOK(notebook, vbox_tab, _("Advanced"));
advanced_wid = prefs_advanced_create();
gtk_box_pack_start(GTK_BOX(vbox_tab), advanced_wid, FALSE, FALSE, 0);
@@ -2581,6 +2601,53 @@ static GtkWidget *prefs_extcmd_create(void)
return vbox1;
}
+static GtkWidget *prefs_update_create(void)
+{
+ GtkWidget *vbox1;
+ GtkWidget *vbox2;
+ GtkWidget *checkbtn_autoupdate;
+ GtkWidget *checkbtn_useproxy;
+ GtkWidget *label;
+ GtkWidget *entry_proxyhost;
+
+ vbox1 = gtk_vbox_new (FALSE, VSPACING);
+ gtk_widget_show (vbox1);
+
+#ifndef G_OS_WIN32
+ label = gtk_label_new (_("Update check requires 'curl' command."));
+ gtk_widget_show (label);
+ gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
+ gtk_box_pack_start (GTK_BOX (vbox1), label, FALSE, FALSE, 0);
+#endif
+
+ vbox2 = gtk_vbox_new (FALSE, VSPACING_NARROW);
+ gtk_widget_show (vbox2);
+ gtk_box_pack_start (GTK_BOX (vbox1), vbox2, FALSE, FALSE, 0);
+
+ PACK_CHECK_BUTTON (vbox2, checkbtn_autoupdate,
+ _("Enable auto update check"));
+ PACK_CHECK_BUTTON (vbox2, checkbtn_useproxy,
+ _("Use HTTP proxy"));
+
+ label = gtk_label_new (_("HTTP proxy host (hostname:port):"));
+ gtk_widget_show (label);
+ gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
+ gtk_box_pack_start (GTK_BOX (vbox2), label, FALSE, FALSE, 0);
+
+ entry_proxyhost = gtk_entry_new ();
+ gtk_widget_show (entry_proxyhost);
+ gtk_box_pack_start (GTK_BOX (vbox2), entry_proxyhost, FALSE, FALSE, 0);
+
+ SET_TOGGLE_SENSITIVITY(checkbtn_useproxy, label);
+ SET_TOGGLE_SENSITIVITY(checkbtn_useproxy, entry_proxyhost);
+
+ update_check.checkbtn_autoupdate = checkbtn_autoupdate;
+ update_check.checkbtn_useproxy = checkbtn_useproxy;
+ update_check.entry_proxyhost = entry_proxyhost;
+
+ return vbox1;
+}
+
static GtkWidget *prefs_advanced_create(void)
{
GtkWidget *vbox1;
diff --git a/src/update_check.c b/src/update_check.c
new file mode 100644
index 00000000..5979ea5f
--- /dev/null
+++ b/src/update_check.c
@@ -0,0 +1,255 @@
+/*
+ * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 1999-2009 Hiroyuki Yamamoto
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "defs.h"
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <gdk/gdkkeysyms.h>
+#include <gtk/gtk.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "update_check.h"
+#include "manage_window.h"
+#include "gtkutils.h"
+#include "alertpanel.h"
+#include "prefs_common.h"
+#include "socket.h"
+#include "utils.h"
+#include "version.h"
+
+
+static gboolean compare_version(gint major, gint minor, gint micro,
+ const gchar *extra)
+{
+ debug_print("comparing %d.%d.%d.%s <> " VERSION "\n", major, minor, micro, extra ? extra : "");
+
+ if (major > MAJOR_VERSION)
+ return TRUE;
+ if (major < MAJOR_VERSION)
+ return FALSE;
+ if (minor > MINOR_VERSION)
+ return TRUE;
+ if (minor < MINOR_VERSION)
+ return FALSE;
+ if (micro > MICRO_VERSION)
+ return TRUE;
+ if (micro < MICRO_VERSION)
+ return FALSE;
+ if (extra) {
+ if (strcmp(extra, EXTRA_VERSION) > 0)
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void parse_version_string(const gchar *ver, gint *major, gint *minor,
+ gint *micro, gchar **extra)
+{
+ gchar **vers;
+
+ vers = g_strsplit(ver, ".", -1);
+ if (vers[0]) {
+ *major = atoi(vers[0]);
+ if (vers[1]) {
+ *minor = atoi(vers[1]);
+ if (vers[2]) {
+ *micro = atoi(vers[2]);
+ if (vers[3]) {
+ *extra = g_strdup(vers[3]);
+ }
+ }
+ }
+ }
+ g_strfreev(vers);
+}
+
+static void update_dialog(const gchar *new_ver, gboolean manual)
+{
+ gchar buf[1024];
+ AlertValue val;
+
+ if (new_ver)
+ g_snprintf(buf, sizeof(buf), "%s\n\n%s -> %s",
+ _("The newer version of Sylpheed found.\n"
+ "Upgrade now?"),
+ VERSION, new_ver);
+ else
+ g_snprintf(buf, sizeof(buf), "%s",
+ _("The newer version of Sylpheed found.\n"
+ "Upgrade now?"));
+
+ val = alertpanel_full(_("New version found"), buf,
+ ALERT_QUESTION,
+ G_ALERTDEFAULT,
+ manual ? FALSE : TRUE,
+ GTK_STOCK_YES, GTK_STOCK_NO, NULL);
+ if ((val & G_ALERT_VALUE_MASK) == G_ALERTDEFAULT) {
+ open_uri(HOMEPAGE_URI, prefs_common.uri_cmd);
+ }
+ if (val & G_ALERTDISABLE) {
+ prefs_common.auto_update_check = FALSE;
+ }
+}
+
+static gint child_stdout;
+
+static void update_check_cb(GPid pid, gint status, gpointer data)
+{
+ gchar **lines;
+ gchar *key, *val, *p;
+ gchar *new_ver = NULL;
+ gint i;
+#ifdef DEVEL_VERSION
+ gboolean cur_ver_is_release = FALSE;
+#else
+ gboolean cur_ver_is_release = TRUE;
+#endif
+ gboolean result = FALSE;
+ gboolean got_version = FALSE;
+ gboolean show_dialog_always = (gboolean)data;
+ gchar buf[BUFFSIZE];
+ ssize_t size;
+
+ debug_print("update_check_cb\n");
+
+ if (!child_stdout) {
+ g_spawn_close_pid(pid);
+ return;
+ }
+
+ size = read(child_stdout, buf, sizeof(buf) - 1);
+ if (size < 0) {
+ fd_close(child_stdout);
+ child_stdout = 0;
+ g_spawn_close_pid(pid);
+ return;
+ }
+ buf[size] = '\0';
+
+ fd_close(child_stdout);
+ child_stdout = 0;
+ g_spawn_close_pid(pid);
+
+ lines = g_strsplit(buf, "\n", -1);
+
+ for (i = 0; lines[i] != NULL; i++) {
+ gint major = 0, minor = 0, micro = 0;
+ gchar *extra = NULL;
+
+ debug_print("update_check: %s\n", lines[i]);
+ p = strchr(lines[i], '=');
+ if (!p) continue;
+ key = g_strndup(lines[i], p - lines[i]);
+ val = p + 1;
+
+ if (!strcmp(key, "RELEASE")) {
+ parse_version_string(val, &major, &minor, &micro,
+ &extra);
+ result = compare_version(major, minor, micro, extra);
+ } else if (!cur_ver_is_release && !strcmp(key, "DEVEL")) {
+ parse_version_string(val, &major, &minor, &micro,
+ &extra);
+ result = compare_version(major, minor, micro, extra);
+ }
+
+ if (major + minor + micro != 0)
+ got_version = TRUE;
+
+ if (result) {
+ new_ver = g_strdup_printf("%d.%d.%d%s", major, minor, micro, extra ? extra : "");
+ debug_print("update_check: new ver: %s\n", new_ver);
+ g_free(extra);
+ g_free(key);
+ break;
+ }
+ g_free(extra);
+ g_free(key);
+ }
+
+ g_strfreev(lines);
+
+ if (result)
+ update_dialog(new_ver, show_dialog_always);
+ else if (show_dialog_always) {
+ if (got_version)
+ alertpanel_message(_("Information"),
+ _("Sylpheed is already the latest version."),
+ ALERT_NOTICE);
+ else
+ alertpanel_error(_("Couldn't get the version information."));
+ }
+ g_free(new_ver);
+}
+
+void update_check(gboolean show_dialog_always)
+{
+ gchar *cmdline[6] = {"curl", "--silent"};
+ GPid pid;
+ GError *error = NULL;
+
+ if (child_stdout > 0) {
+ debug_print("update check is in progress\n");
+ return;
+ }
+
+ child_stdout = 0;
+
+ debug_print("update_check: getting latest version from http://sylpheed.sraoss.jp/version.txt\n");
+
+ cmdline[2] = "http://sylpheed.sraoss.jp/version.txt?";
+ if (prefs_common.use_http_proxy && prefs_common.http_proxy_host &&
+ prefs_common.http_proxy_host[0] != '\0') {
+ cmdline[3] = "--proxy";
+ cmdline[4] = prefs_common.http_proxy_host;
+ cmdline[5] = NULL;
+ } else
+ cmdline[3] = NULL;
+
+ if (g_spawn_async_with_pipes
+ (NULL, cmdline, NULL,
+ G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH,
+ NULL, NULL, &pid,
+ NULL, &child_stdout, NULL, &error) == FALSE) {
+ g_warning("Couldn't execute curl");
+ if (error) {
+ g_warning("g_spawn_async_with_pipes: %s",
+ error->message);
+ g_error_free(error);
+ }
+ return;
+ }
+ if (pid == 0) {
+ g_warning("Couldn't get PID of child process");
+ if (child_stdout) {
+ fd_close(child_stdout);
+ child_stdout = 0;
+ }
+ return;
+ }
+
+ g_child_watch_add(pid, update_check_cb, (gpointer)show_dialog_always);
+}
diff --git a/src/update_check.h b/src/update_check.h
new file mode 100644
index 00000000..532a407a
--- /dev/null
+++ b/src/update_check.h
@@ -0,0 +1,29 @@
+/*
+ * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 1999-2009 Hiroyuki Yamamoto
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __UPDATE_CHECK_H__
+#define __UPDATE_CHECK_H__
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+void update_check(gboolean show_dialog_always);
+
+#endif /* __PLUGIN_MANAGER_H__ */
diff --git a/src/version.h.in b/src/version.h.in
index d7fac0aa..8e7affa6 100644
--- a/src/version.h.in
+++ b/src/version.h.in
@@ -1,6 +1,6 @@
/*
* Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 1999-2006 Hiroyuki Yamamoto
+ * Copyright (C) 1999-2009 Hiroyuki Yamamoto
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -22,6 +22,10 @@
#define PACKAGE "@PACKAGE@"
#define VERSION "@VERSION@"
+#define MAJOR_VERSION @MAJOR_VERSION@
+#define MINOR_VERSION @MINOR_VERSION@
+#define MICRO_VERSION @MICRO_VERSION@
+#define EXTRA_VERSION "@EXTRA_VERSION@"
#define PROG_VERSION "Sylpheed " VERSION
#endif /* __VERSION_H__ */