From a245ea5c0679ae2b746ea29f03dd60d7b875a881 Mon Sep 17 00:00:00 2001 From: Paul Mangan Date: Thu, 17 Apr 2003 08:18:15 +0000 Subject: [PATCH] sync with 0.8.11cvs27 --- ChangeLog | 35 ++ ChangeLog.claws | 5 + ChangeLog.jp | 34 ++ configure.ac | 2 +- src/Makefile.am | 1 + src/action.c | 1398 +++++++++++++++++++++++++++++++++++++++++++ src/action.h | 59 ++ src/codeconv.c | 45 +- src/codeconv.h | 2 + src/compose.c | 2 +- src/inc.c | 24 +- src/mainwindow.c | 1 + src/prefs_actions.c | 1376 +----------------------------------------- src/prefs_actions.h | 18 +- src/send_message.c | 26 +- src/toolbar.c | 1 + 16 files changed, 1607 insertions(+), 1422 deletions(-) create mode 100644 src/action.c create mode 100644 src/action.h diff --git a/ChangeLog b/ChangeLog index b5c145df4..0c7d1f6a7 100644 --- 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 diff --git a/ChangeLog.claws b/ChangeLog.claws index c0853a2fc..7213d25c5 100644 --- a/ChangeLog.claws +++ b/ChangeLog.claws @@ -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] diff --git a/ChangeLog.jp b/ChangeLog.jp index 9ba714e65..e0e5e2366 100644 --- a/ChangeLog.jp +++ b/ChangeLog.jp @@ -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(): ¥Ø¥Ã¥À¤Î²þ¹Ô¤ò½üµî¤·¡¢ diff --git a/configure.ac b/configure.ac index e132f0128..57cd1a79f 100644 --- a/configure.ac +++ b/configure.ac @@ -11,7 +11,7 @@ MINOR_VERSION=8 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 diff --git a/src/Makefile.am b/src/Makefile.am index a693fcaeb..b4494ed61 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -16,6 +16,7 @@ sylpheed_SOURCES = \ 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 \ diff --git a/src/action.c b/src/action.c new file mode 100644 index 000000000..04a124965 --- /dev/null +++ b/src/action.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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, ""}; + + 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 index 000000000..56f132d87 --- /dev/null +++ b/src/action.h @@ -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 +#include + +#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__ */ diff --git a/src/codeconv.c b/src/codeconv.c index fb0baab9f..19b842811 100644 --- a/src/codeconv.c +++ b/src/codeconv.c @@ -802,6 +802,7 @@ gchar *conv_iconv_strdup(const gchar *inbuf, gint out_size; gint out_left; gint n_conv; + gint len; 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; - in_size = strlen(inbuf) + 1; + in_size = strlen(inbuf); 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; +#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--; + if (out_left == 0) { + EXPAND_BUF(); + } *outbuf_p++ = SUBST_CHAR; out_left--; } else if (EINVAL == errno) { - *outbuf_p = '\0'; 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)); - *outbuf_p = '\0'; 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); @@ -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_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}, @@ -1326,6 +1346,7 @@ gboolean conv_is_multibyte_encoding(CharSet encoding) case C_GB2312: case C_BIG5: case C_UTF_8: + case C_UTF_7: return TRUE; default: return FALSE; diff --git a/src/codeconv.h b/src/codeconv.h index 7633f9fa9..7dfb14f4e 100644 --- a/src/codeconv.h +++ b/src/codeconv.h @@ -33,6 +33,7 @@ typedef enum C_AUTO, C_US_ASCII, C_UTF_8, + C_UTF_7, 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_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" diff --git a/src/compose.c b/src/compose.c index fabcffa09..79931bed8 100644 --- a/src/compose.c +++ b/src/compose.c @@ -84,7 +84,7 @@ #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" diff --git a/src/inc.c b/src/inc.c index eff804fb1..725c11014 100644 --- 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); - IncProgressDialog *inc_dialog = (IncProgressDialog *)inc_session->data; - ProgressDialog *dialog = inc_dialog->dialog; + IncProgressDialog *inc_dialog; + ProgressDialog *dialog; 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; @@ -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) { - 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; } @@ -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); - 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: diff --git a/src/mainwindow.c b/src/mainwindow.c index cadc7d52e..04a5fc0ae 100644 --- a/src/mainwindow.c +++ b/src/mainwindow.c @@ -67,6 +67,7 @@ #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" diff --git a/src/prefs_actions.c b/src/prefs_actions.c index bb025dd80..e42937a8a 100644 --- a/src/prefs_actions.c +++ b/src/prefs_actions.c @@ -26,15 +26,10 @@ #include #include #include -#include #include #include #include #include -#include -#include -#include -#include #include "intl.h" #include "prefs_gtk.h" @@ -46,29 +41,8 @@ #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_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 { @@ -82,54 +56,6 @@ static struct 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); @@ -165,90 +91,6 @@ static void prefs_actions_cancel (GtkWidget *w, 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) @@ -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); @@ -1026,983 +629,6 @@ static void prefs_actions_ok(GtkWidget *widget, gpointer data) 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, ""}; - - 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 * diff --git a/src/prefs_actions.h b/src/prefs_actions.h index 0246b7e29..f20f62303 100644 --- a/src/prefs_actions.h +++ b/src/prefs_actions.h @@ -1,6 +1,6 @@ /* * 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 @@ -17,23 +17,13 @@ * 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); -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 actions_execute (gpointer data, - guint action_nb, - GtkWidget *widget, - gint source); - -#endif /* __ACTIONS_H__ */ +#endif /* __PREFS_ACTIONS_H__ */ diff --git a/src/send_message.c b/src/send_message.c index d4883cb42..5a2a6baef 100644 --- a/src/send_message.c +++ b/src/send_message.c @@ -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) { - SMTPSession *smtp_session; - SendProgressDialog *dialog; 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: @@ -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) { - SendProgressDialog *dialog = (SendProgressDialog *)data; 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); + 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; } diff --git a/src/toolbar.c b/src/toolbar.c index 1299b5ae1..67a7a76de 100644 --- a/src/toolbar.c +++ b/src/toolbar.c @@ -50,6 +50,7 @@ #include "toolbar.h" #include "menu.h" #include "inc.h" +#include "action.h" #include "prefs_actions.h" #include "prefs_common.h" #include "prefs_toolbar.h" -- 2.25.1