/*
* Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 1999-2002 Hiroyuki Yamamoto
+ * 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
#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 "prefs_gtk.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 "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_OPEN_IN = 1 << 6,
- ACTION_HIDE_IN = 1 << 7,
- ACTION_INSERT = 1 << 8,
- ACTION_ERROR = 1 << 9,
-} ActionType;
static struct Actions
{
GtkWidget *actions_clist;
} actions;
-typedef struct _Children Children;
-typedef struct _ChildInfo ChildInfo;
-
-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;
-};
-
/* widget creating functions */
static void prefs_actions_create (MainWindow *mainwin);
static void prefs_actions_set_dialog (void);
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);
-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);
void prefs_actions_open(MainWindow *mainwin)
{
-#if 0
- if (prefs_rc_is_readonly(ACTIONS_RC))
- return;
-#endif
inc_lock();
if (!actions.window)
gtk_signal_connect(GTK_OBJECT(reg_btn), "clicked",
GTK_SIGNAL_FUNC(prefs_actions_register_cb), NULL);
- subst_btn = gtk_button_new_with_label(_(" Replace "));
+ subst_btn = gtk_button_new_with_label(_(" Replace "));
gtk_widget_show(subst_btn);
gtk_box_pack_start(GTK_BOX(btn_hbox), subst_btn, FALSE, TRUE, 0);
gtk_signal_connect(GTK_OBJECT(subst_btn), "clicked",
g_strchomp(buf);
act = strstr(buf, ": ");
if (act && act[2] &&
- get_action_type(&act[2]) != ACTION_ERROR)
+ action_get_type(&act[2]) != ACTION_ERROR)
prefs_common.actions_list =
g_slist_append(prefs_common.actions_list,
g_strdup(buf));
}
}
-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_OPEN_IN;
- p++;
- } else if (p[0] == '*') {
- action_type |= ACTION_HIDE_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;
- 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)
-{
- 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;
- 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);
return -1;
}
- if (get_action_type(entry_text) == ACTION_ERROR) {
+ if (action_get_type(entry_text) == ACTION_ERROR) {
alertpanel_error(_("The command\n%s\nhas a syntax error."),
entry_text);
return -1;
prefs_actions_write_config();
ifactory = gtk_item_factory_from_widget(mainwin->menubar);
- update_mainwin_actions_menu(ifactory, mainwin);
+ action_update_mainwin_menu(ifactory, mainwin);
gtk_widget_hide(actions.window);
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;
- gchar *buf,
- *action;
- MimeView *mimeview = NULL;
- GdkFont *msgfont = NULL;
- guint body_pos = 0;
- GtkWidget *text = NULL;
-
- 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;
-
- 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 */
- }
-
- 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);
- 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_OPEN_IN |
- ACTION_HIDE_IN)) : 0;
- }
- g_free(cmd);
- }
- } else {
- cmd = parse_action_cmd(action, NULL, ctree, mimeview);
- 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_OPEN_IN |
- ACTION_HIDE_IN);
- }
- g_free(cmd);
- } else
- is_ok = FALSE; /* ERR: incorrect command */
- }
-
- 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];
- gint start, end, 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_OPEN_IN |
- ACTION_HIDE_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_OPEN_IN | ACTION_HIDE_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_OPEN_IN | ACTION_HIDE_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) {
- gint 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_OPEN_IN | ACTION_HIDE_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_HIDE_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;
-
- 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);
- c = write(child_info->chld_in, input, strlen(input));
-
- g_free(input);
-
- write(child_info->chld_in, "\n", 2);
-
- gtk_entry_set_text(GTK_ENTRY(children->input_entry), "");
- gtk_widget_set_sensitive(children->input_hbox, TRUE);
- 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);
-}
-
/*
* Strings describing action format strings
*
* When adding new lines, remember to put one string for each line
*/
static gchar *actions_desc_strings[] = {
- N_("Menu name:"), NULL,
+ N_("MENU NAME:"), NULL,
" ", N_("Use / in menu name to make submenus."),
"", NULL,
- N_("Command line:"), NULL,
- N_("* Begin with:"), NULL,
+ N_("COMMAND LINE:"), NULL,
+ N_("Begin with:"), NULL,
" |", N_("to send message body or selection to command"),
" >", N_("to send user provided text to command"),
" *", N_("to send user provided hidden text to command"),
- N_("* End with:"), NULL,
+ N_("End with:"), NULL,
" |", N_("to replace message body or selection with command output"),
" >", N_("to insert command's output without replacing old text"),
" &", N_("to run command asynchronously"),
- N_("* Use:"), NULL,
+ N_("Use:"), NULL,
" %f", N_("for message file name"),
" %F", N_("for the list of the file names of selected messages"),
- " %p", N_("for the selected message MIME part."),
+ " %p", N_("for the selected message MIME part"),
+ " %u", N_("for a user provided argument"),
+ " %h", N_("for a user provided hidden argument"),
+ " %s", N_("for the text selection"),
NULL
};