sync with 0.8.11cvs27
authorPaul Mangan <paul@claws-mail.org>
Thu, 17 Apr 2003 08:18:15 +0000 (08:18 +0000)
committerPaul Mangan <paul@claws-mail.org>
Thu, 17 Apr 2003 08:18:15 +0000 (08:18 +0000)
16 files changed:
ChangeLog
ChangeLog.claws
ChangeLog.jp
configure.ac
src/Makefile.am
src/action.c [new file with mode: 0644]
src/action.h [new file with mode: 0644]
src/codeconv.c
src/codeconv.h
src/compose.c
src/inc.c
src/mainwindow.c
src/prefs_actions.c
src/prefs_actions.h
src/send_message.c
src/toolbar.c

index b5c145df41fce53c22d3f850dd9ac71d949d052d..0c7d1f6a7808edf391bd9a1753194a237dbc6ce3 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,38 @@
+2003-04-16
+
+       * src/prefs_actions.[ch]: separated action execution routine into
+         action.[ch].
+
+2003-04-16
+
+       * src/prefs_actions.c: minor code cleanup.
+
+2003-04-16
+
+       * src/codeconv.[ch]: conv_iconv_strdup(): fixed the handling of
+         EILSEQ.
+
+2003-04-16
+
+       * src/inc.c:
+         inc_recv_data_progressive()
+         inc_recv_data_finished()
+         inc_recv_message()
+         send_recv_message()
+         send_send_data_progressive()
+         send_send_data_finished(): added assertion.
+
+2003-04-16
+
+       * src/codeconv.[ch]: conv_iconv_strdup(): fixed potential memory
+         corruption bug.
+
+2003-04-16
+
+       * src/codeconv.[ch]: conv_iconv_strdup(): don't include nul character
+         in source buffer since it messed up some encoding conversion (like
+         UTF-7).
+
 2003-04-15
 
        * src/procmsg.c: procmsg_get_filter_keyword(): unfold headers and
 2003-04-15
 
        * src/procmsg.c: procmsg_get_filter_keyword(): unfold headers and
index c0853a2fce899165b701dbf249fa5f9a5f513798..7213d25c56b75eb6541623b8919feaf72c8f9f40 100644 (file)
@@ -1,3 +1,8 @@
+2003-04-15 [paul]      0.8.11claws95
+
+       * sync with 0.8.11cvs27
+               see ChangeLog 2003-04-16
+
 2003-04-15 [paul]      0.8.11claws94
 
        * src/prefs_common.[ch]
 2003-04-15 [paul]      0.8.11claws94
 
        * src/prefs_common.[ch]
index 9ba714e65fbc492ef28f440ab32f85fb935058f1..e0e5e23666909d78938c13316e5e33ffb315880c 100644 (file)
@@ -1,3 +1,37 @@
+2003-04-16
+
+       * src/prefs_actions.[ch]: ¥¢¥¯¥·¥ç¥ó¼Â¹Ô¥ë¡¼¥Á¥ó¤ò action.[ch] ¤Ë
+         Ê¬Î¥¡£
+
+2003-04-16
+
+       * src/prefs_actions.c: ¾¯¤·¥³¡¼¥É¤ÎÀ°Íý¡£
+
+2003-04-16
+
+       * src/codeconv.[ch]: conv_iconv_strdup(): EILSEQ ¤Î½èÍý¤ò½¤Àµ¡£
+
+2003-04-16
+
+       * src/inc.c:
+         inc_recv_data_progressive()
+         inc_recv_data_finished()
+         inc_recv_message()
+         send_recv_message()
+         send_send_data_progressive()
+         send_send_data_finished(): assertion ¤òÄɲá£
+
+2003-04-16
+
+       * src/codeconv.[ch]: conv_iconv_strdup(): ÀøºßŪ¤Ê¥á¥â¥êÇ˲õ¥Ð¥°¤ò
+         ½¤Àµ¡£
+
+2003-04-16
+
+       * src/codeconv.[ch]: conv_iconv_strdup(): °ìÉô¤Î¥¨¥ó¥³¡¼¥Ç¥£¥ó¥°ÊÑ´¹
+         (UTF-7 Åù)¤òº®Í𤵤»¤Æ¤¤¤¿¤¿¤á¡¢¥½¡¼¥¹¥Ð¥Ã¥Õ¥¡¤Ë¥Ì¥ëʸ»ú¤ò´Þ¤á¤Ê¤¤
+         ¤è¤¦¤Ë¤·¤¿¡£
+
 2003-04-15
 
        * src/procmsg.c: procmsg_get_filter_keyword(): ¥Ø¥Ã¥À¤Î²þ¹Ô¤ò½üµî¤·¡¢
 2003-04-15
 
        * src/procmsg.c: procmsg_get_filter_keyword(): ¥Ø¥Ã¥À¤Î²þ¹Ô¤ò½üµî¤·¡¢
index e132f01281f3b26a475f585cf82d99dadf5cc4f6..57cd1a79fa208db181473ec920f9c5458d208990 100644 (file)
@@ -11,7 +11,7 @@ MINOR_VERSION=8
 MICRO_VERSION=11
 INTERFACE_AGE=0
 BINARY_AGE=0
 MICRO_VERSION=11
 INTERFACE_AGE=0
 BINARY_AGE=0
-EXTRA_VERSION=claws94
+EXTRA_VERSION=claws95
 VERSION=$MAJOR_VERSION.$MINOR_VERSION.$MICRO_VERSION$EXTRA_VERSION
 
 dnl set $target
 VERSION=$MAJOR_VERSION.$MINOR_VERSION.$MICRO_VERSION$EXTRA_VERSION
 
 dnl set $target
index a693fcaeb2079b7a37656cce58db74d80b20cd3e..b4494ed6106e0f4e03580dbe95f2e0cf7e1268f1 100644 (file)
@@ -16,6 +16,7 @@ sylpheed_SOURCES = \
        folder.c folder.h \
        procmsg.c procmsg.h \
        procheader.c procheader.h \
        folder.c folder.h \
        procmsg.c procmsg.h \
        procheader.c procheader.h \
+       action.c action.h \
        compose.c compose.h \
        stock_pixmap.c stock_pixmap.h \
        prefs_gtk.c prefs_gtk.h \
        compose.c compose.h \
        stock_pixmap.c stock_pixmap.h \
        prefs_gtk.c prefs_gtk.h \
diff --git a/src/action.c b/src/action.c
new file mode 100644 (file)
index 0000000..04a1249
--- /dev/null
@@ -0,0 +1,1398 @@
+/*
+ * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 1999-2003 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 <gtk/gtk.h>
+#include <gdk/gdkkeysyms.h>
+#include <gdk/gdkx.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <unistd.h>
+
+#include "intl.h"
+#include "utils.h"
+#include "gtkutils.h"
+#include "manage_window.h"
+#include "mainwindow.h"
+#include "prefs_common.h"
+#include "alertpanel.h"
+#include "action.h"
+#include "compose.h"
+#include "procmsg.h"
+#include "gtkstext.h"
+#include "mimeview.h"
+#include "textview.h"
+
+typedef struct _Children               Children;
+typedef struct _ChildInfo              ChildInfo;
+typedef struct _UserStringDialog       UserStringDialog;
+
+struct _Children
+{
+       GtkWidget       *dialog;
+       GtkWidget       *text;
+       GtkWidget       *input_entry;
+       GtkWidget       *input_hbox;
+       GtkWidget       *abort_btn;
+       GtkWidget       *close_btn;
+       GtkWidget       *scrolledwin;
+
+       gchar           *action;
+       GSList          *list;
+       gint             nb;
+       gint             open_in;
+       gboolean         output;
+};
+
+struct _ChildInfo
+{
+       Children        *children;
+       gchar           *cmd;
+       guint            type;
+       pid_t            pid;
+       gint             chld_in;
+       gint             chld_out;
+       gint             chld_err;
+       gint             chld_status;
+       gint             tag_in;
+       gint             tag_out;
+       gint             tag_err;
+       gint             tag_status;
+       gint             new_out;
+       GString         *output;
+       GtkWidget       *text;
+       GdkFont         *msgfont;
+};
+
+struct _UserStringDialog
+{
+       GtkWidget       *dialog;
+       GtkWidget       *entry;
+       gchar           *user_str;
+};
+
+static void update_actions_menu                (GtkItemFactory *ifactory,
+                                        gchar          *branch_path,
+                                        gpointer        callback,
+                                        gpointer        data);
+static void compose_actions_execute_cb (Compose        *compose,
+                                        guint           action_nb,
+                                        GtkWidget      *widget);
+static void mainwin_actions_execute_cb         (MainWindow     *mainwin,
+                                        guint           action_nb,
+                                        GtkWidget      *widget);
+static void msgview_actions_execute_cb (MessageView    *msgview,
+                                        guint           action_nb,
+                                        GtkWidget      *widget);
+static void message_actions_execute    (MessageView    *msgview,
+                                        guint           action_nb,
+                                        GtkCTree       *ctree);
+
+static gboolean execute_actions                (gchar          *action, 
+                                        GtkCTree       *ctree, 
+                                        GtkWidget      *text,
+                                        GdkFont        *msgfont,
+                                        gint            body_pos,
+                                        MimeView       *mimeview);
+
+static gchar *parse_action_cmd         (gchar          *action,
+                                        MsgInfo        *msginfo,
+                                        GtkCTree       *ctree,
+                                        MimeView       *mimeview,
+                                        const gchar    *user_str,
+                                        const gchar    *user_hidden_str,
+                                        const gchar    *sel_str);
+static gboolean parse_append_filename  (GString        *cmd,
+                                        MsgInfo        *msginfo);
+
+static gboolean parse_append_msgpart   (GString        *cmd,
+                                        MsgInfo        *msginfo,
+                                        MimeView       *mimeview);
+
+static ChildInfo *fork_child           (gchar          *cmd,
+                                        gint            action_type,
+                                        GtkWidget      *text,
+                                        GdkFont        *msgfont,
+                                        gint            body_pos,
+                                        Children       *children);
+
+static gint wait_for_children          (gpointer        data);
+
+static void free_children              (Children       *children);
+
+static void childinfo_close_pipes      (ChildInfo      *child_info);
+
+static void create_io_dialog           (Children       *children);
+static void update_io_dialog           (Children       *children);
+
+static void hide_io_dialog_cb          (GtkWidget      *widget,
+                                        gpointer        data);
+static gint io_dialog_key_pressed_cb   (GtkWidget      *widget,
+                                        GdkEventKey    *event,
+                                        gpointer        data);
+
+static void catch_output               (gpointer                data,
+                                        gint                    source,
+                                        GdkInputCondition       cond);
+static void catch_input                        (gpointer                data, 
+                                        gint                    source,
+                                        GdkInputCondition       cond);
+static void catch_status               (gpointer                data,
+                                        gint                    source,
+                                        GdkInputCondition       cond);
+
+static gboolean user_string_dialog_delete_cb
+                                       (GtkWidget      *widget,
+                                        GdkEvent       *event,
+                                        gpointer        data);
+static void user_string_dialog_destroy_cb
+                                       (GtkWidget      *widget,
+                                        gpointer        data);
+static void user_string_dialog_activate_cb
+                                       (GtkWidget      *widget,
+                                        gpointer        data);
+
+static gchar *get_user_string          (const gchar    *action,
+                                        ActionType      type);
+
+
+ActionType get_action_type(const gchar *action_str)
+{
+       const gchar *p;
+       ActionType action_type = ACTION_NONE;
+
+       g_return_val_if_fail(action_str,  ACTION_ERROR);
+       g_return_val_if_fail(*action_str, ACTION_ERROR);
+
+       p = action_str;
+
+       if (p[0] == '|') {
+               action_type |= ACTION_PIPE_IN;
+               p++;
+       } else if (p[0] == '>') {
+               action_type |= ACTION_USER_IN;
+               p++;
+       } else if (p[0] == '*') {
+               action_type |= ACTION_USER_HIDDEN_IN;
+               p++;
+       }
+
+       if (p[0] == '\0')
+               return ACTION_ERROR;
+
+       while (*p && action_type != ACTION_ERROR) {
+               if (p[0] == '%') {
+                       switch (p[1]) {
+                       case 'f':
+                               action_type |= ACTION_SINGLE;
+                               break;
+                       case 'F':
+                               action_type |= ACTION_MULTIPLE;
+                               break;
+                       case 'p':
+                               action_type |= ACTION_SINGLE;
+                               break;
+                       case 's':
+                               action_type |= ACTION_SELECTION_STR;
+                               break;
+                       case 'u':
+                               action_type |= ACTION_USER_STR;
+                               break;
+                       case 'h':
+                               action_type |= ACTION_USER_HIDDEN_STR;
+                               break;
+                       default:
+                               action_type = ACTION_ERROR;
+                               break;
+                       }
+               } else if (p[0] == '|') {
+                       if (p[1] == '\0')
+                               action_type |= ACTION_PIPE_OUT;
+               } else if (p[0] == '>') {
+                       if (p[1] == '\0')
+                               action_type |= ACTION_INSERT;
+               } else if (p[0] == '&') {
+                       if (p[1] == '\0')
+                               action_type |= ACTION_ASYNC;
+               }
+               p++;
+       }
+
+       return action_type;
+}
+
+static gchar *parse_action_cmd(gchar *action, MsgInfo *msginfo,
+                              GtkCTree *ctree, MimeView *mimeview,
+                              const gchar *user_str,
+                              const gchar *user_hidden_str,
+                              const gchar *sel_str)
+{
+       GString *cmd;
+       gchar *p;
+       GList *cur;
+       MsgInfo *msg;
+       
+       p = action;
+       
+       if (p[0] == '|' || p[0] == '>' || p[0] == '*')
+               p++;
+
+       cmd = g_string_sized_new(strlen(action));
+
+       while (p[0] &&
+              !((p[0] == '|' || p[0] == '>' || p[0] == '&') && !p[1])) {
+               if (p[0] == '%' && p[1]) {
+                       switch (p[1]) {
+                       case 'f':
+                               if (!parse_append_filename(cmd, msginfo)) {
+                                       g_string_free(cmd, TRUE);
+                                       return NULL;
+                               }
+                               p++;
+                               break;
+                       case 'F':
+                               for (cur = GTK_CLIST(ctree)->selection;
+                                    cur != NULL; cur = cur->next) {
+                                       msg = gtk_ctree_node_get_row_data(ctree,
+                                             GTK_CTREE_NODE(cur->data));
+                                       if (!parse_append_filename(cmd, msg)) {
+                                               g_string_free(cmd, TRUE);
+                                               return NULL;
+                                       }
+                                       if (cur->next)
+                                               g_string_append_c(cmd, ' ');
+                               }
+                               p++;
+                               break;
+                       case 'p':
+                               if (!parse_append_msgpart(cmd, msginfo,
+                                                         mimeview)) {
+                                       g_string_free(cmd, TRUE);
+                                       return NULL;
+                               }
+                               p++;
+                               break;
+                       case 's':
+                               if (sel_str)
+                                       g_string_append(cmd, sel_str);
+                               p++;
+                               break;
+                       case 'u':
+                               if (user_str)
+                                       g_string_append(cmd, user_str);
+                               p++;
+                               break;
+                       case 'h':
+                               if (user_hidden_str)
+                                       g_string_append(cmd, user_hidden_str);
+                               p++;
+                               break;
+                       default:
+                               g_string_append_c(cmd, p[0]);
+                               g_string_append_c(cmd, p[1]);
+                               p++;
+                       }
+               } else {
+                       g_string_append_c(cmd, p[0]);
+               }
+               p++;
+       }
+       if (cmd->len == 0) {
+               g_string_free(cmd, TRUE);
+               return NULL;
+       }
+
+       p = cmd->str;
+       g_string_free(cmd, FALSE);
+       return p;
+}
+
+static gboolean parse_append_filename(GString *cmd, MsgInfo *msginfo)
+{
+       gchar *filename;
+
+       g_return_val_if_fail(msginfo, FALSE);
+
+       filename = procmsg_get_message_file(msginfo);
+
+       if (filename) {
+               g_string_append(cmd, filename);
+               g_free(filename);
+       } else {
+               alertpanel_error(_("Could not get message file %d"),
+                                msginfo->msgnum);
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+static gboolean parse_append_msgpart(GString *cmd, MsgInfo *msginfo,
+                                    MimeView *mimeview)
+{
+       gchar    *filename;
+       gchar    *partname;
+       MimeInfo *partinfo;
+       gint      ret;
+       FILE     *fp;
+
+       if (!mimeview) {
+#if USE_GPGME
+               if ((fp = procmsg_open_message_decrypted(msginfo, &partinfo))
+                   == NULL) {
+                       alertpanel_error(_("Could not get message file."));
+                       return FALSE;
+               }
+#else
+               if ((fp = procmsg_open_message(msginfo)) == NULL) {
+                       alertpanel_error(_("Could not get message file."));
+                       return FALSE;
+               }
+               partinfo = procmime_scan_mime_header(fp);
+#endif
+               fclose(fp);
+               if (!partinfo) {
+                       procmime_mimeinfo_free_all(partinfo);
+                       alertpanel_error(_("Could not get message part."));
+                       return FALSE;
+               }
+               filename = procmsg_get_message_file(msginfo);
+       } else {
+               if (!mimeview->opened) {
+                       alertpanel_error(_("No message part selected."));
+                       return FALSE;
+               }
+               if (!mimeview->file) {
+                       alertpanel_error(_("No message file selected."));
+                       return FALSE;
+               }
+               partinfo = gtk_ctree_node_get_row_data
+                               (GTK_CTREE(mimeview->ctree),
+                                mimeview->opened);
+               g_return_val_if_fail(partinfo != NULL, FALSE);
+               filename = mimeview->file;
+       }
+       partname = procmime_get_tmp_file_name(partinfo);
+
+       ret = procmime_get_part(partname, filename, partinfo); 
+
+       if (!mimeview) {
+               procmime_mimeinfo_free_all(partinfo);
+               g_free(filename);
+       }
+
+       if (ret < 0) {
+               alertpanel_error(_("Can't get part of multipart message"));
+               g_free(partname);
+               return FALSE;
+       }
+
+       g_string_append(cmd, partname);
+
+       g_free(partname);
+
+       return TRUE;
+}
+
+void actions_execute(gpointer data, 
+                    guint action_nb,
+                    GtkWidget *widget,
+                    gint source)
+{
+       if (source == TOOLBAR_MAIN) 
+               mainwin_actions_execute_cb((MainWindow*)data, action_nb, widget);
+       else if (source == TOOLBAR_COMPOSE)
+               compose_actions_execute_cb((Compose*)data, action_nb, widget);
+       else if (source == TOOLBAR_MSGVIEW)
+               msgview_actions_execute_cb((MessageView*)data, action_nb, widget);      
+}
+
+
+void update_mainwin_actions_menu(GtkItemFactory *ifactory,
+                                MainWindow *mainwin)
+{
+       update_actions_menu(ifactory, "/Tools/Actions",
+                           mainwin_actions_execute_cb,
+                           mainwin);
+}
+
+void update_compose_actions_menu(GtkItemFactory *ifactory,
+                                gchar *branch_path,
+                                Compose *compose)
+{
+       update_actions_menu(ifactory, branch_path,
+                           compose_actions_execute_cb,
+                           compose);
+}
+
+static void update_actions_menu(GtkItemFactory *ifactory,
+                               gchar *branch_path,
+                               gpointer callback,
+                               gpointer data)
+{
+       GtkWidget *menuitem;
+       gchar *menu_path;
+       GSList *cur;
+       gchar *action, *action_p;
+       GList *amenu;
+       GtkItemFactoryEntry ifentry = {NULL, NULL, NULL, 0, "<Branch>"};
+
+       ifentry.path = branch_path;
+       menuitem = gtk_item_factory_get_widget(ifactory, branch_path);
+       g_return_if_fail(menuitem != NULL);
+
+       amenu = GTK_MENU_SHELL(menuitem)->children;
+       while (amenu != NULL) {
+               GList *alist = amenu->next;
+               gtk_widget_destroy(GTK_WIDGET(amenu->data));
+               amenu = alist;
+       }
+
+       ifentry.accelerator     = NULL;
+       ifentry.callback_action = 0;
+       ifentry.callback        = callback;
+       ifentry.item_type       = NULL;
+
+       for (cur = prefs_common.actions_list; cur; cur = cur->next) {
+               action   = g_strdup((gchar *)cur->data);
+               action_p = strstr(action, ": ");
+               if (action_p && action_p[2] &&
+                   get_action_type(&action_p[2]) != ACTION_ERROR) {
+                       action_p[0] = 0x00;
+                       menu_path = g_strdup_printf("%s/%s", branch_path,
+                                                   action);
+                       ifentry.path = menu_path;
+                       gtk_item_factory_create_item(ifactory, &ifentry, data,
+                                                    1);
+                       g_free(menu_path);
+               }
+               g_free(action);
+               ifentry.callback_action++;
+       }
+}
+
+static void compose_actions_execute_cb(Compose *compose, guint action_nb,
+                                      GtkWidget *widget)
+{
+       gchar *buf, *action;
+       guint action_type;
+
+       g_return_if_fail(action_nb < g_slist_length(prefs_common.actions_list));
+
+       buf = (gchar *)g_slist_nth_data(prefs_common.actions_list, action_nb);
+       g_return_if_fail(buf != NULL);
+       action = strstr(buf, ": ");
+       g_return_if_fail(action != NULL);
+
+       /* Point to the beginning of the command-line */
+       action += 2;
+
+       action_type = get_action_type(action);
+       if (action_type & (ACTION_SINGLE | ACTION_MULTIPLE)) {
+               alertpanel_warning
+                       (_("The selected action cannot be used in the compose window\n"
+                          "because it contains %%f, %%F or %%p."));
+               return;
+       }
+
+       execute_actions(action, NULL, compose->text, NULL, 0, NULL);
+}
+
+static void mainwin_actions_execute_cb(MainWindow *mainwin, guint action_nb,
+                                      GtkWidget *widget)
+{
+       message_actions_execute(mainwin->messageview, action_nb,
+                               GTK_CTREE(mainwin->summaryview->ctree));
+}
+
+static void msgview_actions_execute_cb(MessageView *msgview, guint action_nb,
+                                      GtkWidget *widget)
+{
+       message_actions_execute(msgview, action_nb, NULL);
+}
+
+static void message_actions_execute(MessageView *msgview, guint action_nb,
+                                   GtkCTree *ctree)
+{
+       TextView *textview = NULL;
+       MimeView *mimeview = NULL;
+       gchar *buf;
+       gchar *action;
+       GtkWidget *text = NULL;
+       GdkFont *msgfont = NULL;
+       guint body_pos = 0;
+
+       g_return_if_fail(action_nb < g_slist_length(prefs_common.actions_list));
+
+       buf = (gchar *)g_slist_nth_data(prefs_common.actions_list, action_nb);
+
+       g_return_if_fail(buf);
+       g_return_if_fail(action = strstr(buf, ": "));
+
+       /* Point to the beginning of the command-line */
+       action += 2;
+
+       switch (msgview->type) {
+       case MVIEW_TEXT:
+               if (msgview->textview && msgview->textview->text)
+                       textview = msgview->textview;
+               break;
+       case MVIEW_MIME:
+               if (msgview->mimeview) {
+                       mimeview = msgview->mimeview;
+                       if (msgview->mimeview->type == MIMEVIEW_TEXT &&
+                           msgview->mimeview->textview &&
+                           msgview->mimeview->textview->text)
+                               textview = msgview->mimeview->textview;
+               }
+               break;
+       }
+
+       if (textview) {
+               text     = textview->text;
+               msgfont  = textview->msgfont;
+               body_pos = textview->body_pos;
+       }
+
+       execute_actions(action, ctree, text, msgfont, body_pos, mimeview);
+}
+
+static gboolean execute_actions(gchar *action, GtkCTree *ctree,
+                               GtkWidget *text, GdkFont *msgfont,
+                               gint body_pos, MimeView *mimeview)
+{
+       GList *cur, *selection = NULL;
+       GSList *children_list = NULL;
+       gint is_ok  = TRUE;
+       gint selection_len = 0;
+       Children *children;
+       ChildInfo *child_info;
+       gint action_type;
+       MsgInfo *msginfo;
+       gchar *cmd;
+       gchar *sel_str = NULL;
+       gchar *user_str = NULL;
+       gchar *user_hidden_str = NULL;
+
+       g_return_val_if_fail(action && *action, FALSE);
+
+       action_type = get_action_type(action);
+
+       if (action_type == ACTION_ERROR)
+               return FALSE;         /* ERR: syntax error */
+
+       if (action_type & (ACTION_SINGLE | ACTION_MULTIPLE) && 
+           !(ctree && GTK_CLIST(ctree)->selection))
+               return FALSE;         /* ERR: file command without selection */
+
+       if (ctree) {
+               selection = GTK_CLIST(ctree)->selection;
+               selection_len = g_list_length(selection);
+       }
+
+       if (action_type & (ACTION_PIPE_OUT | ACTION_PIPE_IN | ACTION_INSERT)) {
+               if (ctree && selection_len > 1)
+                       return FALSE; /* ERR: pipe + multiple selection */
+               if (!text)
+                       return FALSE; /* ERR: pipe and no displayed text */
+       }
+
+       if (action_type & ACTION_SELECTION_STR) {
+               if (!text)
+                       return FALSE; /* ERR: selection string but no text */
+               else {
+                       guint start = 0, end = 0;
+                       if (GTK_EDITABLE(text)->has_selection) {
+                               start = GTK_EDITABLE(text)->selection_start_pos;
+                               end   = GTK_EDITABLE(text)->selection_end_pos;
+                               if (start > end) {
+                                       guint tmp;
+                                       tmp = start;
+                                       start = end;
+                                       end = tmp;
+                               }
+                       }
+                       sel_str = gtk_editable_get_chars(GTK_EDITABLE(text),
+                                                        start, end);
+               }
+       }
+
+       if (action_type & (ACTION_USER_STR))
+               if (!(user_str = get_user_string(action, ACTION_USER_STR)))
+                       return FALSE;
+
+       if (action_type & (ACTION_USER_HIDDEN_STR))
+               if (!(user_hidden_str =
+                       get_user_string(action, ACTION_USER_HIDDEN_STR)))
+                       return FALSE;
+
+       children = g_new0(Children, 1);
+
+       if (action_type & ACTION_SINGLE) {
+               for (cur = selection; cur && is_ok == TRUE; cur = cur->next) {
+                       msginfo = gtk_ctree_node_get_row_data(ctree,
+                                       GTK_CTREE_NODE(cur->data));
+                       if (!msginfo) {
+                               is_ok  = FALSE; /* ERR: msginfo missing */
+                               break;
+                       }
+                       cmd = parse_action_cmd(action, msginfo, ctree,
+                                              mimeview, user_str,
+                                              user_hidden_str, sel_str);
+                       if (!cmd) {
+                               debug_print("Action command error\n");
+                               is_ok  = FALSE; /* ERR: incorrect command */
+                               break;
+                       }
+                       if ((child_info = fork_child(cmd, action_type, text,
+                                                    msgfont, body_pos,
+                                                    children))) {
+                               children_list = g_slist_append(children_list,
+                                                              child_info);
+                               children->open_in = (selection_len == 1) ?
+                                                   (action_type &
+                                                    (ACTION_USER_IN |
+                                                     ACTION_USER_HIDDEN_IN)) : 0;
+                       }
+                       g_free(cmd);
+               }
+       } else {
+               cmd = parse_action_cmd(action, NULL, ctree, mimeview, user_str,
+                                      user_hidden_str, sel_str);
+               if (cmd) {
+                       if ((child_info = fork_child(cmd, action_type, text,
+                                                    msgfont, body_pos,
+                                                    children))) {
+                               children_list = g_slist_append(children_list,
+                                                              child_info);
+                               children->open_in = action_type &
+                                                   (ACTION_USER_IN |
+                                                    ACTION_USER_HIDDEN_IN);
+                       }
+                       g_free(cmd);
+               } else
+                       is_ok  = FALSE;         /* ERR: incorrect command */
+       }
+
+       g_free(user_str);
+       g_free(user_hidden_str);
+
+       if (!children_list) {
+                /* If not waiting for children, return */
+               g_free(children);
+       } else {
+               GSList *cur;
+
+               children->action  = g_strdup(action);
+               children->dialog  = NULL;
+               children->list    = children_list;
+               children->nb      = g_slist_length(children_list);
+
+               for (cur = children_list; cur; cur = cur->next) {
+                       child_info = (ChildInfo *) cur->data;
+                       child_info->tag_status = 
+                               gdk_input_add(child_info->chld_status,
+                                             GDK_INPUT_READ,
+                                             catch_status, child_info);
+               }
+
+               create_io_dialog(children);
+       }
+
+       return is_ok;
+}
+
+static ChildInfo *fork_child(gchar *cmd, gint action_type, GtkWidget *text,
+                            GdkFont *msgfont, gint body_pos,
+                            Children *children)
+{
+       gint chld_in[2], chld_out[2], chld_err[2], chld_status[2];
+       gchar *cmdline[4];
+       guint start, end;
+       gint is_selection;
+       gchar *selection;
+       pid_t pid, gch_pid;
+       ChildInfo *child_info;
+       gint sync;
+
+       sync = !(action_type & ACTION_ASYNC);
+
+       chld_in[0] = chld_in[1] = chld_out[0] = chld_out[1] = chld_err[0]
+               = chld_err[1] = chld_status[0] = chld_status[1] = -1;
+
+       if (sync) {
+               if (pipe(chld_status) || pipe(chld_in) || pipe(chld_out) ||
+                   pipe(chld_err)) {
+                       alertpanel_error(_("Command could not be started. "
+                                          "Pipe creation failed.\n%s"),
+                                       g_strerror(errno));
+                       /* Closing fd = -1 fails silently */
+                       close(chld_in[0]);
+                       close(chld_in[1]);
+                       close(chld_out[0]);
+                       close(chld_out[1]);
+                       close(chld_err[0]);
+                       close(chld_err[1]);
+                       close(chld_status[0]);
+                       close(chld_status[1]);
+                       return NULL; /* Pipe error */
+               }
+       }
+
+       debug_print("Forking child and grandchild.\n");
+
+       pid = fork();
+       if (pid == 0) { /* Child */
+               if (setpgid(0, 0))
+                       perror("setpgid");
+
+               close(ConnectionNumber(gdk_display));
+
+               gch_pid = fork();
+
+               if (gch_pid == 0) {
+                       if (setpgid(0, getppid()))
+                               perror("setpgid");
+                       if (sync) {
+                               if (action_type &
+                                   (ACTION_PIPE_IN |
+                                    ACTION_USER_IN |
+                                    ACTION_USER_HIDDEN_IN)) {
+                                       close(fileno(stdin));
+                                       dup  (chld_in[0]);
+                               }
+                               close(chld_in[0]);
+                               close(chld_in[1]);
+
+                               close(fileno(stdout));
+                               dup  (chld_out[1]);
+                               close(chld_out[0]);
+                               close(chld_out[1]);
+
+                               close(fileno(stderr));
+                               dup  (chld_err[1]);
+                               close(chld_err[0]);
+                               close(chld_err[1]);
+                       }
+
+                       cmdline[0] = "sh";
+                       cmdline[1] = "-c";
+                       cmdline[2] = cmd;
+                       cmdline[3] = 0;
+                       execvp("/bin/sh", cmdline);
+
+                       perror("execvp");
+                       _exit(1);
+               } else if (gch_pid < (pid_t) 0) { /* Fork error */
+                       if (sync)
+                               write(chld_status[1], "1\n", 2);
+                       perror("fork");
+                       _exit(1);
+               } else { /* Child */
+                       if (sync) {
+                               close(chld_in[0]);
+                               close(chld_in[1]);
+                               close(chld_out[0]);
+                               close(chld_out[1]);
+                               close(chld_err[0]);
+                               close(chld_err[1]);
+                               close(chld_status[0]);
+                       }
+                       if (sync) {
+                               debug_print("Child: Waiting for grandchild\n");
+                               waitpid(gch_pid, NULL, 0);
+                               debug_print("Child: grandchild ended\n");
+                               write(chld_status[1], "0\n", 2);
+                               close(chld_status[1]);
+                       }
+                       _exit(0);
+               }
+       } else if (pid < 0) { /* Fork error */
+               alertpanel_error(_("Could not fork to execute the following "
+                                  "command:\n%s\n%s"),
+                                cmd, g_strerror(errno));
+               return NULL; 
+       }
+
+       /* Parent */
+
+       if (!sync) {
+               waitpid(pid, NULL, 0);
+               return NULL;
+       }
+
+       close(chld_in[0]);
+       if (!(action_type & (ACTION_PIPE_IN | ACTION_USER_IN | ACTION_USER_HIDDEN_IN)))
+               close(chld_in[1]);
+       close(chld_out[1]);
+       close(chld_err[1]);
+       close(chld_status[1]);
+
+       child_info = g_new0(ChildInfo, 1);
+
+       child_info->children    = children;
+
+       child_info->pid         = pid;
+       child_info->cmd         = g_strdup(cmd);
+       child_info->type        = action_type;
+       child_info->new_out     = FALSE;
+       child_info->output      = g_string_new(NULL);
+       child_info->chld_in     =
+               (action_type &
+                (ACTION_PIPE_IN | ACTION_USER_IN | ACTION_USER_HIDDEN_IN))
+                       ? chld_in [1] : -1;
+       child_info->chld_out    = chld_out[0];
+       child_info->chld_err    = chld_err[0];
+       child_info->chld_status = chld_status[0];
+       child_info->tag_in      = -1;
+       child_info->tag_out     = gdk_input_add(chld_out[0], GDK_INPUT_READ,
+                                               catch_output, child_info);
+       child_info->tag_err     = gdk_input_add(chld_err[0], GDK_INPUT_READ,
+                                               catch_output, child_info);
+
+       if (!(action_type & (ACTION_PIPE_IN | ACTION_PIPE_OUT | ACTION_INSERT)))
+               return child_info;
+
+       child_info->text        = text;
+       child_info->msgfont     = msgfont;
+
+       start = body_pos;
+       end   = gtk_stext_get_length(GTK_STEXT(text));
+
+       if (GTK_EDITABLE(text)->has_selection) {
+               start = GTK_EDITABLE(text)->selection_start_pos;
+               end   = GTK_EDITABLE(text)->selection_end_pos;
+               if (start > end) {
+                       guint tmp;
+                       tmp = start;
+                       start = end;
+                       end = tmp;
+               }
+               is_selection = TRUE;
+               if (start == end) {
+                       start = 0;
+                       end = gtk_stext_get_length(GTK_STEXT(text));
+                       is_selection = FALSE;
+               }
+       }
+
+       selection = gtk_editable_get_chars(GTK_EDITABLE(text), start, end);
+
+       if (action_type & ACTION_PIPE_IN) {
+               write(chld_in[1], selection, strlen(selection));
+               if (!(action_type & (ACTION_USER_IN | ACTION_USER_HIDDEN_IN)))
+                       close(chld_in[1]);
+               child_info->chld_in = -1; /* No more input */
+       }
+       g_free(selection);
+
+       gtk_stext_freeze(GTK_STEXT(text));
+       if (action_type & ACTION_PIPE_OUT) {
+               gtk_stext_set_point(GTK_STEXT(text), start);
+               gtk_stext_forward_delete(GTK_STEXT(text), end - start);
+       }
+
+       gtk_stext_thaw(GTK_STEXT(text));
+
+       return child_info;
+}
+
+static void kill_children_cb(GtkWidget *widget, gpointer data)
+{
+       GSList *cur;
+       Children *children = (Children *) data;
+       ChildInfo *child_info;
+
+       for (cur = children->list; cur; cur = cur->next) {
+               child_info = (ChildInfo *)(cur->data);
+               debug_print("Killing child group id %d\n", child_info->pid);
+               if (child_info->pid && kill(-child_info->pid, SIGTERM) < 0)
+                       perror("kill");
+       }
+}
+
+static gint wait_for_children(gpointer data)
+{
+       gboolean new_output;
+       Children *children = (Children *)data;
+       ChildInfo *child_info;
+       GSList *cur;
+       gint nb = children->nb;
+
+       children->nb = 0;
+
+       cur = children->list;
+       new_output = FALSE;
+       while (cur) {
+               child_info = (ChildInfo *)cur->data;
+               if (child_info->pid)
+                       children->nb++;
+               new_output |= child_info->new_out;
+               cur = cur->next;
+       }
+
+       children->output |= new_output;
+
+       if (new_output || (children->dialog && (nb != children->nb)))
+               update_io_dialog(children);
+
+       if (children->nb)
+               return FALSE;
+
+       if (!children->dialog) {
+               free_children(children);
+       } else if (!children->output) {
+               gtk_widget_destroy(children->dialog);
+       }
+
+       return FALSE;
+}
+
+static void send_input(GtkWidget *w, gpointer data)
+{
+       Children *children = (Children *) data;
+       ChildInfo *child_info = (ChildInfo *) children->list->data;
+
+       child_info->tag_in = gdk_input_add(child_info->chld_in,
+                                          GDK_INPUT_WRITE,
+                                          catch_input, children);
+       gtk_widget_set_sensitive(children->input_hbox, FALSE);
+}
+
+static gint delete_io_dialog_cb(GtkWidget *w, GdkEvent *e, gpointer data)
+{
+       hide_io_dialog_cb(w, data);
+       return TRUE;
+}
+
+static void hide_io_dialog_cb(GtkWidget *w, gpointer data)
+{
+
+       Children *children = (Children *)data;
+
+       if (!children->nb) {
+               gtk_signal_disconnect_by_data(GTK_OBJECT(children->dialog),
+                                             children);
+               gtk_widget_destroy(children->dialog);
+               free_children(children);
+       }
+}
+
+static gint io_dialog_key_pressed_cb(GtkWidget *widget, GdkEventKey *event,
+                                    gpointer data)
+{
+       if (event && event->keyval == GDK_Escape)
+               hide_io_dialog_cb(widget, data);
+       return TRUE;
+}
+
+static void childinfo_close_pipes(ChildInfo *child_info)
+{
+       if (child_info->tag_in > 0)
+               gdk_input_remove(child_info->tag_in);
+       gdk_input_remove(child_info->tag_out);
+       gdk_input_remove(child_info->tag_err);
+
+       if (child_info->chld_in >= 0)
+               close(child_info->chld_in);
+       close(child_info->chld_out);
+       close(child_info->chld_err);
+       close(child_info->chld_status);
+}
+
+static void free_children(Children *children)
+{
+       GSList *cur;
+       ChildInfo *child_info;
+
+       debug_print("Freeing children data %p\n", children);
+
+       g_free(children->action);
+       for (cur = children->list; cur;) {
+               child_info = (ChildInfo *)cur->data;
+               g_free(child_info->cmd);
+               g_string_free(child_info->output, TRUE);
+               children->list = g_slist_remove(children->list, child_info);
+               g_free(child_info);
+               cur = children->list;
+       }
+       g_free(children);
+}
+
+static void update_io_dialog(Children *children)
+{
+       GSList *cur;
+
+       debug_print("Updating actions input/output dialog.\n");
+
+       if (!children->nb) {
+               gtk_widget_set_sensitive(children->abort_btn, FALSE);
+               gtk_widget_set_sensitive(children->close_btn, TRUE);
+               if (children->input_hbox)
+                       gtk_widget_set_sensitive(children->input_hbox, FALSE);
+               gtk_widget_grab_focus(children->close_btn);
+               gtk_signal_connect(GTK_OBJECT(children->dialog),
+                                  "key_press_event",
+                                  GTK_SIGNAL_FUNC(io_dialog_key_pressed_cb),
+                                  children);
+       }
+
+       if (children->output) {
+               GtkWidget *text = children->text;
+               gchar *caption;
+               ChildInfo *child_info;
+
+               gtk_widget_show(children->scrolledwin);
+               gtk_text_freeze(GTK_TEXT(text));
+               gtk_text_set_point(GTK_TEXT(text), 0);
+               gtk_text_forward_delete(GTK_TEXT(text), 
+                                       gtk_text_get_length(GTK_TEXT(text)));
+               for (cur = children->list; cur; cur = cur->next) {
+                       child_info = (ChildInfo *)cur->data;
+                       if (child_info->pid)
+                               caption = g_strdup_printf
+                                       (_("--- Running: %s\n"),
+                                        child_info->cmd);
+                       else
+                               caption = g_strdup_printf
+                                       (_("--- Ended: %s\n"),
+                                        child_info->cmd);
+
+                       gtk_text_insert(GTK_TEXT(text), NULL, NULL, NULL,
+                                       caption, -1);
+                       gtk_text_insert(GTK_TEXT(text), NULL, NULL, NULL,
+                                       child_info->output->str, -1);
+                       g_free(caption);
+                       child_info->new_out = FALSE;
+               }
+               gtk_text_thaw(GTK_TEXT(text));
+       }
+}
+
+static void create_io_dialog(Children *children)
+{
+       GtkWidget *dialog;
+       GtkWidget *vbox;
+       GtkWidget *entry = NULL;
+       GtkWidget *input_hbox = NULL;
+       GtkWidget *send_button;
+       GtkWidget *label;
+       GtkWidget *text;
+       GtkWidget *scrolledwin;
+       GtkWidget *hbox;
+       GtkWidget *abort_button;
+       GtkWidget *close_button;
+
+       debug_print("Creating action IO dialog\n");
+
+       dialog = gtk_dialog_new();
+       gtk_container_set_border_width
+               (GTK_CONTAINER(GTK_DIALOG(dialog)->action_area), 5);
+       gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER);
+       gtk_window_set_title(GTK_WINDOW(dialog), _("Action's input/output"));
+       gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
+       manage_window_set_transient(GTK_WINDOW(dialog));
+       gtk_signal_connect(GTK_OBJECT(dialog), "delete_event",
+                       GTK_SIGNAL_FUNC(delete_io_dialog_cb), children);
+       gtk_signal_connect(GTK_OBJECT(dialog), "destroy",
+                       GTK_SIGNAL_FUNC(hide_io_dialog_cb),
+                       children);
+
+       vbox = gtk_vbox_new(FALSE, 8);
+       gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), vbox);
+       gtk_container_set_border_width(GTK_CONTAINER(vbox), 8);
+       gtk_widget_show(vbox);
+
+       label = gtk_label_new(children->action);
+       gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
+       gtk_widget_show(label);
+
+       scrolledwin = gtk_scrolled_window_new(NULL, NULL);
+       gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwin),
+                                      GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
+       gtk_box_pack_start(GTK_BOX(vbox), scrolledwin, TRUE, TRUE, 0);
+       gtk_widget_set_usize(scrolledwin, 480, 200);
+       gtk_widget_hide(scrolledwin);
+
+       text = gtk_text_new(gtk_scrolled_window_get_hadjustment
+                           (GTK_SCROLLED_WINDOW(scrolledwin)),
+                           gtk_scrolled_window_get_vadjustment
+                           (GTK_SCROLLED_WINDOW(scrolledwin)));
+       gtk_text_set_editable(GTK_TEXT(text), FALSE);
+       gtk_container_add(GTK_CONTAINER(scrolledwin), text);
+       gtk_widget_show(text);
+
+       if (children->open_in) {
+               input_hbox = gtk_hbox_new(FALSE, 8);
+               gtk_widget_show(input_hbox);
+
+               entry = gtk_entry_new();
+               gtk_widget_set_usize(entry, 320, -1);
+               gtk_signal_connect(GTK_OBJECT(entry), "activate",
+                                  GTK_SIGNAL_FUNC(send_input), children);
+               gtk_box_pack_start(GTK_BOX(input_hbox), entry, TRUE, TRUE, 0);
+               if (children->open_in & ACTION_USER_HIDDEN_IN)
+                       gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE);
+               gtk_widget_show(entry);
+
+               send_button = gtk_button_new_with_label(_(" Send "));
+               gtk_signal_connect(GTK_OBJECT(send_button), "clicked",
+                                  GTK_SIGNAL_FUNC(send_input), children);
+               gtk_box_pack_start(GTK_BOX(input_hbox), send_button, FALSE,
+                                  FALSE, 0);
+               gtk_widget_show(send_button);
+
+               gtk_box_pack_start(GTK_BOX(vbox), input_hbox, FALSE, FALSE, 0);
+               gtk_widget_grab_focus(entry);
+       }
+
+       gtkut_button_set_create(&hbox, &abort_button, _("Abort"),
+                               &close_button, _("Close"), NULL, NULL);
+       gtk_signal_connect(GTK_OBJECT(abort_button), "clicked",
+                       GTK_SIGNAL_FUNC(kill_children_cb), children);
+       gtk_signal_connect(GTK_OBJECT(close_button), "clicked",
+                       GTK_SIGNAL_FUNC(hide_io_dialog_cb), children);
+       gtk_widget_show(hbox);
+
+       if (children->nb)
+               gtk_widget_set_sensitive(close_button, FALSE);
+
+       gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area), hbox);
+
+       children->dialog      = dialog;
+       children->scrolledwin = scrolledwin;
+       children->text        = text;
+       children->input_hbox  = children->open_in ? input_hbox : NULL;
+       children->input_entry = children->open_in ? entry : NULL;
+       children->abort_btn   = abort_button;
+       children->close_btn   = close_button;
+
+       gtk_widget_show(dialog);
+}
+
+static void catch_status(gpointer data, gint source, GdkInputCondition cond)
+{
+       ChildInfo *child_info = (ChildInfo *)data;
+       gchar buf;
+       gint c;
+
+       gdk_input_remove(child_info->tag_status);
+
+       c = read(source, &buf, 1);
+       debug_print("Child returned %c\n", buf);
+
+       waitpid(-child_info->pid, NULL, 0);
+       childinfo_close_pipes(child_info);
+       child_info->pid = 0;
+
+       wait_for_children(child_info->children);
+}
+       
+static void catch_input(gpointer data, gint source, GdkInputCondition cond)
+{
+       Children *children = (Children *)data;
+       ChildInfo *child_info = (ChildInfo *)children->list->data;
+       gchar *input;
+       gint c, count, len;
+
+       debug_print("Sending input to grand child.\n");
+       if (!(cond && GDK_INPUT_WRITE))
+               return;
+
+       gdk_input_remove(child_info->tag_in);
+       child_info->tag_in = -1;
+
+       input = gtk_editable_get_chars(GTK_EDITABLE(children->input_entry),
+                                      0, -1);
+       len = strlen(input);
+       count = 0;
+
+       do {
+               c = write(child_info->chld_in, input + count, len - count);
+               if (c >= 0)
+                       count += c;
+       } while (c >= 0 && count < len);
+
+       if (c >= 0)
+               write(child_info->chld_in, "\n", 2);
+
+       g_free(input);
+
+       gtk_entry_set_text(GTK_ENTRY(children->input_entry), "");
+       gtk_widget_set_sensitive(children->input_hbox, TRUE);
+       close(child_info->chld_in);
+       child_info->chld_in = -1;
+       debug_print("Input to grand child sent.\n");
+}
+
+static void catch_output(gpointer data, gint source, GdkInputCondition cond)
+{
+       ChildInfo *child_info = (ChildInfo *)data;
+       gint c, i;
+       gchar buf[BUFFSIZE];
+
+       debug_print("Catching grand child's output.\n");
+       if (child_info->type & (ACTION_PIPE_OUT | ACTION_INSERT)
+           && source == child_info->chld_out) {
+               gboolean is_selection = FALSE;
+               GtkWidget *text = child_info->text;
+               if (GTK_EDITABLE(text)->has_selection)
+                       is_selection = TRUE;
+               gtk_stext_freeze(GTK_STEXT(text));
+               while (TRUE) {
+                       c = read(source, buf, sizeof(buf) - 1);
+                       if (c == 0)
+                               break;
+                       gtk_stext_insert(GTK_STEXT(text), child_info->msgfont,
+                                        NULL, NULL, buf, c);
+               }
+               if (is_selection) {
+                       /* Using the select_region draws things. Should not.
+                        * so we just change selection position and 
+                        * defere drawing when thawing. Hack?
+                        */
+                       GTK_EDITABLE(text)->selection_end_pos =
+                                       gtk_stext_get_point(GTK_STEXT(text));
+               }
+               gtk_stext_thaw(GTK_STEXT(child_info->text));
+       } else {
+               c = read(source, buf, sizeof(buf) - 1);
+               for (i = 0; i < c; i++)
+                       g_string_append_c(child_info->output, buf[i]);
+               if (c > 0)
+                       child_info->new_out = TRUE;
+       }
+       wait_for_children(child_info->children);
+}
+
+static gboolean user_string_dialog_delete_cb(GtkWidget *widget,
+                                            GdkEvent *event, gpointer data)
+{
+       return FALSE;
+}
+
+static void user_string_dialog_destroy_cb(GtkWidget *widget, gpointer data)
+{
+       gtk_main_quit();
+}
+
+static void user_string_dialog_activate_cb(GtkWidget *widget, gpointer data)
+{
+       UserStringDialog *user_dialog = (UserStringDialog *) data;
+
+       g_free(user_dialog->user_str);
+       user_dialog->user_str =
+               gtk_editable_get_chars(GTK_EDITABLE(user_dialog->entry), 0, -1);
+       gtk_widget_destroy(user_dialog->dialog);
+}
+
+static gchar *get_user_string(const gchar *action, ActionType type)
+{
+       GtkWidget *dialog;
+       GtkWidget *label;
+       GtkWidget *entry;
+       GtkWidget *ok_button;
+       GtkWidget *cancel_button;
+       gchar *label_text;
+       UserStringDialog user_dialog;
+
+       dialog = gtk_dialog_new();
+       gtk_window_set_policy(GTK_WINDOW(dialog), FALSE, FALSE, FALSE);
+       gtk_container_set_border_width
+               (GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), 8);
+       gtk_container_set_border_width
+               (GTK_CONTAINER(GTK_DIALOG(dialog)->action_area), 5);
+       gtk_window_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER);
+
+       switch (type) {
+       case ACTION_USER_HIDDEN_STR:
+               gtk_window_set_title(GTK_WINDOW(dialog),
+                                    _("Action's hidden user argument"));
+               label_text = g_strdup_printf(_("Enter the '%%h' "
+                                            "argument for the following "
+                                            "action:\n%s"), action);
+               break;
+       case ACTION_USER_STR:
+               gtk_window_set_title(GTK_WINDOW(dialog),
+                                    _("Action's user argument"));
+               label_text = g_strdup_printf(_("Enter the '%%u' "
+                                            "argument for the following "
+                                            "action:\n%s"), action);
+               break;
+       default:
+               label_text = NULL;
+               debug_print("Unsupported action type %d", type);
+       }
+
+       label = gtk_label_new(label_text);
+       g_free(label_text);
+       gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), label,
+                          TRUE, TRUE, 0);
+
+       entry = gtk_entry_new();
+       gtk_entry_set_visibility(GTK_ENTRY(entry),
+                                type != ACTION_USER_HIDDEN_STR);
+       gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), entry,
+                          TRUE, TRUE, 0);
+
+       ok_button = gtk_button_new_with_label(_("OK"));
+       gtk_box_pack_end(GTK_BOX(GTK_DIALOG(dialog)->action_area),
+                        ok_button, TRUE, TRUE, 0);
+
+       cancel_button = gtk_button_new_with_label(_("Cancel"));
+       gtk_box_pack_end(GTK_BOX(GTK_DIALOG(dialog)->action_area),
+                        cancel_button, TRUE, TRUE, 0);
+
+       user_dialog.dialog   = dialog;
+       user_dialog.user_str = NULL;
+       user_dialog.entry    = entry;
+
+       gtk_signal_connect(GTK_OBJECT(dialog), "delete_event",
+                          GTK_SIGNAL_FUNC(user_string_dialog_delete_cb),
+                          &user_dialog);
+       gtk_signal_connect(GTK_OBJECT(dialog), "destroy",
+                          GTK_SIGNAL_FUNC(user_string_dialog_destroy_cb),
+                          &user_dialog);
+       gtk_signal_connect(GTK_OBJECT(entry), "activate",
+                          GTK_SIGNAL_FUNC(user_string_dialog_activate_cb),
+                          &user_dialog);
+       gtk_signal_connect(GTK_OBJECT(ok_button), "clicked",
+                          GTK_SIGNAL_FUNC(user_string_dialog_activate_cb),
+                          &user_dialog);
+       gtk_signal_connect_object(GTK_OBJECT(cancel_button), "clicked",
+                                 GTK_SIGNAL_FUNC(gtk_widget_destroy),
+                                 GTK_OBJECT(dialog));
+
+       gtk_widget_grab_focus(entry);
+       gtk_widget_show_all(dialog);
+       gtk_main();
+
+       return user_dialog.user_str;
+}
diff --git a/src/action.h b/src/action.h
new file mode 100644 (file)
index 0000000..56f132d
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 1999-2003 Hiroyuki Yamamoto & The Sylpheed Claws Team
+ *
+ * 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 __ACTION_H__
+#define __ACTION_H__
+
+#include <glib.h>
+#include <gtk/gtkitemfactory.h>
+
+#include "mainwindow.h"
+#include "compose.h"
+
+typedef enum
+{
+       ACTION_NONE             = 1 << 0,
+       ACTION_PIPE_IN          = 1 << 1,
+       ACTION_PIPE_OUT         = 1 << 2,
+       ACTION_SINGLE           = 1 << 3,
+       ACTION_MULTIPLE         = 1 << 4,
+       ACTION_ASYNC            = 1 << 5,
+       ACTION_USER_IN          = 1 << 6,
+       ACTION_USER_HIDDEN_IN   = 1 << 7,
+       ACTION_INSERT           = 1 << 8,
+       ACTION_USER_STR         = 1 << 9,
+       ACTION_USER_HIDDEN_STR  = 1 << 10,
+       ACTION_SELECTION_STR    = 1 << 11,
+       ACTION_ERROR            = 1 << 30
+} ActionType;
+
+void update_mainwin_actions_menu       (GtkItemFactory *ifactory, 
+                                        MainWindow     *mainwin);
+void update_compose_actions_menu       (GtkItemFactory *ifactory, 
+                                        gchar          *branch_path,
+                                        Compose        *compose);
+
+void actions_execute                    (gpointer       data, 
+                                        guint          action_nb,
+                                        GtkWidget      *widget,
+                                        gint           source);
+
+ActionType get_action_type             (const gchar    *action_str);
+
+#endif /* __ACTION_H__ */
index fb0baab9f9e8ad10e692da997a44a88ebef4d38a..19b8428116218b987f0a00f2061f84514f802530 100644 (file)
@@ -802,6 +802,7 @@ gchar *conv_iconv_strdup(const gchar *inbuf,
        gint out_size;
        gint out_left;
        gint n_conv;
        gint out_size;
        gint out_left;
        gint n_conv;
+       gint len;
 
        if (!src_code)
                src_code = conv_get_outgoing_charset_str();
 
        if (!src_code)
                src_code = conv_get_outgoing_charset_str();
@@ -821,40 +822,58 @@ gchar *conv_iconv_strdup(const gchar *inbuf,
                return NULL;
 
        inbuf_p = inbuf;
                return NULL;
 
        inbuf_p = inbuf;
-       in_size = strlen(inbuf) + 1;
+       in_size = strlen(inbuf);
        in_left = in_size;
        in_left = in_size;
-       out_size = in_size * 2;
+       out_size = (in_size + 1) * 2;
        outbuf = g_malloc(out_size);
        outbuf_p = outbuf;
        out_left = out_size;
 
        outbuf = g_malloc(out_size);
        outbuf_p = outbuf;
        out_left = out_size;
 
+#define EXPAND_BUF()                           \
+{                                              \
+       len = outbuf_p - outbuf;                \
+       out_size *= 2;                          \
+       outbuf = g_realloc(outbuf, out_size);   \
+       outbuf_p = outbuf + len;                \
+       out_left = out_size - len;              \
+}
+
        while ((n_conv = iconv(cd, (ICONV_CONST gchar **)&inbuf_p, &in_left,
                               &outbuf_p, &out_left)) < 0) {
                if (EILSEQ == errno) {
                        inbuf_p++;
                        in_left--;
        while ((n_conv = iconv(cd, (ICONV_CONST gchar **)&inbuf_p, &in_left,
                               &outbuf_p, &out_left)) < 0) {
                if (EILSEQ == errno) {
                        inbuf_p++;
                        in_left--;
+                       if (out_left == 0) {
+                               EXPAND_BUF();
+                       }
                        *outbuf_p++ = SUBST_CHAR;
                        out_left--;
                } else if (EINVAL == errno) {
                        *outbuf_p++ = SUBST_CHAR;
                        out_left--;
                } else if (EINVAL == errno) {
-                       *outbuf_p = '\0';
                        break;
                } else if (E2BIG == errno) {
                        break;
                } else if (E2BIG == errno) {
-                       out_size *= 2;
-                       outbuf = g_realloc(outbuf, out_size);
-                       inbuf_p = inbuf;
-                       in_left = in_size;
-                       outbuf_p = outbuf;
-                       out_left = out_size;
+                       EXPAND_BUF();
                } else {
                        g_warning("conv_iconv_strdup(): %s\n",
                                  g_strerror(errno));
                } else {
                        g_warning("conv_iconv_strdup(): %s\n",
                                  g_strerror(errno));
-                       *outbuf_p = '\0';
                        break;
                }
        }
 
                        break;
                }
        }
 
-       iconv(cd, NULL, NULL, &outbuf_p, &out_left);
-       outbuf = g_realloc(outbuf, strlen(outbuf) + 1);
+       while ((n_conv = iconv(cd, NULL, NULL, &outbuf_p, &out_left)) < 0) {
+               if (E2BIG == errno) {
+                       EXPAND_BUF();
+               } else {
+                       g_warning("conv_iconv_strdup(): %s\n",
+                                 g_strerror(errno));
+                       break;
+               }
+       }
+
+#undef EXPAND_BUF
+
+       len = outbuf_p - outbuf;
+       outbuf = g_realloc(outbuf, len + 1);
+       outbuf[len] = '\0';
 
        iconv_close(cd);
 
 
        iconv_close(cd);
 
@@ -869,6 +888,7 @@ static const struct {
        {C_US_ASCII,            CS_US_ASCII},
        {C_US_ASCII,            CS_ANSI_X3_4_1968},
        {C_UTF_8,               CS_UTF_8},
        {C_US_ASCII,            CS_US_ASCII},
        {C_US_ASCII,            CS_ANSI_X3_4_1968},
        {C_UTF_8,               CS_UTF_8},
+       {C_UTF_7,               CS_UTF_7},
        {C_ISO_8859_1,          CS_ISO_8859_1},
        {C_ISO_8859_2,          CS_ISO_8859_2},
        {C_ISO_8859_3,          CS_ISO_8859_3},
        {C_ISO_8859_1,          CS_ISO_8859_1},
        {C_ISO_8859_2,          CS_ISO_8859_2},
        {C_ISO_8859_3,          CS_ISO_8859_3},
@@ -1326,6 +1346,7 @@ gboolean conv_is_multibyte_encoding(CharSet encoding)
        case C_GB2312:
        case C_BIG5:
        case C_UTF_8:
        case C_GB2312:
        case C_BIG5:
        case C_UTF_8:
+       case C_UTF_7:
                return TRUE;
        default:
                return FALSE;
                return TRUE;
        default:
                return FALSE;
index 7633f9fa93f8dfe86599900d7124f46e53d7b8d3..7dfb14f4e9614502ab85c1cf5dc17d3b3277872d 100644 (file)
@@ -33,6 +33,7 @@ typedef enum
        C_AUTO,
        C_US_ASCII,
        C_UTF_8,
        C_AUTO,
        C_US_ASCII,
        C_UTF_8,
+       C_UTF_7,
        C_ISO_8859_1,
        C_ISO_8859_2,
        C_ISO_8859_3,
        C_ISO_8859_1,
        C_ISO_8859_2,
        C_ISO_8859_3,
@@ -101,6 +102,7 @@ struct _CodeConverter
 #define CS_US_ASCII            "US-ASCII"
 #define CS_ANSI_X3_4_1968      "ANSI_X3.4-1968"
 #define CS_UTF_8               "UTF-8"
 #define CS_US_ASCII            "US-ASCII"
 #define CS_ANSI_X3_4_1968      "ANSI_X3.4-1968"
 #define CS_UTF_8               "UTF-8"
+#define CS_UTF_7               "UTF-7"
 #define CS_ISO_8859_1          "ISO-8859-1"
 #define CS_ISO_8859_2          "ISO-8859-2"
 #define CS_ISO_8859_3          "ISO-8859-3"
 #define CS_ISO_8859_1          "ISO-8859-1"
 #define CS_ISO_8859_2          "ISO-8859-2"
 #define CS_ISO_8859_3          "ISO-8859-3"
index fabcffa09cf8a48ecd287a71fec0cbd81a78d2e9..79931bed88dad9b7b9f38426a581116e1eceb7e5 100644 (file)
@@ -84,7 +84,7 @@
 #include "customheader.h"
 #include "prefs_common.h"
 #include "prefs_account.h"
 #include "customheader.h"
 #include "prefs_common.h"
 #include "prefs_account.h"
-#include "prefs_actions.h"
+#include "action.h"
 #include "account.h"
 #include "filesel.h"
 #include "procheader.h"
 #include "account.h"
 #include "filesel.h"
 #include "procheader.h"
index eff804fb11262108d581135b9cfaea1ec9bd9b47..725c110146d745a82d43cb55c95839700a24d5f1 100644 (file)
--- a/src/inc.c
+++ b/src/inc.c
@@ -764,11 +764,16 @@ static gint inc_recv_data_progressive(Session *session, guint cur_len,
        gchar buf[MSGBUFSIZE];
        IncSession *inc_session = (IncSession *)data;
        Pop3Session *pop3_session = POP3_SESSION(session);
        gchar buf[MSGBUFSIZE];
        IncSession *inc_session = (IncSession *)data;
        Pop3Session *pop3_session = POP3_SESSION(session);
-       IncProgressDialog *inc_dialog = (IncProgressDialog *)inc_session->data;
-       ProgressDialog *dialog = inc_dialog->dialog;
+       IncProgressDialog *inc_dialog;
+       ProgressDialog *dialog;
        gint cur_total;
        gchar *total_size;
 
        gint cur_total;
        gchar *total_size;
 
+       g_return_val_if_fail(inc_session != NULL, -1);
+
+       inc_dialog = (IncProgressDialog *)inc_session->data;
+       dialog = inc_dialog->dialog;
+
        cur_total = pop3_session->cur_total_bytes + cur_len;
        if (cur_total > pop3_session->total_bytes)
                cur_total = pop3_session->total_bytes;
        cur_total = pop3_session->cur_total_bytes + cur_len;
        if (cur_total > pop3_session->total_bytes)
                cur_total = pop3_session->total_bytes;
@@ -793,7 +798,11 @@ static gint inc_recv_data_progressive(Session *session, guint cur_len,
 
 static gint inc_recv_data_finished(Session *session, guint len, gpointer data)
 {
 
 static gint inc_recv_data_finished(Session *session, guint len, gpointer data)
 {
-       inc_recv_data_progressive(session, 0, len, data);
+       IncSession *inc_session = (IncSession *)data;
+
+       g_return_val_if_fail(inc_session != NULL, -1);
+
+       inc_recv_data_progressive(session, 0, len, inc_session);
        return 0;
 }
 
        return 0;
 }
 
@@ -802,8 +811,13 @@ static gint inc_recv_message(Session *session, const gchar *msg, gpointer data)
        gchar buf[MSGBUFSIZE];
        IncSession *inc_session = (IncSession *)data;
        Pop3Session *pop3_session = POP3_SESSION(session);
        gchar buf[MSGBUFSIZE];
        IncSession *inc_session = (IncSession *)data;
        Pop3Session *pop3_session = POP3_SESSION(session);
-       IncProgressDialog *inc_dialog = (IncProgressDialog *)inc_session->data;
-       ProgressDialog *dialog = inc_dialog->dialog;
+       IncProgressDialog *inc_dialog;
+       ProgressDialog *dialog;
+
+       g_return_val_if_fail(inc_session != NULL, -1);
+
+       inc_dialog = (IncProgressDialog *)inc_session->data;
+       dialog = inc_dialog->dialog;
 
        switch (pop3_session->state) {
        case POP3_GREETING:
 
        switch (pop3_session->state) {
        case POP3_GREETING:
index cadc7d52eacfd221589f4b5457ab1f09e13d0a58..04a5fc0ae6e08829ee696641bee045379a51a0d8 100644 (file)
@@ -67,6 +67,7 @@
 #include "prefs_folder_item.h"
 #include "prefs_summary_column.h"
 #include "prefs_template.h"
 #include "prefs_folder_item.h"
 #include "prefs_summary_column.h"
 #include "prefs_template.h"
+#include "action.h"
 #include "account.h"
 #include "addressbook.h"
 #include "logwindow.h"
 #include "account.h"
 #include "addressbook.h"
 #include "logwindow.h"
index bb025dd8087457b7bc50e8c0808b1511f40af164..e42937a8aa93e92f29e6afffb88dd072f3f22f1e 100644 (file)
 #include <glib.h>
 #include <gtk/gtk.h>
 #include <gdk/gdkkeysyms.h>
 #include <glib.h>
 #include <gtk/gtk.h>
 #include <gdk/gdkkeysyms.h>
-#include <gdk/gdkx.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <signal.h>
-#include <unistd.h>
 
 #include "intl.h"
 #include "prefs_gtk.h"
 
 #include "intl.h"
 #include "prefs_gtk.h"
 #include "prefs_common.h"
 #include "alertpanel.h"
 #include "prefs_actions.h"
 #include "prefs_common.h"
 #include "alertpanel.h"
 #include "prefs_actions.h"
-#include "compose.h"
-#include "procmsg.h"
-#include "gtkstext.h"
-#include "mimeview.h"
+#include "action.h"
 #include "description_window.h"
 #include "description_window.h"
-#include "textview.h"
-
-typedef enum
-{
-       ACTION_NONE             = 1 << 0,
-       ACTION_PIPE_IN          = 1 << 1,
-       ACTION_PIPE_OUT         = 1 << 2,
-       ACTION_SINGLE           = 1 << 3,
-       ACTION_MULTIPLE         = 1 << 4,
-       ACTION_ASYNC            = 1 << 5,
-       ACTION_USER_IN          = 1 << 6,
-       ACTION_USER_HIDDEN_IN   = 1 << 7,
-       ACTION_INSERT           = 1 << 8,
-       ACTION_USER_STR         = 1 << 9,
-       ACTION_USER_HIDDEN_STR  = 1 << 10,
-       ACTION_SELECTION_STR    = 1 << 11,
-       ACTION_ERROR            = 1 << 30,
-} ActionType;
 
 static struct Actions
 {
 
 static struct Actions
 {
@@ -82,54 +56,6 @@ static struct Actions
        GtkWidget *actions_clist;
 } actions;
 
        GtkWidget *actions_clist;
 } actions;
 
-typedef struct _Children Children;
-typedef struct _ChildInfo ChildInfo;
-typedef struct _UserStringDialog UserStringDialog;
-
-struct _Children
-{
-       GtkWidget       *dialog;
-       GtkWidget       *text;
-       GtkWidget       *input_entry;
-       GtkWidget       *input_hbox;
-       GtkWidget       *abort_btn;
-       GtkWidget       *close_btn;
-       GtkWidget       *scrolledwin;
-
-       gchar           *action;
-       GSList          *list;
-       gint             nb;
-       gint             open_in;
-       gboolean         output;
-};
-
-struct _ChildInfo
-{
-       Children        *children;
-       gchar           *cmd;
-       guint            type;
-       pid_t            pid;
-       gint             chld_in;
-       gint             chld_out;
-       gint             chld_err;
-       gint             chld_status;
-       gint             tag_in;
-       gint             tag_out;
-       gint             tag_err;
-       gint             tag_status;
-       gint             new_out;
-       GString         *output;
-       GtkWidget       *text;
-       GdkFont         *msgfont;
-};
-
-struct _UserStringDialog
-{
-       GtkWidget       *dialog;
-       GtkWidget       *entry;
-       gchar           *user_str;
-};
-
 /* widget creating functions */
 static void prefs_actions_create       (MainWindow *mainwin);
 static void prefs_actions_set_dialog   (void);
 /* widget creating functions */
 static void prefs_actions_create       (MainWindow *mainwin);
 static void prefs_actions_set_dialog   (void);
@@ -165,90 +91,6 @@ static void prefs_actions_cancel    (GtkWidget      *w,
                                         gpointer        data);
 static void prefs_actions_ok           (GtkWidget      *w,
                                         gpointer        data);
                                         gpointer        data);
 static void prefs_actions_ok           (GtkWidget      *w,
                                         gpointer        data);
-static void update_actions_menu                (GtkItemFactory *ifactory,
-                                        gchar          *branch_path,
-                                        gpointer        callback,
-                                        gpointer        data);
-static void compose_actions_execute_cb (Compose        *compose,
-                                        guint           action_nb,
-                                        GtkWidget      *widget);
-static void mainwin_actions_execute_cb         (MainWindow     *mainwin,
-                                        guint           action_nb,
-                                        GtkWidget      *widget);
-static void msgview_actions_execute_cb (MessageView    *msgview,
-                                        guint           action_nb,
-                                        GtkWidget      *widget);
-static void message_actions_execute    (MessageView    *msgview,
-                                        guint           action_nb,
-                                        GtkCTree       *ctree);
-static guint get_action_type           (gchar          *action);
-
-static gboolean execute_actions                (gchar          *action, 
-                                        GtkCTree       *ctree, 
-                                        GtkWidget      *text,
-                                        GdkFont        *msgfont,
-                                        gint            body_pos,
-                                        MimeView       *mimeview);
-
-static gchar *parse_action_cmd         (gchar          *action,
-                                        MsgInfo        *msginfo,
-                                        GtkCTree       *ctree,
-                                        MimeView       *mimeview,
-                                        const gchar    *user_str,
-                                        const gchar    *user_hidden_str,
-                                        const gchar    *sel_str);
-static gboolean parse_append_filename  (GString        **cmd,
-                                        MsgInfo        *msginfo);
-
-static gboolean parse_append_msgpart   (GString        **cmd,
-                                        MsgInfo        *msginfo,
-                                        MimeView       *mimeview);
-
-ChildInfo *fork_child                  (gchar          *cmd,
-                                        gint            action_type,
-                                        GtkWidget      *text,
-                                        GdkFont        *msgfont,
-                                        gint            body_pos,
-                                        Children       *children);
-
-static gint wait_for_children          (gpointer        data);
-
-static void free_children              (Children       *children);
-
-static void childinfo_close_pipes      (ChildInfo      *child_info);
-
-static void create_io_dialog           (Children       *children);
-static void update_io_dialog           (Children       *children);
-
-static void hide_io_dialog_cb          (GtkWidget      *widget,
-                                        gpointer        data);
-static gint io_dialog_key_pressed_cb   (GtkWidget      *widget,
-                                        GdkEventKey    *event,
-                                        gpointer        data);
-
-static void catch_output               (gpointer                data,
-                                        gint                    source,
-                                        GdkInputCondition       cond);
-static void catch_input                        (gpointer                data, 
-                                        gint                    source,
-                                        GdkInputCondition       cond);
-static void catch_status               (gpointer                data,
-                                        gint                    source,
-                                        GdkInputCondition       cond);
-
-static gboolean user_string_dialog_delete_cb
-                                       (GtkWidget      *widget,
-                                        GdkEvent       *event,
-                                        gpointer        data);
-static void user_string_dialog_destroy_cb
-                                       (GtkWidget      *widget,
-                                        gpointer        data);
-static void user_string_dialog_activate_cb
-                                       (GtkWidget      *widget,
-                                        gpointer        data);
-
-static gchar *get_user_string          (const gchar    *action,
-                                        ActionType      type);
 
 
 void prefs_actions_open(MainWindow *mainwin)
 
 
 void prefs_actions_open(MainWindow *mainwin)
@@ -527,245 +369,6 @@ void prefs_actions_write_config(void)
        }
 }
 
        }
 }
 
-static guint get_action_type(gchar *action)
-{
-       gchar *p;
-       guint action_type = ACTION_NONE;
-
-       g_return_val_if_fail(action,  ACTION_ERROR);
-       g_return_val_if_fail(*action, ACTION_ERROR);
-
-       p = action;
-
-       if (p[0] == '|') {
-               action_type |= ACTION_PIPE_IN;
-               p++;
-       } else if (p[0] == '>') {
-               action_type |= ACTION_USER_IN;
-               p++;
-       } else if (p[0] == '*') {
-               action_type |= ACTION_USER_HIDDEN_IN;
-               p++;
-       }
-
-       if (p[0] == 0x00)
-               return ACTION_ERROR;
-
-       while (*p && action_type != ACTION_ERROR) {
-               if (p[0] == '%') {
-                       switch (p[1]) {
-                       case 'f':
-                               action_type |= ACTION_SINGLE;
-                               break;
-                       case 'F':
-                               action_type |= ACTION_MULTIPLE;
-                               break;
-                       case 'p':
-                               action_type |= ACTION_SINGLE;
-                               break;
-                       case 's':
-                               action_type |= ACTION_SELECTION_STR;
-                               break;
-                       case 'u':
-                               action_type |= ACTION_USER_STR;
-                               break;
-                       case 'h':
-                               action_type |= ACTION_USER_HIDDEN_STR;
-                               break;
-                       default:
-                               action_type = ACTION_ERROR;
-                               break;
-                       }
-               } else if (p[0] == '|') {
-                       if (p[1] == 0x00)
-                               action_type |= ACTION_PIPE_OUT;
-               } else if (p[0] == '>') {
-                       if (p[1] == 0x00)
-                               action_type |= ACTION_INSERT;
-               } else if (p[0] == '&') {
-                       if (p[1] == 0x00)
-                               action_type |= ACTION_ASYNC;
-               }
-               p++;
-       }
-
-       return action_type;
-}
-
-static gchar *parse_action_cmd(gchar *action, MsgInfo *msginfo,
-                              GtkCTree *ctree, MimeView *mimeview,
-                              const gchar *user_str,
-                              const gchar *user_hidden_str,
-                              const gchar *sel_str)
-{
-       GString *cmd;
-       gchar *p;
-       GList *cur;
-       MsgInfo *msg;
-       
-       p = action;
-       
-       if (p[0] == '|' || p[0] == '>' || p[0] == '*')
-               p++;
-
-       cmd = g_string_sized_new(strlen(action));
-
-       while (p[0] &&
-              !((p[0] == '|' || p[0] == '>' || p[0] == '&') && !p[1])) {
-               if (p[0] == '%' && p[1]) {
-                       switch (p[1]) {
-                       case 'f':
-                               if (!parse_append_filename(&cmd, msginfo)) {
-                                       g_string_free(cmd, TRUE);
-                                       return NULL;
-                               }
-                               p++;
-                               break;
-                       case 'F':
-                               for (cur = GTK_CLIST(ctree)->selection;
-                                    cur != NULL; cur = cur->next) {
-                                       msg = gtk_ctree_node_get_row_data(ctree,
-                                             GTK_CTREE_NODE(cur->data));
-                                       if (!parse_append_filename(&cmd, msg)) {
-                                               g_string_free(cmd, TRUE);
-                                               return NULL;
-                                       }
-                                       if (cur->next)
-                                               cmd = g_string_append_c(cmd, ' ');
-                               }
-                               p++;
-                               break;
-                       case 'p':
-                               if (!parse_append_msgpart(&cmd, msginfo,
-                                                         mimeview)) {
-                                       g_string_free(cmd, TRUE);
-                                       return NULL;
-                               }
-                               p++;
-                               break;
-                       case 's':
-                               if (sel_str)
-                                       cmd = g_string_append(cmd, sel_str);
-                               p++;
-                               break;
-                       case 'u':
-                               if (user_str)
-                                       cmd = g_string_append(cmd, user_str);
-                               p++;
-                               break;
-                       case 'h':
-                               if (user_hidden_str)
-                                       cmd = g_string_append(cmd,
-                                                             user_hidden_str);
-                               p++;
-                               break;
-                       default:
-                               cmd = g_string_append_c(cmd, p[0]);
-                               cmd = g_string_append_c(cmd, p[1]);
-                               p++;
-                       }
-               } else {
-                       cmd = g_string_append_c(cmd, p[0]);
-               }
-               p++;
-       }
-       if (cmd->len == 0) {
-               g_string_free(cmd, TRUE);
-               return NULL;
-       }
-
-       p = cmd->str;
-       g_string_free(cmd, FALSE);
-       return p;
-}
-
-static gboolean parse_append_filename(GString **cmd, MsgInfo *msginfo)
-{
-       gchar *filename;
-
-       g_return_val_if_fail(msginfo, FALSE);
-
-       filename = procmsg_get_message_file(msginfo);
-
-       if (filename) {
-               *cmd = g_string_append(*cmd, filename);
-               g_free(filename);
-       } else {
-               alertpanel_error(_("Could not get message file %d"),
-                                msginfo->msgnum);
-               return FALSE;
-       }
-
-       return TRUE;
-}
-
-static gboolean parse_append_msgpart(GString **cmd, MsgInfo *msginfo,
-                                    MimeView *mimeview)
-{
-       gchar    *filename;
-       gchar    *partname;
-       MimeInfo *partinfo;
-       gint      ret;
-       FILE     *fp;
-
-       if (!mimeview) {
-#if USE_GPGME
-               if ((fp = procmsg_open_message_decrypted(msginfo, &partinfo))
-                   == NULL) {
-                       alertpanel_error(_("Could not get message file."));
-                       return FALSE;
-               }
-#else
-               if ((fp = procmsg_open_message(msginfo)) == NULL) {
-                       alertpanel_error(_("Could not get message file."));
-                       return FALSE;
-               }
-               partinfo = procmime_scan_mime_header(fp);
-#endif
-               fclose(fp);
-               if (!partinfo) {
-                       procmime_mimeinfo_free_all(partinfo);
-                       alertpanel_error(_("Could not get message part."));
-                       return FALSE;
-               }
-               filename = procmsg_get_message_file(msginfo);
-       } else {
-               if (!mimeview->opened) {
-                       alertpanel_error(_("No message part selected."));
-                       return FALSE;
-               }
-               if (!mimeview->file) {
-                       alertpanel_error(_("No message file selected."));
-                       return FALSE;
-               }
-               partinfo = gtk_ctree_node_get_row_data
-                               (GTK_CTREE(mimeview->ctree),
-                                mimeview->opened);
-               g_return_val_if_fail(partinfo != NULL, FALSE);
-               filename = mimeview->file;
-       }
-       partname = procmime_get_tmp_file_name(partinfo);
-
-       ret = procmime_get_part(partname, filename, partinfo); 
-
-       if (!mimeview) {
-               procmime_mimeinfo_free_all(partinfo);
-               g_free(filename);
-       }
-
-       if (ret < 0) {
-               alertpanel_error(_("Can't get part of multipart message"));
-               g_free(partname);
-               return FALSE;
-       }
-
-       *cmd = g_string_append(*cmd, partname);
-
-       g_free(partname);
-
-       return TRUE;
-}
-
 static void prefs_actions_set_dialog(void)
 {
        GtkCList *clist = GTK_CLIST(actions.actions_clist);
 static void prefs_actions_set_dialog(void)
 {
        GtkCList *clist = GTK_CLIST(actions.actions_clist);
@@ -1026,983 +629,6 @@ static void prefs_actions_ok(GtkWidget *widget, gpointer data)
        inc_unlock();
 }
 
        inc_unlock();
 }
 
-void update_mainwin_actions_menu(GtkItemFactory *ifactory,
-                                MainWindow *mainwin)
-{
-       update_actions_menu(ifactory, "/Tools/Actions",
-                           mainwin_actions_execute_cb,
-                           mainwin);
-}
-
-void update_compose_actions_menu(GtkItemFactory *ifactory,
-                                gchar *branch_path,
-                                Compose *compose)
-{
-       update_actions_menu(ifactory, branch_path,
-                           compose_actions_execute_cb,
-                           compose);
-}
-
-
-void actions_execute(gpointer data, 
-                    guint action_nb,
-                    GtkWidget *widget,
-                    gint source)
-{
-       if (source == TOOLBAR_MAIN) 
-               mainwin_actions_execute_cb((MainWindow*)data, action_nb, widget);
-       else if (source == TOOLBAR_COMPOSE)
-               compose_actions_execute_cb((Compose*)data, action_nb, widget);
-       else if (source == TOOLBAR_MSGVIEW)
-               msgview_actions_execute_cb((MessageView*)data, action_nb, widget);      
-}
-
-
-static void update_actions_menu(GtkItemFactory *ifactory,
-                               gchar *branch_path,
-                               gpointer callback,
-                               gpointer data)
-{
-       GtkWidget *menuitem;
-       gchar *menu_path;
-       GSList *cur;
-       gchar *action, *action_p;
-       GList *amenu;
-       GtkItemFactoryEntry ifentry = {NULL, NULL, NULL, 0, "<Branch>"};
-
-       ifentry.path = branch_path;
-       menuitem = gtk_item_factory_get_widget(ifactory, branch_path);
-       g_return_if_fail(menuitem != NULL);
-
-       amenu = GTK_MENU_SHELL(menuitem)->children;
-       while (amenu != NULL) {
-               GList *alist = amenu->next;
-               gtk_widget_destroy(GTK_WIDGET(amenu->data));
-               amenu = alist;
-       }
-
-       ifentry.accelerator     = NULL;
-       ifentry.callback_action = 0;
-       ifentry.callback        = callback;
-       ifentry.item_type       = NULL;
-
-       for (cur = prefs_common.actions_list; cur; cur = cur->next) {
-               action   = g_strdup((gchar *)cur->data);
-               action_p = strstr(action, ": ");
-               if (action_p && action_p[2] &&
-                   get_action_type(&action_p[2]) != ACTION_ERROR) {
-                       action_p[0] = 0x00;
-                       menu_path = g_strdup_printf("%s/%s", branch_path,
-                                                   action);
-                       ifentry.path = menu_path;
-                       gtk_item_factory_create_item(ifactory, &ifentry, data,
-                                                    1);
-                       g_free(menu_path);
-               }
-               g_free(action);
-               ifentry.callback_action++;
-       }
-}
-
-static void compose_actions_execute_cb(Compose *compose, guint action_nb,
-                                      GtkWidget *widget)
-{
-       gchar *buf, *action;
-       guint action_type;
-
-       g_return_if_fail(action_nb < g_slist_length(prefs_common.actions_list));
-
-       buf = (gchar *)g_slist_nth_data(prefs_common.actions_list, action_nb);
-       g_return_if_fail(buf != NULL);
-       action = strstr(buf, ": ");
-       g_return_if_fail(action != NULL);
-
-       /* Point to the beginning of the command-line */
-       action += 2;
-
-       action_type = get_action_type(action);
-       if (action_type & (ACTION_SINGLE | ACTION_MULTIPLE)) {
-               alertpanel_warning
-                       (_("The selected action cannot be used in the compose window\n"
-                          "because it contains %%f, %%F or %%p."));
-               return;
-       }
-
-       execute_actions(action, NULL, compose->text, NULL, 0, NULL);
-}
-
-static void mainwin_actions_execute_cb(MainWindow *mainwin, guint action_nb,
-                                      GtkWidget *widget)
-{
-       message_actions_execute(mainwin->messageview, action_nb,
-                               GTK_CTREE(mainwin->summaryview->ctree));
-}
-
-static void msgview_actions_execute_cb(MessageView *msgview, guint action_nb,
-                                      GtkWidget *widget)
-{
-       message_actions_execute(msgview, action_nb, NULL);
-}
-
-static void message_actions_execute(MessageView *msgview, guint action_nb,
-                                   GtkCTree *ctree)
-{
-       TextView *textview = NULL;
-       MimeView *mimeview = NULL;
-       gchar *buf;
-       gchar *action;
-       GtkWidget *text = NULL;
-       GdkFont *msgfont = NULL;
-       guint body_pos = 0;
-
-       g_return_if_fail(action_nb < g_slist_length(prefs_common.actions_list));
-
-       buf = (gchar *)g_slist_nth_data(prefs_common.actions_list, action_nb);
-
-       g_return_if_fail(buf);
-       g_return_if_fail(action = strstr(buf, ": "));
-
-       /* Point to the beginning of the command-line */
-       action += 2;
-
-       switch (msgview->type) {
-       case MVIEW_TEXT:
-               if (msgview->textview && msgview->textview->text)
-                       textview = msgview->textview;
-               break;
-       case MVIEW_MIME:
-               if (msgview->mimeview) {
-                       mimeview = msgview->mimeview;
-                       if (msgview->mimeview->type == MIMEVIEW_TEXT &&
-                           msgview->mimeview->textview &&
-                           msgview->mimeview->textview->text)
-                               textview = msgview->mimeview->textview;
-               }
-               break;
-       }
-
-       if (textview) {
-               text     = textview->text;
-               msgfont  = textview->msgfont;
-               body_pos = textview->body_pos;
-       }
-
-       execute_actions(action, ctree, text, msgfont, body_pos, mimeview);
-}
-
-static gboolean execute_actions(gchar *action, GtkCTree *ctree,
-                               GtkWidget *text, GdkFont *msgfont,
-                               gint body_pos, MimeView *mimeview)
-{
-       GList *cur, *selection = NULL;
-       GSList *children_list = NULL;
-       gint is_ok  = TRUE;
-       gint selection_len = 0;
-       Children *children;
-       ChildInfo *child_info;
-       gint action_type;
-       MsgInfo *msginfo;
-       gchar *cmd;
-       gchar *sel_str = NULL;
-       gchar *user_str = NULL;
-       gchar *user_hidden_str = NULL;
-
-       g_return_val_if_fail(action && *action, FALSE);
-
-       action_type = get_action_type(action);
-
-       if (action_type == ACTION_ERROR)
-               return FALSE;         /* ERR: syntax error */
-
-       if (action_type & (ACTION_SINGLE | ACTION_MULTIPLE) && 
-           !(ctree && GTK_CLIST(ctree)->selection))
-               return FALSE;         /* ERR: file command without selection */
-
-       if (ctree) {
-               selection = GTK_CLIST(ctree)->selection;
-               selection_len = g_list_length(selection);
-       }
-
-       if (action_type & (ACTION_PIPE_OUT | ACTION_PIPE_IN | ACTION_INSERT)) {
-               if (ctree && selection_len > 1)
-                       return FALSE; /* ERR: pipe + multiple selection */
-               if (!text)
-                       return FALSE; /* ERR: pipe and no displayed text */
-       }
-
-       if (action_type & ACTION_SELECTION_STR) {
-               if (!text)
-                       return FALSE; /* ERR: selection string but no text */
-               else {
-                       guint start = 0, end = 0;
-                       if (GTK_EDITABLE(text)->has_selection) {
-                               start = GTK_EDITABLE(text)->selection_start_pos;
-                               end   = GTK_EDITABLE(text)->selection_end_pos;
-                               if (start > end) {
-                                       guint tmp;
-                                       tmp = start;
-                                       start = end;
-                                       end = tmp;
-                               }
-                       }
-                       sel_str = gtk_editable_get_chars(GTK_EDITABLE(text),
-                                                        start, end);
-               }
-       }
-
-       if (action_type & (ACTION_USER_STR))
-               if (!(user_str = get_user_string(action, ACTION_USER_STR)))
-                       return FALSE;
-
-       if (action_type & (ACTION_USER_HIDDEN_STR))
-               if (!(user_hidden_str =
-                       get_user_string(action, ACTION_USER_HIDDEN_STR)))
-                       return FALSE;
-
-       children = g_new0(Children, 1);
-
-       if (action_type & ACTION_SINGLE) {
-               for (cur = selection; cur && is_ok == TRUE; cur = cur->next) {
-                       msginfo = gtk_ctree_node_get_row_data(ctree,
-                                       GTK_CTREE_NODE(cur->data));
-                       if (!msginfo) {
-                               is_ok  = FALSE; /* ERR: msginfo missing */
-                               break;
-                       }
-                       cmd = parse_action_cmd(action, msginfo, ctree,
-                                              mimeview, user_str,
-                                              user_hidden_str, sel_str);
-                       if (!cmd) {
-                               debug_print("Action command error\n");
-                               is_ok  = FALSE; /* ERR: incorrect command */
-                               break;
-                       }
-                       if ((child_info = fork_child(cmd, action_type, text,
-                                                    msgfont, body_pos,
-                                                    children))) {
-                               children_list = g_slist_append(children_list,
-                                                              child_info);
-                               children->open_in = (selection_len == 1) ?
-                                                   (action_type &
-                                                    (ACTION_USER_IN |
-                                                     ACTION_USER_HIDDEN_IN)) : 0;
-                       }
-                       g_free(cmd);
-               }
-       } else {
-               cmd = parse_action_cmd(action, NULL, ctree, mimeview, user_str,
-                                      user_hidden_str, sel_str);
-               if (cmd) {
-                       if ((child_info = fork_child(cmd, action_type, text,
-                                                    msgfont, body_pos,
-                                                    children))) {
-                               children_list = g_slist_append(children_list,
-                                                              child_info);
-                               children->open_in = action_type &
-                                                   (ACTION_USER_IN |
-                                                    ACTION_USER_HIDDEN_IN);
-                       }
-                       g_free(cmd);
-               } else
-                       is_ok  = FALSE;         /* ERR: incorrect command */
-       }
-
-       g_free(user_str);
-       g_free(user_hidden_str);
-
-       if (!children_list) {
-                /* If not waiting for children, return */
-               g_free(children);
-       } else {
-               GSList *cur;
-
-               children->action  = g_strdup(action);
-               children->dialog  = NULL;
-               children->list    = children_list;
-               children->nb      = g_slist_length(children_list);
-
-               for (cur = children_list; cur; cur = cur->next) {
-                       child_info = (ChildInfo *) cur->data;
-                       child_info->tag_status = 
-                               gdk_input_add(child_info->chld_status,
-                                             GDK_INPUT_READ,
-                                             catch_status, child_info);
-               }
-
-               create_io_dialog(children);
-       }
-
-       return is_ok;
-}
-
-ChildInfo *fork_child(gchar *cmd, gint action_type, GtkWidget *text,
-                     GdkFont *msgfont, gint body_pos, Children *children)
-{
-       gint chld_in[2], chld_out[2], chld_err[2], chld_status[2];
-       gchar *cmdline[4];
-       guint start, end;
-       gint is_selection;
-       gchar *selection;
-       pid_t pid, gch_pid;
-       ChildInfo *child_info;
-       gint sync;
-
-       sync = !(action_type & ACTION_ASYNC);
-
-       chld_in[0] = chld_in[1] = chld_out[0] = chld_out[1] = chld_err[0]
-               = chld_err[1] = chld_status[0] = chld_status[1] = -1;
-
-       if (sync) {
-               if (pipe(chld_status) || pipe(chld_in) || pipe(chld_out) ||
-                   pipe(chld_err)) {
-                       alertpanel_error(_("Command could not be started. "
-                                          "Pipe creation failed.\n%s"),
-                                       g_strerror(errno));
-                       /* Closing fd = -1 fails silently */
-                       close(chld_in[0]);
-                       close(chld_in[1]);
-                       close(chld_out[0]);
-                       close(chld_out[1]);
-                       close(chld_err[0]);
-                       close(chld_err[1]);
-                       close(chld_status[0]);
-                       close(chld_status[1]);
-                       return NULL; /* Pipe error */
-               }
-       }
-
-       debug_print("Forking child and grandchild.\n");
-
-       pid = fork();
-       if (pid == 0) { /* Child */
-               if (setpgid(0, 0))
-                       perror("setpgid");
-
-               close(ConnectionNumber(gdk_display));
-
-               gch_pid = fork();
-
-               if (gch_pid == 0) {
-                       if (setpgid(0, getppid()))
-                               perror("setpgid");
-                       if (sync) {
-                               if (action_type &
-                                   (ACTION_PIPE_IN |
-                                    ACTION_USER_IN |
-                                    ACTION_USER_HIDDEN_IN)) {
-                                       close(fileno(stdin));
-                                       dup  (chld_in[0]);
-                               }
-                               close(chld_in[0]);
-                               close(chld_in[1]);
-
-                               close(fileno(stdout));
-                               dup  (chld_out[1]);
-                               close(chld_out[0]);
-                               close(chld_out[1]);
-
-                               close(fileno(stderr));
-                               dup  (chld_err[1]);
-                               close(chld_err[0]);
-                               close(chld_err[1]);
-                       }
-
-                       cmdline[0] = "sh";
-                       cmdline[1] = "-c";
-                       cmdline[2] = cmd;
-                       cmdline[3] = 0;
-                       execvp("/bin/sh", cmdline);
-
-                       perror("execvp");
-                       _exit(1);
-               } else if (gch_pid < (pid_t) 0) { /* Fork error */
-                       if (sync)
-                               write(chld_status[1], "1\n", 2);
-                       perror("fork");
-                       _exit(1);
-               } else { /* Child */
-                       if (sync) {
-                               close(chld_in[0]);
-                               close(chld_in[1]);
-                               close(chld_out[0]);
-                               close(chld_out[1]);
-                               close(chld_err[0]);
-                               close(chld_err[1]);
-                               close(chld_status[0]);
-                       }
-                       if (sync) {
-                               debug_print("Child: Waiting for grandchild\n");
-                               waitpid(gch_pid, NULL, 0);
-                               debug_print("Child: grandchild ended\n");
-                               write(chld_status[1], "0\n", 2);
-                               close(chld_status[1]);
-                       }
-                       _exit(0);
-               }
-       } else if (pid < 0) { /* Fork error */
-               alertpanel_error(_("Could not fork to execute the following "
-                                  "command:\n%s\n%s"),
-                                cmd, g_strerror(errno));
-               return NULL; 
-       }
-
-       /* Parent */
-
-       if (!sync) {
-               waitpid(pid, NULL, 0);
-               return NULL;
-       }
-
-       close(chld_in[0]);
-       if (!(action_type & (ACTION_PIPE_IN | ACTION_USER_IN | ACTION_USER_HIDDEN_IN)))
-               close(chld_in[1]);
-       close(chld_out[1]);
-       close(chld_err[1]);
-       close(chld_status[1]);
-
-       child_info = g_new0(ChildInfo, 1);
-
-       child_info->children    = children;
-
-       child_info->pid         = pid;
-       child_info->cmd         = g_strdup(cmd);
-       child_info->type        = action_type;
-       child_info->new_out     = FALSE;
-       child_info->output      = g_string_sized_new(0);
-       child_info->chld_in     =
-               (action_type &
-                (ACTION_PIPE_IN | ACTION_USER_IN | ACTION_USER_HIDDEN_IN))
-                       ? chld_in [1] : -1;
-       child_info->chld_out    = chld_out[0];
-       child_info->chld_err    = chld_err[0];
-       child_info->chld_status = chld_status[0];
-       child_info->tag_in      = -1;
-       child_info->tag_out     = gdk_input_add(chld_out[0], GDK_INPUT_READ,
-                                               catch_output, child_info);
-       child_info->tag_err     = gdk_input_add(chld_err[0], GDK_INPUT_READ,
-                                               catch_output, child_info);
-
-       if (!(action_type & (ACTION_PIPE_IN | ACTION_PIPE_OUT | ACTION_INSERT)))
-               return child_info;
-
-       child_info->text        = text;
-       child_info->msgfont     = msgfont;
-
-       start = body_pos;
-       end   = gtk_stext_get_length(GTK_STEXT(text));
-
-       if (GTK_EDITABLE(text)->has_selection) {
-               start = GTK_EDITABLE(text)->selection_start_pos;
-               end   = GTK_EDITABLE(text)->selection_end_pos;
-               if (start > end) {
-                       guint tmp;
-                       tmp = start;
-                       start = end;
-                       end = tmp;
-               }
-               is_selection = TRUE;
-               if (start == end) {
-                       start = 0;
-                       end = gtk_stext_get_length(GTK_STEXT(text));
-                       is_selection = FALSE;
-               }
-       }
-
-       selection = gtk_editable_get_chars(GTK_EDITABLE(text), start, end);
-
-       if (action_type & ACTION_PIPE_IN) {
-               write(chld_in[1], selection, strlen(selection));
-               if (!(action_type & (ACTION_USER_IN | ACTION_USER_HIDDEN_IN)))
-                       close(chld_in[1]);
-               child_info->chld_in = -1; /* No more input */
-       }
-       g_free(selection);
-
-       gtk_stext_freeze(GTK_STEXT(text));
-       if (action_type & ACTION_PIPE_OUT) {
-               gtk_stext_set_point(GTK_STEXT(text), start);
-               gtk_stext_forward_delete(GTK_STEXT(text), end - start);
-       }
-
-       gtk_stext_thaw(GTK_STEXT(text));
-
-       return child_info;
-}
-
-static void kill_children_cb(GtkWidget *widget, gpointer data)
-{
-       GSList *cur;
-       Children *children = (Children *) data;
-       ChildInfo *child_info;
-
-       for (cur = children->list; cur; cur = cur->next) {
-               child_info = (ChildInfo *)(cur->data);
-               debug_print("Killing child group id %d\n", child_info->pid);
-               if (child_info->pid && kill(-child_info->pid, SIGTERM) < 0)
-                       perror("kill");
-       }
-}
-
-static gint wait_for_children(gpointer data)
-{
-       gboolean new_output;
-       Children *children = (Children *)data;
-       ChildInfo *child_info;
-       GSList *cur;
-       gint nb = children->nb;
-
-       children->nb = 0;
-
-       cur = children->list;
-       new_output = FALSE;
-       while (cur) {
-               child_info = (ChildInfo *)cur->data;
-               if (child_info->pid)
-                       children->nb++;
-               new_output |= child_info->new_out;
-               cur = cur->next;
-       }
-
-       children->output |= new_output;
-
-       if (new_output || (children->dialog && (nb != children->nb)))
-               update_io_dialog(children);
-
-       if (children->nb)
-               return FALSE;
-
-       if (!children->dialog) {
-               free_children(children);
-       } else if (!children->output) {
-               gtk_widget_destroy(children->dialog);
-       }
-
-       return FALSE;
-}
-
-static void send_input(GtkWidget *w, gpointer data)
-{
-       Children *children = (Children *) data;
-       ChildInfo *child_info = (ChildInfo *) children->list->data;
-
-       child_info->tag_in = gdk_input_add(child_info->chld_in,
-                                          GDK_INPUT_WRITE,
-                                          catch_input, children);
-       gtk_widget_set_sensitive(children->input_hbox, FALSE);
-}
-
-static gint delete_io_dialog_cb(GtkWidget *w, GdkEvent *e, gpointer data)
-{
-       hide_io_dialog_cb(w, data);
-       return TRUE;
-}
-
-static void hide_io_dialog_cb(GtkWidget *w, gpointer data)
-{
-
-       Children *children = (Children *)data;
-
-       if (!children->nb) {
-               gtk_signal_disconnect_by_data(GTK_OBJECT(children->dialog),
-                                             children);
-               gtk_widget_destroy(children->dialog);
-               free_children(children);
-       }
-}
-
-static gint io_dialog_key_pressed_cb(GtkWidget *widget, GdkEventKey *event,
-                                    gpointer data)
-{
-       if (event && event->keyval == GDK_Escape)
-               hide_io_dialog_cb(widget, data);
-       return TRUE;
-}
-
-static void childinfo_close_pipes(ChildInfo *child_info)
-{
-       if (child_info->tag_in > 0)
-               gdk_input_remove(child_info->tag_in);
-       gdk_input_remove(child_info->tag_out);
-       gdk_input_remove(child_info->tag_err);
-
-       if (child_info->chld_in >= 0)
-               close(child_info->chld_in);
-       close(child_info->chld_out);
-       close(child_info->chld_err);
-       close(child_info->chld_status);
-}
-
-static void free_children(Children *children)
-{
-       GSList *cur;
-       ChildInfo *child_info;
-
-       debug_print("Freeing children data %p\n", children);
-
-       g_free(children->action);
-       for (cur = children->list; cur;) {
-               child_info = (ChildInfo *)cur->data;
-               g_free(child_info->cmd);
-               g_string_free(child_info->output, TRUE);
-               children->list = g_slist_remove(children->list, child_info);
-               g_free(child_info);
-               cur = children->list;
-       }
-       g_free(children);
-}
-
-static void update_io_dialog(Children *children)
-{
-       GSList *cur;
-
-       debug_print("Updating actions input/output dialog.\n");
-
-       if (!children->nb) {
-               gtk_widget_set_sensitive(children->abort_btn, FALSE);
-               gtk_widget_set_sensitive(children->close_btn, TRUE);
-               if (children->input_hbox)
-                       gtk_widget_set_sensitive(children->input_hbox, FALSE);
-               gtk_widget_grab_focus(children->close_btn);
-               gtk_signal_connect(GTK_OBJECT(children->dialog),
-                                  "key_press_event",
-                                  GTK_SIGNAL_FUNC(io_dialog_key_pressed_cb),
-                                  children);
-       }
-
-       if (children->output) {
-               GtkWidget *text = children->text;
-               gchar *caption;
-               ChildInfo *child_info;
-
-               gtk_widget_show(children->scrolledwin);
-               gtk_text_freeze(GTK_TEXT(text));
-               gtk_text_set_point(GTK_TEXT(text), 0);
-               gtk_text_forward_delete(GTK_TEXT(text), 
-                                       gtk_text_get_length(GTK_TEXT(text)));
-               for (cur = children->list; cur; cur = cur->next) {
-                       child_info = (ChildInfo *)cur->data;
-                       if (child_info->pid)
-                               caption = g_strdup_printf
-                                       (_("--- Running: %s\n"),
-                                        child_info->cmd);
-                       else
-                               caption = g_strdup_printf
-                                       (_("--- Ended: %s\n"),
-                                        child_info->cmd);
-
-                       gtk_text_insert(GTK_TEXT(text), NULL, NULL, NULL,
-                                       caption, -1);
-                       gtk_text_insert(GTK_TEXT(text), NULL, NULL, NULL,
-                                       child_info->output->str, -1);
-                       g_free(caption);
-                       child_info->new_out = FALSE;
-               }
-               gtk_text_thaw(GTK_TEXT(text));
-       }
-}
-
-static void create_io_dialog(Children *children)
-{
-       GtkWidget *dialog;
-       GtkWidget *vbox;
-       GtkWidget *entry = NULL;
-       GtkWidget *input_hbox = NULL;
-       GtkWidget *send_button;
-       GtkWidget *label;
-       GtkWidget *text;
-       GtkWidget *scrolledwin;
-       GtkWidget *hbox;
-       GtkWidget *abort_button;
-       GtkWidget *close_button;
-
-       debug_print("Creating action IO dialog\n");
-
-       dialog = gtk_dialog_new();
-       gtk_container_set_border_width
-               (GTK_CONTAINER(GTK_DIALOG(dialog)->action_area), 5);
-       gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER);
-       gtk_window_set_title(GTK_WINDOW(dialog), _("Action's input/output"));
-       gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
-       manage_window_set_transient(GTK_WINDOW(dialog));
-       gtk_signal_connect(GTK_OBJECT(dialog), "delete_event",
-                       GTK_SIGNAL_FUNC(delete_io_dialog_cb), children);
-       gtk_signal_connect(GTK_OBJECT(dialog), "destroy",
-                       GTK_SIGNAL_FUNC(hide_io_dialog_cb),
-                       children);
-
-       vbox = gtk_vbox_new(FALSE, 8);
-       gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), vbox);
-       gtk_container_set_border_width(GTK_CONTAINER(vbox), 8);
-       gtk_widget_show(vbox);
-
-       label = gtk_label_new(children->action);
-       gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
-       gtk_widget_show(label);
-
-       scrolledwin = gtk_scrolled_window_new(NULL, NULL);
-       gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwin),
-                                      GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
-       gtk_box_pack_start(GTK_BOX(vbox), scrolledwin, TRUE, TRUE, 0);
-       gtk_widget_set_usize(scrolledwin, 480, 200);
-       gtk_widget_hide(scrolledwin);
-
-       text = gtk_text_new(gtk_scrolled_window_get_hadjustment
-                           (GTK_SCROLLED_WINDOW(scrolledwin)),
-                           gtk_scrolled_window_get_vadjustment
-                           (GTK_SCROLLED_WINDOW(scrolledwin)));
-       gtk_text_set_editable(GTK_TEXT(text), FALSE);
-       gtk_container_add(GTK_CONTAINER(scrolledwin), text);
-       gtk_widget_show(text);
-
-       if (children->open_in) {
-               input_hbox = gtk_hbox_new(FALSE, 8);
-               gtk_widget_show(input_hbox);
-
-               entry = gtk_entry_new();
-               gtk_widget_set_usize(entry, 320, -1);
-               gtk_signal_connect(GTK_OBJECT(entry), "activate",
-                                  GTK_SIGNAL_FUNC(send_input), children);
-               gtk_box_pack_start(GTK_BOX(input_hbox), entry, TRUE, TRUE, 0);
-               if (children->open_in & ACTION_USER_HIDDEN_IN)
-                       gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE);
-               gtk_widget_show(entry);
-
-               send_button = gtk_button_new_with_label(_(" Send "));
-               gtk_signal_connect(GTK_OBJECT(send_button), "clicked",
-                                  GTK_SIGNAL_FUNC(send_input), children);
-               gtk_box_pack_start(GTK_BOX(input_hbox), send_button, FALSE,
-                                  FALSE, 0);
-               gtk_widget_show(send_button);
-
-               gtk_box_pack_start(GTK_BOX(vbox), input_hbox, FALSE, FALSE, 0);
-               gtk_widget_grab_focus(entry);
-       }
-
-       gtkut_button_set_create(&hbox, &abort_button, _("Abort"),
-                               &close_button, _("Close"), NULL, NULL);
-       gtk_signal_connect(GTK_OBJECT(abort_button), "clicked",
-                       GTK_SIGNAL_FUNC(kill_children_cb), children);
-       gtk_signal_connect(GTK_OBJECT(close_button), "clicked",
-                       GTK_SIGNAL_FUNC(hide_io_dialog_cb), children);
-       gtk_widget_show(hbox);
-
-       if (children->nb)
-               gtk_widget_set_sensitive(close_button, FALSE);
-
-       gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area), hbox);
-
-       children->dialog      = dialog;
-       children->scrolledwin = scrolledwin;
-       children->text        = text;
-       children->input_hbox  = children->open_in ? input_hbox : NULL;
-       children->input_entry = children->open_in ? entry : NULL;
-       children->abort_btn   = abort_button;
-       children->close_btn   = close_button;
-
-       gtk_widget_show(dialog);
-}
-
-static void catch_status(gpointer data, gint source, GdkInputCondition cond)
-{
-       ChildInfo *child_info = (ChildInfo *)data;
-       gchar buf;
-       gint c;
-
-       gdk_input_remove(child_info->tag_status);
-
-       c = read(source, &buf, 1);
-       debug_print("Child returned %c\n", buf);
-
-       waitpid(-child_info->pid, NULL, 0);
-       childinfo_close_pipes(child_info);
-       child_info->pid = 0;
-
-       wait_for_children(child_info->children);
-}
-       
-static void catch_input(gpointer data, gint source, GdkInputCondition cond)
-{
-       Children *children = (Children *)data;
-       ChildInfo *child_info = (ChildInfo *)children->list->data;
-       gchar *input;
-       gint c, count, len;
-
-       debug_print("Sending input to grand child.\n");
-       if (!(cond && GDK_INPUT_WRITE))
-               return;
-
-       gdk_input_remove(child_info->tag_in);
-       child_info->tag_in = -1;
-
-       input = gtk_editable_get_chars(GTK_EDITABLE(children->input_entry),
-                                      0, -1);
-       len = strlen(input);
-       count = 0;
-
-       do {
-               c = write(child_info->chld_in, input + count, len - count);
-               if (c >= 0)
-                       count += c;
-       } while (c >= 0 && count < len);
-
-       if (c >= 0)
-               write(child_info->chld_in, "\n", 2);
-
-       g_free(input);
-
-       gtk_entry_set_text(GTK_ENTRY(children->input_entry), "");
-       gtk_widget_set_sensitive(children->input_hbox, TRUE);
-       close(child_info->chld_in);
-       child_info->chld_in = -1;
-       debug_print("Input to grand child sent.\n");
-}
-
-static void catch_output(gpointer data, gint source, GdkInputCondition cond)
-{
-       ChildInfo *child_info = (ChildInfo *)data;
-       gint c, i;
-       gchar buf[PREFSBUFSIZE];
-
-       debug_print("Catching grand child's output.\n");
-       if (child_info->type & (ACTION_PIPE_OUT | ACTION_INSERT)
-           && source == child_info->chld_out) {
-               gboolean is_selection = FALSE;
-               GtkWidget *text = child_info->text;
-               if (GTK_EDITABLE(text)->has_selection)
-                       is_selection = TRUE;
-               gtk_stext_freeze(GTK_STEXT(text));
-               while (TRUE) {
-                       c = read(source, buf, PREFSBUFSIZE - 1);
-                       if (c == 0)
-                               break;
-                       gtk_stext_insert(GTK_STEXT(text), child_info->msgfont,
-                                        NULL, NULL, buf, c);
-               }
-               if (is_selection) {
-                       /* Using the select_region draws things. Should not.
-                        * so we just change selection position and 
-                        * defere drawing when thawing. Hack?
-                        */
-                       GTK_EDITABLE(text)->selection_end_pos =
-                                       gtk_stext_get_point(GTK_STEXT(text));
-               }
-               gtk_stext_thaw(GTK_STEXT(child_info->text));
-       } else {
-               c = read(source, buf, PREFSBUFSIZE - 1);
-               for (i = 0; i < c; i++)
-                       child_info->output = g_string_append_c
-                               (child_info->output, buf[i]);
-               if (c > 0)
-                       child_info->new_out = TRUE;
-       }
-       wait_for_children(child_info->children);
-}
-
-static gboolean user_string_dialog_delete_cb(GtkWidget *widget,
-                                            GdkEvent *event, gpointer data)
-{
-       return FALSE;
-}
-
-static void user_string_dialog_destroy_cb(GtkWidget *widget, gpointer data)
-{
-       gtk_main_quit();
-}
-
-static void user_string_dialog_activate_cb(GtkWidget *widget, gpointer data)
-{
-       UserStringDialog *user_dialog = (UserStringDialog *) data;
-
-       g_free(user_dialog->user_str);
-       user_dialog->user_str =
-               gtk_editable_get_chars(GTK_EDITABLE(user_dialog->entry), 0, -1);
-       gtk_widget_destroy(user_dialog->dialog);
-}
-
-static gchar *get_user_string(const gchar *action, ActionType type)
-{
-       GtkWidget *dialog;
-       GtkWidget *label;
-       GtkWidget *entry;
-       GtkWidget *ok_button;
-       GtkWidget *cancel_button;
-       gchar *label_text;
-       UserStringDialog user_dialog;
-
-       dialog = gtk_dialog_new();
-       gtk_window_set_policy(GTK_WINDOW(dialog), FALSE, FALSE, FALSE);
-       gtk_container_set_border_width
-               (GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), 8);
-       gtk_container_set_border_width
-               (GTK_CONTAINER(GTK_DIALOG(dialog)->action_area), 5);
-       gtk_window_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER);
-
-       switch (type) {
-       case ACTION_USER_HIDDEN_STR:
-               gtk_window_set_title(GTK_WINDOW(dialog),
-                                    _("Action's hidden user argument"));
-               label_text = g_strdup_printf(_("Enter the '%%h' "
-                                            "argument for the following "
-                                            "action:\n%s"), action);
-               break;
-       case ACTION_USER_STR:
-               gtk_window_set_title(GTK_WINDOW(dialog),
-                                    _("Action's user argument"));
-               label_text = g_strdup_printf(_("Enter the '%%u' "
-                                            "argument for the following "
-                                            "action:\n%s"), action);
-               break;
-       default:
-               label_text = NULL;
-               debug_print("Unsupported action type %d", type);
-       }
-
-       label = gtk_label_new(label_text);
-       g_free(label_text);
-       gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), label,
-                          TRUE, TRUE, 0);
-
-       entry = gtk_entry_new();
-       gtk_entry_set_visibility(GTK_ENTRY(entry),
-                                type != ACTION_USER_HIDDEN_STR);
-       gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), entry,
-                          TRUE, TRUE, 0);
-
-       ok_button = gtk_button_new_with_label(_("OK"));
-       gtk_box_pack_end(GTK_BOX(GTK_DIALOG(dialog)->action_area),
-                        ok_button, TRUE, TRUE, 0);
-
-       cancel_button = gtk_button_new_with_label(_("Cancel"));
-       gtk_box_pack_end(GTK_BOX(GTK_DIALOG(dialog)->action_area),
-                        cancel_button, TRUE, TRUE, 0);
-
-       user_dialog.dialog   = dialog;
-       user_dialog.user_str = NULL;
-       user_dialog.entry    = entry;
-
-       gtk_signal_connect(GTK_OBJECT(dialog), "delete_event",
-                          GTK_SIGNAL_FUNC(user_string_dialog_delete_cb),
-                          &user_dialog);
-       gtk_signal_connect(GTK_OBJECT(dialog), "destroy",
-                          GTK_SIGNAL_FUNC(user_string_dialog_destroy_cb),
-                          &user_dialog);
-       gtk_signal_connect(GTK_OBJECT(entry), "activate",
-                          GTK_SIGNAL_FUNC(user_string_dialog_activate_cb),
-                          &user_dialog);
-       gtk_signal_connect(GTK_OBJECT(ok_button), "clicked",
-                          GTK_SIGNAL_FUNC(user_string_dialog_activate_cb),
-                          &user_dialog);
-       gtk_signal_connect_object(GTK_OBJECT(cancel_button), "clicked",
-                                 GTK_SIGNAL_FUNC(gtk_widget_destroy),
-                                 GTK_OBJECT(dialog));
-
-       gtk_widget_grab_focus(entry);
-       gtk_widget_show_all(dialog);
-       gtk_main();
-
-       return user_dialog.user_str;
-}
-
 /*
  * Strings describing action format strings
  * 
 /*
  * Strings describing action format strings
  * 
index 0246b7e294ea65e19cf0b3296826b3e56fe73e22..f20f6230394afa8373a63334e7a2f0205c705cab 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
 /*
  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 1999-2002 Hiroyuki Yamamoto & The Sylpheed Claws Team
+ * Copyright (C) 1999-2003 Hiroyuki Yamamoto & The Sylpheed Claws Team
  *
  * 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
  *
  * 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
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
-#ifndef __ACTIONS_H__
-#define __ACTIONS_H__
+#ifndef __PREFS_ACTIONS_H__
+#define __PREFS_ACTIONS_H__
 
 #include "mainwindow.h"
 
 void prefs_actions_read_config         (void);
 void prefs_actions_write_config                (void);
 
 #include "mainwindow.h"
 
 void prefs_actions_read_config         (void);
 void prefs_actions_write_config                (void);
-void update_mainwin_actions_menu       (GtkItemFactory *ifactory, 
-                                        MainWindow     *mainwin);
-void update_compose_actions_menu       (GtkItemFactory *ifactory, 
-                                        gchar          *branch_path,
-                                        Compose        *compose);
 void prefs_actions_open                        (MainWindow     *mainwin);
 
 void prefs_actions_open                        (MainWindow     *mainwin);
 
-void actions_execute                    (gpointer       data, 
-                                        guint          action_nb,
-                                        GtkWidget      *widget,
-                                        gint           source);
-
-#endif /* __ACTIONS_H__ */
+#endif /* __PREFS_ACTIONS_H__ */
index d4883cb42654952c9bfb0ebe07379dadea70233c..5a2a6baef5bed31743eb974df3618052833b7f00 100644 (file)
@@ -426,14 +426,12 @@ gint send_message_smtp(PrefsAccount *ac_prefs, GSList *to_list, FILE *fp)
 
 static gint send_recv_message(Session *session, const gchar *msg, gpointer data)
 {
 
 static gint send_recv_message(Session *session, const gchar *msg, gpointer data)
 {
-       SMTPSession *smtp_session;
-       SendProgressDialog *dialog; 
        gchar buf[BUFFSIZE];
        gchar buf[BUFFSIZE];
-       gchar *state_str;
+       SMTPSession *smtp_session = SMTP_SESSION(session);
+       SendProgressDialog *dialog = (SendProgressDialog *)data;
+       gchar *state_str = NULL;
 
 
-       dialog = (SendProgressDialog *) data;
-       state_str = NULL;
-       smtp_session = SMTP_SESSION(session);
+       g_return_val_if_fail(dialog != NULL, -1);
 
        switch (smtp_session->state) {
        case SMTP_READY:
 
        switch (smtp_session->state) {
        case SMTP_READY:
@@ -485,27 +483,27 @@ static gint send_recv_message(Session *session, const gchar *msg, gpointer data)
 static gint send_send_data_progressive(Session *session, guint cur_len,
                                       guint total_len, gpointer data)
 {
 static gint send_send_data_progressive(Session *session, guint cur_len,
                                       guint total_len, gpointer data)
 {
-       SendProgressDialog *dialog = (SendProgressDialog *)data;
        gchar buf[BUFFSIZE];
        gchar buf[BUFFSIZE];
+       SendProgressDialog *dialog = (SendProgressDialog *)data;
+
+       g_return_val_if_fail(dialog != NULL, -1);
 
        g_snprintf(buf, sizeof(buf), _("Sending message (%d / %d bytes)"),
                   cur_len, total_len);
        progress_dialog_set_label(dialog->dialog, buf);
        progress_dialog_set_percentage
                (dialog->dialog, (gfloat)cur_len / (gfloat)total_len);
 
        g_snprintf(buf, sizeof(buf), _("Sending message (%d / %d bytes)"),
                   cur_len, total_len);
        progress_dialog_set_label(dialog->dialog, buf);
        progress_dialog_set_percentage
                (dialog->dialog, (gfloat)cur_len / (gfloat)total_len);
+
        return 0;
 }
 
 static gint send_send_data_finished(Session *session, guint len, gpointer data)
 {
        SendProgressDialog *dialog = (SendProgressDialog *)data;
        return 0;
 }
 
 static gint send_send_data_finished(Session *session, guint len, gpointer data)
 {
        SendProgressDialog *dialog = (SendProgressDialog *)data;
-       gchar buf[BUFFSIZE];
-       
-       g_snprintf(buf, sizeof(buf), _("Sending message (%d / %d bytes)"),
-                  len, len);
-       progress_dialog_set_label(dialog->dialog, buf);
-       progress_dialog_set_percentage
-               (dialog->dialog, (gfloat)len / (gfloat)len);
+
+       g_return_val_if_fail(dialog != NULL, -1);
+
+       send_send_data_progressive(session, len, len, dialog);
        return 0;
 }
 
        return 0;
 }
 
index 1299b5ae1b9465dcac5df836c4ce40ba4b5030c3..67a7a76de45c44a035e6b353b597db561ff06a4c 100644 (file)
@@ -50,6 +50,7 @@
 #include "toolbar.h"
 #include "menu.h"
 #include "inc.h"
 #include "toolbar.h"
 #include "menu.h"
 #include "inc.h"
+#include "action.h"
 #include "prefs_actions.h"
 #include "prefs_common.h"
 #include "prefs_toolbar.h"
 #include "prefs_actions.h"
 #include "prefs_common.h"
 #include "prefs_toolbar.h"