/*
* Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 1999-2003 Hiroyuki Yamamoto & The Sylpheed Claws Team
+ * Copyright (C) 1999-2006 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
*
* 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "defs.h"
#include <glib.h>
+#include <glib/gi18n.h>
#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>
#ifdef GDK_WINDOWING_X11
-# include <gdk/gdkx.h>
+# include <gdk/gdkx.h>
#endif /* GDK_WINDOWING_X11 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
-#include <sys/wait.h>
+#if HAVE_SYS_WAIT_H
+# include <sys/wait.h>
+#endif
#include <signal.h>
#include <unistd.h>
-#include "intl.h"
#include "utils.h"
#include "gtkutils.h"
#include "manage_window.h"
gint new_out;
GString *output;
+ void (*callback)(void *data);
+ void *data;
};
static void action_update_menu (GtkItemFactory *ifactory,
GSList *msg_list,
GtkWidget *text,
gint body_pos,
- MimeInfo *partinfo);
+ MimeInfo *partinfo,
+ void (*callback)(void *data),
+ void *data);
static gchar *parse_action_cmd (gchar *action,
MsgInfo *msginfo,
static gboolean parse_append_filename(GString *cmd, MsgInfo *msginfo)
{
gchar *filename;
+ gchar *p, *q;
+ gchar escape_ch[] = "\\ ";
g_return_val_if_fail(msginfo, FALSE);
filename = procmsg_get_message_file(msginfo);
- if (filename) {
- g_string_append(cmd, filename);
- g_free(filename);
- } else {
+ if (!filename) {
alertpanel_error(_("Could not get message file %d"),
msginfo->msgnum);
return FALSE;
}
+ p = filename;
+ while ((q = strpbrk(p, "$\"`'\\ \t*?[]&|;<>()!#~")) != NULL) {
+ escape_ch[1] = *q;
+ *q = '\0';
+ g_string_append(cmd, p);
+ g_string_append(cmd, escape_ch);
+ p = q + 1;
+ }
+ g_string_append(cmd, p);
+
+ g_free(filename);
+
return TRUE;
}
action = g_strdup((gchar *)cur->data);
action_p = strstr(action, ": ");
if (action_p && action_p[2] &&
- action_get_type(&action_p[2]) != ACTION_ERROR) {
- action_p[0] = 0x00;
+ (action_get_type(&action_p[2]) != ACTION_ERROR) &&
+ (action[0] != '/')) {
+ action_p[0] = '\0';
menu_path = g_strdup_printf("%s/%s", branch_path,
action);
ifentry.path = menu_path;
return;
}
- execute_actions(action, NULL, compose->text, 0, NULL);
+ execute_actions(action, NULL, compose->text, 0, NULL,
+ compose_action_cb, compose);
}
static void mainwin_actions_execute_cb(MainWindow *mainwin, guint action_nb,
* filtering */
execute_filtering_actions(action, msg_list);
else
- execute_actions(action, msg_list, text, body_pos, partinfo);
+ execute_actions(action, msg_list, text, body_pos, partinfo,
+ NULL, NULL);
}
static gboolean execute_filtering_actions(gchar *action, GSList *msglist)
GSList *action_list, *p;
const gchar *sbegin, *send;
gchar *action_string;
-
+ SummaryView *summaryview = NULL;
+ MainWindow *mainwin = NULL;
+
+ if (mainwindow_get_mainwindow()) {
+ summaryview = mainwindow_get_mainwindow()->summaryview;
+ mainwin = mainwindow_get_mainwindow();
+ }
+
if (NULL == (sbegin = strstr2(action, "%as{")))
return FALSE;
sbegin += sizeof "%as{" - 1;
if (action_list == NULL) return FALSE;
/* apply actions on each message info */
- for (p = msglist; p && p->data; p = g_slist_next(p))
+ for (p = msglist; p && p->data; p = g_slist_next(p)) {
filteringaction_apply_action_list(action_list, (MsgInfo *) p->data);
+ }
+
+ if (summaryview) {
+ summary_lock(summaryview);
+ main_window_cursor_wait(mainwin);
+ gtk_clist_freeze(GTK_CLIST(summaryview->ctree));
+ folder_item_update_freeze();
+ }
+
+ filtering_move_and_copy_msgs(msglist);
+
+ if (summaryview) {
+ folder_item_update_thaw();
+ gtk_clist_thaw(GTK_CLIST(summaryview->ctree));
+ main_window_cursor_normal(mainwin);
+ summary_unlock(summaryview);
+ }
for (p = action_list; p; p = g_slist_next(p))
if (p->data) filteringaction_free(p->data);
g_slist_free(action_list);
static gboolean execute_actions(gchar *action, GSList *msg_list,
GtkWidget *text,
- gint body_pos, MimeInfo *partinfo)
+ gint body_pos, MimeInfo *partinfo,
+ void (*callback)(void *data), void *data)
{
GSList *children_list = NULL;
gint is_ok = TRUE;
GtkTextBuffer *textbuf;
textbuf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text));
- is_selection = gtk_text_buffer_get_selection_bounds(textbuf,
- &start_iter,
- &end_iter);
+ is_selection = gtk_text_buffer_get_selection_bounds
+ (textbuf, &start_iter, &end_iter);
if (!is_selection) {
- gtk_text_buffer_get_start_iter(textbuf, &start_iter);
+ gtk_text_buffer_get_iter_at_offset
+ (textbuf, &start_iter, body_pos);
gtk_text_buffer_get_end_iter(textbuf, &end_iter);
}
- msg_str = gtk_text_buffer_get_text(textbuf,
- &start_iter, &end_iter,
- FALSE);
+ msg_str = gtk_text_buffer_get_text
+ (textbuf, &start_iter, &end_iter, FALSE);
if (is_selection)
- sel_str = g_strdup (msg_str);
+ sel_str = g_strdup(msg_str);
}
if (action_type & ACTION_USER_STR) {
for (cur = children_list; cur; cur = cur->next) {
child_info = (ChildInfo *) cur->data;
+ child_info->callback = callback;
+ child_info->data = data;
child_info->tag_status =
gdk_input_add(child_info->chld_status,
GDK_INPUT_READ,
create_io_dialog(children);
}
-
return is_ok;
}
static ChildInfo *fork_child(gchar *cmd, const gchar *msg_str,
Children *children)
{
+#ifdef G_OS_UNIX
gint chld_in[2], chld_out[2], chld_err[2], chld_status[2];
- gchar *cmdline[4];
+ gchar *cmdline[4], *ret_str;
pid_t pid, gch_pid;
ChildInfo *child_info;
gint sync;
+ gssize by_written = 0, by_read = 0;
sync = !(children->action_type & ACTION_ASYNC);
}
debug_print("Forking child and grandchild.\n");
+ debug_print("Executing: /bin/sh -c %s\n", cmd);
pid = fork();
if (pid == 0) { /* Child */
cmdline[0] = "sh";
cmdline[1] = "-c";
- cmdline[2] = cmd;
- cmdline[3] = 0;
+ ret_str = g_locale_from_utf8(cmd, strlen(cmd),
+ &by_read, &by_written,
+ NULL);
+ if (ret_str && by_written)
+ cmdline[2] = ret_str;
+ else
+ cmdline[2] = cmd;
+ cmdline[3] = NULL;
execvp("/bin/sh", cmdline);
perror("execvp");
+ g_free(ret_str);
_exit(1);
} else if (gch_pid < (pid_t) 0) { /* Fork error */
if (sync)
return child_info;
if ((children->action_type & ACTION_PIPE_IN) && msg_str) {
- write(chld_in[1], msg_str, strlen(msg_str));
+ ret_str = g_locale_from_utf8(msg_str, strlen(msg_str),
+ &by_read, &by_written, NULL);
+ if (ret_str && by_written) {
+ write(chld_in[1], ret_str, strlen(ret_str));
+ g_free(ret_str);
+ } else
+ write(chld_in[1], msg_str, strlen(msg_str));
if (!(children->action_type &
(ACTION_USER_IN | ACTION_USER_HIDDEN_IN)))
close(chld_in[1]);
}
return child_info;
+#else
+ return NULL;
+#endif /* G_OS_UNIX */
}
static void kill_children_cb(GtkWidget *widget, gpointer data)
{
+#ifdef G_OS_UNIX
GSList *cur;
Children *children = (Children *) data;
ChildInfo *child_info;
if (child_info->pid && kill(-child_info->pid, SIGTERM) < 0)
perror("kill");
}
+#endif /* G_OS_UNIX */
}
static gint wait_for_children(Children *children)
static void free_children(Children *children)
{
ChildInfo *child_info;
+ void (*callback)(void *data) = NULL;
+ void *data = NULL;
debug_print("Freeing children data %p\n", children);
g_free(child_info->cmd);
g_string_free(child_info->output, TRUE);
children->list = g_slist_remove(children->list, child_info);
+ callback = child_info->callback;
+ data = child_info->data;
g_free(child_info);
}
+
+ if (callback)
+ callback(data);
+
g_free(children);
}
debug_print("Updating actions input/output dialog.\n");
if (children->progress_bar) {
- gtk_progress_configure(GTK_PROGRESS(children->progress_bar),
- children->initial_nb -children->nb,
- 0.0, children->initial_nb);
- }
+ gchar *text;
+
+ gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(children->progress_bar),
+ (gdouble) (children->initial_nb - children->nb) /
+ (gdouble) children->initial_nb);
+ text = g_strdup_printf("%s %d/%d", _("Completed"),
+ children->initial_nb - children->nb,
+ children->initial_nb);
+ gtk_progress_bar_set_text(GTK_PROGRESS_BAR(children->progress_bar), text);
+ g_free(text);
+ }
if (!children->nb) {
gtk_widget_set_sensitive(children->abort_btn, FALSE);
if (children->output) {
GtkWidget *text = children->text;
- gchar *caption;
- ChildInfo *child_info;
GtkTextBuffer *textbuf;
GtkTextIter iter, start_iter, end_iter;
+ gchar *caption;
+ ChildInfo *child_info;
gtk_widget_show(children->scrolledwin);
textbuf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text));
- gtk_text_buffer_get_start_iter(textbuf, &start_iter);
- gtk_text_buffer_get_end_iter(textbuf, &end_iter);
+ gtk_text_buffer_get_bounds(textbuf, &start_iter, &end_iter);
gtk_text_buffer_delete(textbuf, &start_iter, &end_iter);
- gtk_text_buffer_get_start_iter(textbuf, &start_iter);
- iter = start_iter;
+ gtk_text_buffer_get_start_iter(textbuf, &iter);
+
for (cur = children->list; cur; cur = cur->next) {
child_info = (ChildInfo *)cur->data;
if (child_info->pid)
(_("--- Ended: %s\n"),
child_info->cmd);
- gtk_text_buffer_insert(textbuf, &iter,
- caption, -1);
+ gtk_text_buffer_insert(textbuf, &iter, caption, -1);
gtk_text_buffer_insert(textbuf, &iter,
child_info->output->str, -1);
g_free(caption);
GtkWidget *progress_bar = NULL;
GtkWidget *abort_button;
GtkWidget *close_button;
- PangoFontDescription *text_font;
debug_print("Creating action IO dialog\n");
scrolledwin = gtk_scrolled_window_new(NULL, NULL);
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwin),
- GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
+ GTK_POLICY_AUTOMATIC,
+ GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolledwin),
+ GTK_SHADOW_IN);
gtk_box_pack_start(GTK_BOX(vbox), scrolledwin, TRUE, TRUE, 0);
- gtk_widget_set_size_request(scrolledwin, 480, 200);
+ gtk_widget_set_size_request(scrolledwin, 560, 200);
gtk_widget_hide(scrolledwin);
text = gtk_text_view_new();
+
if (prefs_common.textfont) {
- if (NULL != (text_font = pango_font_description_from_string
- (prefs_common.textfont))) {
- gtk_widget_modify_font(text, text_font);
- pango_font_description_free(text_font);
- }
- }
+ PangoFontDescription *font_desc;
+ font_desc = pango_font_description_from_string
+ (prefs_common.textfont);
+ if (font_desc) {
+ gtk_widget_modify_font(text, font_desc);
+ pango_font_description_free(font_desc);
+ }
+ }
+
gtk_text_view_set_editable(GTK_TEXT_VIEW(text), FALSE);
+ gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(text), GTK_WRAP_WORD);
+ gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text), 6);
+ gtk_text_view_set_right_margin(GTK_TEXT_VIEW(text), 6);
gtk_container_add(GTK_CONTAINER(scrolledwin), text);
gtk_widget_show(text);
gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE);
gtk_widget_show(entry);
- send_button = gtk_button_new_with_label(_(" Send "));
+ send_button = gtk_button_new_from_stock(GTK_STOCK_EXECUTE);
g_signal_connect(G_OBJECT(send_button), "clicked",
G_CALLBACK(send_input), children);
gtk_box_pack_start(GTK_BOX(input_hbox), send_button, FALSE,
}
if (children->initial_nb > 1) {
+ gchar * text;
+
progress_bar = gtk_progress_bar_new();
- gtk_progress_bar_set_bar_style(GTK_PROGRESS_BAR(progress_bar),
- GTK_PROGRESS_CONTINUOUS);
gtk_progress_bar_set_orientation(GTK_PROGRESS_BAR(progress_bar),
GTK_PROGRESS_LEFT_TO_RIGHT);
- gtk_progress_set_activity_mode(GTK_PROGRESS(progress_bar),
- FALSE);
- gtk_progress_set_format_string(GTK_PROGRESS(progress_bar),
- _("Completed %v/%u"));
- gtk_progress_set_show_text(GTK_PROGRESS(progress_bar), TRUE);
- gtk_progress_configure(GTK_PROGRESS(progress_bar),
- children->initial_nb -children->nb,
- 0.0, children->initial_nb);
-
+ text = g_strdup_printf("%s 0/%d\n", _("Completed"),
+ children->initial_nb);
+ gtk_progress_bar_set_text(GTK_PROGRESS_BAR(progress_bar),
+ text);
+ g_free(text);
gtk_box_pack_start(GTK_BOX(vbox), progress_bar, FALSE, FALSE, 0);
gtk_widget_show(progress_bar);
}
- gtkut_button_set_create(&hbox, &abort_button, _("Abort"),
- &close_button, _("Close"), NULL, NULL);
+ gtkut_stock_button_set_create(&hbox, &abort_button, GTK_STOCK_STOP,
+ &close_button, GTK_STOCK_CLOSE, NULL, NULL);
g_signal_connect(G_OBJECT(abort_button), "clicked",
G_CALLBACK(kill_children_cb), children);
g_signal_connect(G_OBJECT(close_button), "clicked",
c = read(source, &buf, 1);
debug_print("Child returned %c\n", buf);
+#ifdef G_OS_UNIX
waitpid(-child_info->pid, NULL, 0);
+#endif
childinfo_close_pipes(child_info);
child_info->pid = 0;
{
Children *children = (Children *)data;
ChildInfo *child_info = (ChildInfo *)children->list->data;
- gchar *input;
+ gchar *input, *ret_str;
gint c, count, len;
+ gssize by_read = 0, by_written = 0;
debug_print("Sending input to grand child.\n");
if (!(cond && GDK_INPUT_WRITE))
input = gtk_editable_get_chars(GTK_EDITABLE(children->input_entry),
0, -1);
+ ret_str = g_locale_from_utf8(input, strlen(input), &by_read,
+ &by_written, NULL);
+ if (ret_str && by_written) {
+ g_free(input);
+ input = ret_str;
+ }
+
len = strlen(input);
count = 0;
static void catch_output(gpointer data, gint source, GdkInputCondition cond)
{
ChildInfo *child_info = (ChildInfo *)data;
- gint c, i;
+ gint c;
gchar buf[BUFFSIZE];
debug_print("Catching grand child's output.\n");
if (child_info->children->action_type &
(ACTION_PIPE_OUT | ACTION_INSERT)
&& source == child_info->chld_out) {
- GtkTextView *text = GTK_TEXT_VIEW(child_info->children->msg_text);
- GtkTextBuffer *textbuf = gtk_text_view_get_buffer(text);
- GtkTextIter iter1, iter2;
- GtkTextMark *mark;
-
- mark = gtk_text_buffer_get_insert(textbuf);
- gtk_text_buffer_get_iter_at_mark(textbuf, &iter1, mark);
- gtk_text_buffer_get_iter_at_mark(textbuf, &iter2, mark);
+ GtkTextView *text =
+ GTK_TEXT_VIEW(child_info->children->msg_text);
+ GtkTextBuffer *textbuf = gtk_text_view_get_buffer(text);
+ GtkTextIter iter;
+ GtkTextMark *mark;
+ gint ins_pos;
+
+ mark = gtk_text_buffer_get_insert(textbuf);
+ gtk_text_buffer_get_iter_at_mark(textbuf, &iter, mark);
+ ins_pos = gtk_text_iter_get_offset(&iter);
while (TRUE) {
+ gsize bytes_read = 0, bytes_written = 0;
+ gchar *ret_str;
+
c = read(source, buf, sizeof(buf) - 1);
if (c == 0)
break;
- gtk_text_buffer_insert(textbuf, &iter2, buf, c);
+
+ ret_str = g_locale_to_utf8
+ (buf, c, &bytes_read, &bytes_written, NULL);
+ if (ret_str && bytes_written > 0) {
+ gtk_text_buffer_insert
+ (textbuf, &iter, ret_str,
+ bytes_written);
+ g_free(ret_str);
+ } else
+ gtk_text_buffer_insert(textbuf, &iter, buf, c);
}
- if (child_info->children->is_selection) {
- gtk_text_buffer_place_cursor(textbuf, &iter1);
- gtk_text_buffer_move_mark_by_name
- (textbuf, "selection_bound", &iter2);
+
+ if (child_info->children->is_selection) {
+ GtkTextIter ins;
+
+ gtk_text_buffer_get_iter_at_offset
+ (textbuf, &ins, ins_pos);
+ gtk_text_buffer_select_range(textbuf, &ins, &iter);
}
} 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)
+ if (c > 0) {
+ gsize bytes_read = 0, bytes_written = 0;
+ gchar *ret_str;
+
+ ret_str = g_locale_to_utf8
+ (buf, c, &bytes_read, &bytes_written, NULL);
+ if (ret_str && bytes_written > 0) {
+ g_string_append_len
+ (child_info->output, ret_str,
+ bytes_written);
+ g_free(ret_str);
+ } else
+ g_string_append_len(child_info->output, buf, c);
+
child_info->new_out = TRUE;
+ }
}
if (c == 0) {
if (source == child_info->chld_out) {
case ACTION_USER_HIDDEN_STR:
message = g_strdup_printf
(_("Enter the argument for the following action:\n"
- "(`%%h' will be replaced with the argument)\n"
+ "('%%h' will be replaced with the argument)\n"
" %s"),
action);
user_str = input_dialog_with_invisible
case ACTION_USER_STR:
message = g_strdup_printf
(_("Enter the argument for the following action:\n"
- "(`%%u' will be replaced with the argument)\n"
+ "('%%u' will be replaced with the argument)\n"
" %s"),
action);
user_str = input_dialog