2005-05-27 [paul] 1.9.11cvs16
authorPaul Mangan <paul@claws-mail.org>
Fri, 27 May 2005 07:24:34 +0000 (07:24 +0000)
committerPaul Mangan <paul@claws-mail.org>
Fri, 27 May 2005 07:24:34 +0000 (07:24 +0000)
sync with main:

* src/main.c
app_will_exit(): cleanup tmp directory when exit
* src/message_search.c
improved the interface and made code cleanup.
removed Clear button
* src/send_message.c
send_message_local(): use GSpawn, and detect errors
* src/summary_search.c
improved the interface and made code cleanup
* src/textview.c
textview_write_link(): also skip non-ascii space
 at the head of link strings (phishing check
 didn't work at the case)
* src/common/utils.c
get_command_output(): use g_spawn_command_line_sync()
instead of popen()

ChangeLog-gtk2.claws
PATCHSETS
configure.ac
src/common/utils.c
src/main.c
src/message_search.c
src/send_message.c
src/summary_search.c
src/textview.c

index c72b1aa..9edc878 100644 (file)
@@ -1,3 +1,24 @@
+2005-05-27 [paul]      1.9.11cvs16
+
+       sync with main:
+
+       * src/main.c
+               app_will_exit(): cleanup tmp directory when exit
+       * src/message_search.c
+               improved the interface and made code cleanup.
+               removed Clear button
+       * src/send_message.c
+               send_message_local(): use GSpawn, and detect errors
+       * src/summary_search.c
+               improved the interface and made code cleanup
+       * src/textview.c
+               textview_write_link(): also skip non-ascii space
+                at the head of link strings (phishing check
+                didn't work at the case)
+       * src/common/utils.c
+               get_command_output(): use g_spawn_command_line_sync()
+               instead of popen()
+
 2005-05-26 [colin]     1.9.11cvs15
 
        * src/folder.c
index 585e190..a3c5702 100644 (file)
--- a/PATCHSETS
+++ b/PATCHSETS
 ( cvs diff -u -r 1.1.2.6 -r 1.1.2.7 src/plugins/pgpmime/passphrase.c; ) > 1.9.11cvs13.patchset
 ( cvs diff -u -r 1.6.2.5 -r 1.6.2.6 src/common/nntp.c; ) > 1.9.11cvs14.patchset
 ( cvs diff -u -r 1.213.2.27 -r 1.213.2.28 src/folder.c; ) > 1.9.11cvs15.patchset
+( cvs diff -u -r 1.115.2.33 -r 1.115.2.34 src/main.c; cvs diff -u -r 1.3.12.8 -r 1.3.12.9 src/message_search.c; cvs diff -u -r 1.17.2.10 -r 1.17.2.11 src/send_message.c; cvs diff -u -r 1.15.2.14 -r 1.15.2.15 src/summary_search.c; cvs diff -u -r 1.96.2.54 -r 1.96.2.55 src/textview.c; cvs diff -u -r 1.36.2.29 -r 1.36.2.30 src/common/utils.c; ) > 1.9.11cvs16.patchset
index 3a61453..d23d174 100644 (file)
@@ -11,7 +11,7 @@ MINOR_VERSION=9
 MICRO_VERSION=11
 INTERFACE_AGE=0
 BINARY_AGE=0
-EXTRA_VERSION=15
+EXTRA_VERSION=16
 EXTRA_RELEASE=
 EXTRA_GTK2_VERSION=
 
index 30f0fd5..369fe16 100644 (file)
@@ -3190,39 +3190,18 @@ gint execute_command_line(const gchar *cmdline, gboolean async)
 
 gchar *get_command_output(const gchar *cmdline)
 {
-       gchar buf[BUFFSIZE];
-       FILE *fp;
-       GString *str;
-       gchar *ret;
+       gchar *child_stdout;
+       gint status;
 
        g_return_val_if_fail(cmdline != NULL, NULL);
 
-       if ((fp = popen(cmdline, "r")) == NULL) {
-               FILE_OP_ERROR(cmdline, "popen");
+       if (g_spawn_command_line_sync(cmdline, &child_stdout, NULL, &status,
+                                     NULL) == FALSE) {
+               g_warning("Can't execute command: %s\n", cmdline);
                return NULL;
        }
 
-       str = g_string_new("");
-
-       while (fgets(buf, sizeof(buf), fp) != NULL)
-               g_string_append(str, buf);
-
-       pclose(fp);
-
-       ret = str->str;
-       g_string_free(str, FALSE);
-
-       if (!g_utf8_validate(ret, -1, NULL)) {
-               const gchar *src_codeset, *dest_codeset;
-               gchar *tmp = NULL;
-               src_codeset = conv_get_locale_charset_str();
-               dest_codeset = CS_UTF_8;
-               tmp = conv_codeset_strdup(ret, src_codeset, dest_codeset);
-               g_free(ret);
-               ret = tmp;
-       }
-       
-       return ret;
+       return child_stdout;
 }
 
 static gint is_unchanged_uri_char(char c)
index 743f980..7c6378e 100644 (file)
@@ -484,6 +484,7 @@ static void exit_sylpheed(MainWindow *mainwin)
        g_free(filename);
 
        /* delete temporary files */
+       remove_all_files(get_tmp_dir());
        remove_all_files(get_mime_tmp_dir());
 
        close_log_file();
index bfe370c..70776d5 100644 (file)
 #include "manage_window.h"
 #include "alertpanel.h"
 
-static GtkWidget *window;
-static GtkWidget *body_entry;
-static GtkWidget *case_checkbtn;
-static GtkWidget *backward_checkbtn;
-static GtkWidget *search_btn;
-static GtkWidget *clear_btn;
-static GtkWidget *close_btn;
-
-static void message_search_create(MessageView *summaryview);
-static void message_search_execute(GtkButton *button, gpointer data);
-static void message_search_clear(GtkButton *button, gpointer data);
-static void body_activated(void);
-static gboolean key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data);
+static struct MessageSearchWindow {
+       GtkWidget *window;
+       GtkWidget *body_entry;
+       GtkWidget *case_checkbtn;
+       GtkWidget *prev_btn;
+       GtkWidget *next_btn;
+       GtkWidget *close_btn;
+
+       MessageView *messageview;
+} search_window;
+
+static void message_search_create      (void);
+static void message_search_execute     (gboolean        backward);
+
+static void message_search_prev_clicked        (GtkButton      *button,
+                                        gpointer        data);
+static void message_search_next_clicked        (GtkButton      *button,
+                                        gpointer        data);
+static void body_activated             (void);
+static gboolean key_pressed            (GtkWidget      *widget,
+                                        GdkEventKey    *event,
+                                        gpointer        data);
 
 void message_search(MessageView *messageview)
 {
-       if (!window)
-               message_search_create(messageview);
+       if (!search_window.window)
+               message_search_create();
        else
-               gtk_widget_hide(window);
+               gtk_widget_hide(search_window.window);
 
-       gtk_widget_grab_focus(search_btn);
-       gtk_widget_grab_focus(body_entry);
-       gtk_widget_show(window);
+       search_window.messageview = messageview;
+
+       gtk_widget_grab_focus(search_window.next_btn);
+       gtk_widget_grab_focus(search_window.body_entry);
+       gtk_widget_show(search_window.window);
 }
 
-static void message_search_create(MessageView *messageview)
+static void message_search_create(void)
 {
+       GtkWidget *window;
+
        GtkWidget *vbox1;
        GtkWidget *hbox1;
        GtkWidget *body_label;
+       GtkWidget *body_entry;
+
        GtkWidget *checkbtn_hbox;
+       GtkWidget *case_checkbtn;
+
        GtkWidget *confirm_area;
+       GtkWidget *prev_btn;
+       GtkWidget *next_btn;
+       GtkWidget *close_btn;
 
        window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
        gtk_window_set_title (GTK_WINDOW (window),
@@ -111,7 +131,7 @@ static void message_search_create(MessageView *messageview)
        gtk_widget_show (body_entry);
        gtk_box_pack_start (GTK_BOX (hbox1), body_entry, TRUE, TRUE, 0);
        g_signal_connect(G_OBJECT(body_entry), "activate",
-                        G_CALLBACK(body_activated), messageview);
+                        G_CALLBACK(body_activated), NULL);
 
        checkbtn_hbox = gtk_hbox_new (FALSE, 8);
        gtk_widget_show (checkbtn_hbox);
@@ -122,50 +142,45 @@ static void message_search_create(MessageView *messageview)
        gtk_widget_show (case_checkbtn);
        gtk_box_pack_start (GTK_BOX (checkbtn_hbox), case_checkbtn,
                            FALSE, FALSE, 0);
-       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(case_checkbtn), FALSE);
-
-       backward_checkbtn =
-               gtk_check_button_new_with_label (_("Backward search"));
-       gtk_widget_show (backward_checkbtn);
-       gtk_box_pack_start (GTK_BOX (checkbtn_hbox), backward_checkbtn,
-                           FALSE, FALSE, 0);
 
        gtkut_stock_button_set_create(&confirm_area,
-                                     &search_btn, GTK_STOCK_FIND,
-                                     &clear_btn, GTK_STOCK_CLEAR,
+                                     &prev_btn, GTK_STOCK_GO_BACK,
+                                     &next_btn, GTK_STOCK_GO_FORWARD,
                                      &close_btn, GTK_STOCK_CLOSE);
        gtk_widget_show (confirm_area);
        gtk_box_pack_start (GTK_BOX (vbox1), confirm_area, FALSE, FALSE, 0);
-       gtk_widget_grab_default(search_btn);
-
-       g_signal_connect(G_OBJECT(search_btn), "clicked",
-                        G_CALLBACK(message_search_execute),
-                        messageview);
-       g_signal_connect(G_OBJECT(clear_btn), "clicked",
-                        G_CALLBACK(message_search_clear),
-                        messageview);
+       gtk_widget_grab_default(next_btn);
+
+       g_signal_connect(G_OBJECT(prev_btn), "clicked",
+                        G_CALLBACK(message_search_prev_clicked), NULL);
+       g_signal_connect(G_OBJECT(next_btn), "clicked",
+                        G_CALLBACK(message_search_next_clicked), NULL);
        g_signal_connect_closure
                (G_OBJECT(close_btn), "clicked",
                 g_cclosure_new_swap(G_CALLBACK(gtk_widget_hide),
                                     window, NULL),
                 FALSE);
+
+       search_window.window = window;
+       search_window.body_entry = body_entry;
+       search_window.case_checkbtn = case_checkbtn;
+       search_window.prev_btn = prev_btn;
+       search_window.next_btn = next_btn;
+       search_window.close_btn = close_btn;
 }
 
-static void message_search_execute(GtkButton *button, gpointer data)
+static void message_search_execute(gboolean backward)
 {
-       MessageView *messageview = data;
+       MessageView *messageview = search_window.messageview;
        gboolean case_sens;
-       gboolean backward;
        gboolean all_searched = FALSE;
        const gchar *body_str;
 
-       body_str = gtk_entry_get_text(GTK_ENTRY(body_entry));
+       body_str = gtk_entry_get_text(GTK_ENTRY(search_window.body_entry));
        if (*body_str == '\0') return;
 
        case_sens = gtk_toggle_button_get_active
-               (GTK_TOGGLE_BUTTON(case_checkbtn));
-       backward = gtk_toggle_button_get_active
-               (GTK_TOGGLE_BUTTON(backward_checkbtn));
+               (GTK_TOGGLE_BUTTON(search_window.case_checkbtn));
 
        for (;;) {
                gchar *str;
@@ -182,8 +197,11 @@ static void message_search_execute(GtkButton *button, gpointer data)
                }
 
                if (all_searched) {
-                       alertpanel_notice
-                               (_("Search string not found."));
+                       alertpanel_with_type
+                               (_("Search failed"),
+                                _("Search string not found."),
+                                NULL, NULL, NULL, NULL,
+                                ALERT_WARNING);
                        break;
                }
 
@@ -199,7 +217,8 @@ static void message_search_execute(GtkButton *button, gpointer data)
                val = alertpanel(_("Search finished"), str,
                                 GTK_STOCK_YES, GTK_STOCK_NO, NULL);
                if (G_ALERTDEFAULT == val) {
-                       manage_window_focus_in(window, NULL, NULL);
+                       manage_window_focus_in(search_window.window,
+                                              NULL, NULL);
                        messageview_set_position(messageview,
                                                 backward ? -1 : 0);
                } else
@@ -207,19 +226,25 @@ static void message_search_execute(GtkButton *button, gpointer data)
        }
 }
 
-static void message_search_clear(GtkButton *button, gpointer data)
+static void message_search_prev_clicked(GtkButton *button, gpointer data)
+{
+       message_search_execute(TRUE);
+}
+
+static void message_search_next_clicked(GtkButton *button, gpointer data)
 {
-       gtk_editable_delete_text(GTK_EDITABLE(body_entry),    0, -1);
+       message_search_execute(FALSE);
 }
 
 static void body_activated(void)
 {
-       gtk_button_clicked(GTK_BUTTON(search_btn));
+       gtk_button_clicked(GTK_BUTTON(search_window.next_btn));
 }
 
-static gboolean key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
+static gboolean key_pressed(GtkWidget *widget, GdkEventKey *event,
+                           gpointer data)
 {
        if (event && event->keyval == GDK_Escape)
-               gtk_widget_hide(window);
+               gtk_widget_hide(search_window.window);
        return FALSE;
 }
index 353ab70..512d024 100644 (file)
@@ -46,6 +46,7 @@
 #include "inputdialog.h"
 #include "alertpanel.h"
 #include "manage_window.h"
+#include "socket.h"
 #include "utils.h"
 #include "gtkutils.h"
 #include "inc.h"
@@ -117,39 +118,54 @@ enum
 
 gint send_message_local(const gchar *command, FILE *fp)
 {
-       FILE *pipefp;
+       gchar **argv;
+       GPid pid;
+       gint child_stdin;
        gchar buf[BUFFSIZE];
-       int r;
-       sigset_t osig, mask;
+       gboolean err = FALSE;
 
        g_return_val_if_fail(command != NULL, -1);
        g_return_val_if_fail(fp != NULL, -1);
 
-       pipefp = popen(command, "w");
-       if (!pipefp) {
-               g_warning("Can't execute external command: %s\n", command);
+       log_message(_("Sending message using command: %s\n"), command);
+
+       argv = strsplit_with_quote(command, " ", 0);
+
+       if (g_spawn_async_with_pipes(NULL, argv, NULL, 0, NULL, NULL, &pid,
+                                    &child_stdin, NULL, NULL, NULL) == FALSE) {
+               g_snprintf(buf, sizeof(buf),
+                          _("Can't execute command: %s"), command);
+               log_warning("%s\n", buf);
+               alertpanel_error("%s", buf);
+               g_strfreev(argv);
                return -1;
        }
+       g_strfreev(argv);
 
        while (fgets(buf, sizeof(buf), fp) != NULL) {
                strretchomp(buf);
-               fputs(buf, pipefp);
-               fputc('\n', pipefp);
+               if (buf[0] == '.' && buf[1] == '\0') {
+                       if (fd_write_all(child_stdin, ".", 1) < 0) {
+                               err = TRUE;
+                               break;
+                       }
+               }
+               if (fd_write_all(child_stdin, buf, strlen(buf)) < 0 ||
+                   fd_write_all(child_stdin, "\n", 1) < 0) {
+                       err = TRUE;
+                       break;
+               }
        }
 
-       /* we need to block SIGCHLD, otherwise pspell's handler will wait()
-        * the pipecommand away and pclose will return -1 because of its
-        * failed wait4().
-        */
-       sigemptyset(&mask);
-       sigaddset(&mask, SIGCHLD);
-       sigprocmask(SIG_BLOCK, &mask, &osig);
-       
-       r = pclose(pipefp);
+       fd_close(child_stdin);
+       g_spawn_close_pid(pid);
 
-       sigprocmask(SIG_SETMASK, &osig, NULL);
-       if (r != 0) {
-               g_warning("external command `%s' failed with code `%i'\n", command, r);
+       if (err) {
+               g_snprintf(buf, sizeof(buf),
+                          _("Error occurred while executing command: %s"),
+                          command);
+               log_warning("%s\n", buf);
+               alertpanel_error("%s", buf);
                return -1;
        }
 
index 31573b0..eacead6 100644 (file)
 #include "manage_window.h"
 #include "alertpanel.h"
 
-static GtkWidget *window;
-static GtkWidget *bool_optmenu;
-static GtkWidget *from_entry;
-static GtkWidget *to_entry;
-static GtkWidget *subject_entry;
-static GtkWidget *body_entry;
-static GtkWidget *case_checkbtn;
-static GtkWidget *backward_checkbtn;
-static GtkWidget *all_checkbtn;
-static GtkWidget *and_checkbtn;
-static GtkWidget *search_btn;
-static GtkWidget *clear_btn;
-static GtkWidget *close_btn;
-
-static void summary_search_create(SummaryView *summaryview);
-static void summary_search_execute(GtkButton *button, gpointer data);
-static void summary_search_clear(GtkButton *button, gpointer data);
-static void from_activated(void);
-static void to_activated(void);
-static void subject_activated(void);
-static void body_activated(void);
-static gboolean all_clicked(GtkButton *button);
-static gboolean key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data);
+static struct SummarySearchWindow {
+       GtkWidget *window;
+
+       GtkWidget *bool_optmenu;
+
+       GtkWidget *from_entry;
+       GtkWidget *to_entry;
+       GtkWidget *subject_entry;
+       GtkWidget *body_entry;
+
+       GtkWidget *case_checkbtn;
+
+       GtkWidget *clear_btn;
+       GtkWidget *all_btn;
+       GtkWidget *prev_btn;
+       GtkWidget *next_btn;
+       GtkWidget *close_btn;
+
+       SummaryView *summaryview;
+} search_window;
+
+static void summary_search_create      (void);
+
+static void summary_search_execute     (gboolean        backward,
+                                        gboolean        search_all);
+
+static void summary_search_clear       (GtkButton      *button,
+                                        gpointer        data);
+static void summary_search_prev_clicked        (GtkButton      *button,
+                                        gpointer        data);
+static void summary_search_next_clicked        (GtkButton      *button,
+                                        gpointer        data);
+static void summary_search_all_clicked (GtkButton      *button,
+                                        gpointer        data);
+
+static void from_activated             (void);
+static void to_activated               (void);
+static void subject_activated          (void);
+static void body_activated             (void);
+
+static gboolean key_pressed            (GtkWidget      *widget,
+                                        GdkEventKey    *event,
+                                        gpointer        data);
+
 
 void summary_search(SummaryView *summaryview)
 {
-       if (!window)
-               summary_search_create(summaryview);
+       if (!search_window.window)
+               summary_search_create();
        else
-               gtk_widget_hide(window);
+               gtk_widget_hide(search_window.window);
+
+       search_window.summaryview = summaryview;
 
-       gtk_widget_grab_focus(search_btn);
-       gtk_widget_grab_focus(subject_entry);
-       gtk_widget_show(window);
+       gtk_widget_grab_focus(search_window.next_btn);
+       gtk_widget_grab_focus(search_window.subject_entry);
+       gtk_widget_show(search_window.window);
 }
 
-static void summary_search_create(SummaryView *summaryview)
+static void summary_search_create(void)
 {
+       GtkWidget *window;
        GtkWidget *vbox1;
        GtkWidget *bool_hbox;
+       GtkWidget *bool_optmenu;
        GtkWidget *bool_menu;
        GtkWidget *menuitem;
+       GtkWidget *clear_btn;
+
        GtkWidget *table1;
        GtkWidget *from_label;
+       GtkWidget *from_entry;
        GtkWidget *to_label;
+       GtkWidget *to_entry;
        GtkWidget *subject_label;
+       GtkWidget *subject_entry;
        GtkWidget *body_label;
+       GtkWidget *body_entry;
+
        GtkWidget *checkbtn_hbox;
-       GtkWidget *confirm_area;
+       GtkWidget *case_checkbtn;
 
-       window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
-       gtk_window_set_title (GTK_WINDOW (window), _("Search messages"));
-       gtk_widget_set_size_request (window, 450, -1);
-       gtk_window_set_resizable(GTK_WINDOW(window), TRUE);
-       gtk_container_set_border_width (GTK_CONTAINER (window), 8);
+       GtkWidget *confirm_area;
+       GtkWidget *all_btn;
+       GtkWidget *prev_btn;
+       GtkWidget *next_btn;
+       GtkWidget *close_btn;
+
+       window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+       gtk_window_set_title(GTK_WINDOW (window), _("Search messages"));
+       gtk_widget_set_size_request(window, 450, -1);
+       gtk_window_set_policy(GTK_WINDOW(window), FALSE, TRUE, TRUE);
+       gtk_container_set_border_width(GTK_CONTAINER (window), 8);
        g_signal_connect(G_OBJECT(window), "delete_event",
                         G_CALLBACK(gtk_widget_hide_on_delete), NULL);
        g_signal_connect(G_OBJECT(window), "key_press_event",
@@ -131,6 +169,10 @@ static void summary_search_create(SummaryView *summaryview)
        MENUITEM_ADD(bool_menu, menuitem, _("Match all of the following"), 1);
        gtk_option_menu_set_menu(GTK_OPTION_MENU(bool_optmenu), bool_menu);
 
+       clear_btn = gtk_button_new_from_stock(GTK_STOCK_CLEAR);
+       gtk_widget_show(clear_btn);
+       gtk_box_pack_end(GTK_BOX(bool_hbox), clear_btn, FALSE, FALSE, 0);
+
        table1 = gtk_table_new (4, 3, FALSE);
        gtk_widget_show (table1);
        gtk_box_pack_start (GTK_BOX (vbox1), table1, TRUE, TRUE, 0);
@@ -143,28 +185,28 @@ static void summary_search_create(SummaryView *summaryview)
        gtk_table_attach (GTK_TABLE (table1), from_entry, 1, 3, 0, 1,
                          GTK_EXPAND|GTK_FILL, 0, 0, 0);
        g_signal_connect(G_OBJECT(from_entry), "activate",
-                        G_CALLBACK(from_activated), summaryview);
+                        G_CALLBACK(from_activated), NULL);
 
        to_entry = gtk_entry_new ();
        gtk_widget_show (to_entry);
        gtk_table_attach (GTK_TABLE (table1), to_entry, 1, 3, 1, 2,
                          GTK_EXPAND|GTK_FILL, 0, 0, 0);
        g_signal_connect(G_OBJECT(to_entry), "activate",
-                        G_CALLBACK(to_activated), summaryview);
+                        G_CALLBACK(to_activated), NULL);
 
        subject_entry = gtk_entry_new ();
        gtk_widget_show (subject_entry);
        gtk_table_attach (GTK_TABLE (table1), subject_entry, 1, 3, 2, 3,
                          GTK_EXPAND|GTK_FILL, 0, 0, 0);
        g_signal_connect(G_OBJECT(subject_entry), "activate",
-                        G_CALLBACK(subject_activated), summaryview);
+                        G_CALLBACK(subject_activated), NULL);
 
        body_entry = gtk_entry_new ();
        gtk_widget_show (body_entry);
        gtk_table_attach (GTK_TABLE (table1), body_entry, 1, 3, 3, 4,
                          GTK_EXPAND|GTK_FILL, 0, 0, 0);
        g_signal_connect(G_OBJECT(body_entry), "activate",
-                        G_CALLBACK(body_activated), summaryview);
+                        G_CALLBACK(body_activated), NULL);
 
        from_label = gtk_label_new (_("From:"));
        gtk_widget_show (from_label);
@@ -200,84 +242,100 @@ static void summary_search_create(SummaryView *summaryview)
        gtk_container_set_border_width (GTK_CONTAINER (checkbtn_hbox), 8);
 
        case_checkbtn = gtk_check_button_new_with_label (_("Case sensitive"));
-       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(case_checkbtn), FALSE);
        gtk_widget_show (case_checkbtn);
        gtk_box_pack_start (GTK_BOX (checkbtn_hbox), case_checkbtn,
                            FALSE, FALSE, 0);
 
-       backward_checkbtn =
-               gtk_check_button_new_with_label (_("Backward search"));
-       gtk_widget_show (backward_checkbtn);
-       gtk_box_pack_start (GTK_BOX (checkbtn_hbox), backward_checkbtn,
-                           FALSE, FALSE, 0);
-
-       all_checkbtn =
-               gtk_check_button_new_with_label (_("Select all matched"));
-       gtk_widget_show (all_checkbtn);
-       gtk_box_pack_start (GTK_BOX (checkbtn_hbox), all_checkbtn,
-                           FALSE, FALSE, 0);
-       g_signal_connect(G_OBJECT(all_checkbtn), "clicked",
-                        G_CALLBACK(all_clicked), summaryview);
-
-       gtkut_stock_button_set_create(&confirm_area,
-                                     &search_btn, GTK_STOCK_FIND,
-                                     &clear_btn, GTK_STOCK_CLEAR,
-                                     &close_btn, GTK_STOCK_CLOSE);
+       confirm_area = gtk_hbutton_box_new();
        gtk_widget_show (confirm_area);
+       gtk_button_box_set_layout(GTK_BUTTON_BOX(confirm_area),
+                                 GTK_BUTTONBOX_END);
+       gtk_box_set_spacing(GTK_BOX(confirm_area), 5);
+
+       all_btn = gtk_button_new_from_stock(_("Find all"));
+       GTK_WIDGET_SET_FLAGS(all_btn, GTK_CAN_DEFAULT);
+       gtk_box_pack_start(GTK_BOX(confirm_area), all_btn, TRUE, TRUE, 0);
+       gtk_widget_show(all_btn);
+
+       prev_btn = gtk_button_new_from_stock(GTK_STOCK_GO_BACK);
+       GTK_WIDGET_SET_FLAGS(prev_btn, GTK_CAN_DEFAULT);
+       gtk_box_pack_start(GTK_BOX(confirm_area), prev_btn, TRUE, TRUE, 0);
+       gtk_widget_show(prev_btn);
+
+       next_btn = gtk_button_new_from_stock(GTK_STOCK_GO_FORWARD);
+       GTK_WIDGET_SET_FLAGS(next_btn, GTK_CAN_DEFAULT);
+       gtk_box_pack_start(GTK_BOX(confirm_area), next_btn, TRUE, TRUE, 0);
+       gtk_widget_show(next_btn);
+
+       close_btn = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
+       GTK_WIDGET_SET_FLAGS(close_btn, GTK_CAN_DEFAULT);
+       gtk_box_pack_start(GTK_BOX(confirm_area), close_btn, TRUE, TRUE, 0);
+       gtk_widget_show(close_btn);
+
        gtk_box_pack_start (GTK_BOX (vbox1), confirm_area, FALSE, FALSE, 0);
-       gtk_widget_grab_default(search_btn);
+       gtk_widget_grab_default(next_btn);
 
-       g_signal_connect(G_OBJECT(search_btn), "clicked",
-                        G_CALLBACK(summary_search_execute),
-                        summaryview);
        g_signal_connect(G_OBJECT(clear_btn), "clicked",
-                        G_CALLBACK(summary_search_clear),
-                        summaryview);
+                        G_CALLBACK(summary_search_clear), NULL);
+       g_signal_connect(G_OBJECT(all_btn), "clicked",
+                        G_CALLBACK(summary_search_all_clicked), NULL);
+       g_signal_connect(G_OBJECT(prev_btn), "clicked",
+                        G_CALLBACK(summary_search_prev_clicked), NULL);
+       g_signal_connect(G_OBJECT(next_btn), "clicked",
+                        G_CALLBACK(summary_search_next_clicked), NULL);
        g_signal_connect_closure
                (G_OBJECT(close_btn), "clicked",
                 g_cclosure_new_swap(G_CALLBACK(gtk_widget_hide),
                                     window, NULL),
                 FALSE);
+
+       search_window.window = window;
+       search_window.bool_optmenu = bool_optmenu;
+       search_window.from_entry = from_entry;
+       search_window.to_entry = to_entry;
+       search_window.subject_entry = subject_entry;
+       search_window.body_entry = body_entry;
+       search_window.case_checkbtn = case_checkbtn;
+       search_window.clear_btn = clear_btn;
+       search_window.all_btn = all_btn;
+       search_window.prev_btn = prev_btn;
+       search_window.next_btn = next_btn;
+       search_window.close_btn = close_btn;
 }
 
-static void summary_search_execute(GtkButton *button, gpointer data)
+static void summary_search_execute(gboolean backward, gboolean search_all)
 {
-       SummaryView *summaryview = data;
+       SummaryView *summaryview = search_window.summaryview;
        GtkCTree *ctree = GTK_CTREE(summaryview->ctree);
        GtkCTreeNode *node;
        MsgInfo *msginfo;
        gboolean bool_and;
        gboolean case_sens;
-       gboolean backward;
-       gboolean search_all;
        gboolean all_searched = FALSE;
        gboolean matched;
        gboolean body_matched;
        const gchar *from_str, *to_str, *subject_str, *body_str;
        StrFindFunc str_find_func;
+       gboolean valid;
 
        if (summary_is_locked(summaryview)) return;
        summary_lock(summaryview);
 
        bool_and = GPOINTER_TO_INT
                (menu_get_option_menu_active_user_data
-                       (GTK_OPTION_MENU(bool_optmenu)));
+                       (GTK_OPTION_MENU(search_window.bool_optmenu)));
        case_sens = gtk_toggle_button_get_active
-               (GTK_TOGGLE_BUTTON(case_checkbtn));
-       backward = gtk_toggle_button_get_active
-               (GTK_TOGGLE_BUTTON(backward_checkbtn));
-       search_all = gtk_toggle_button_get_active
-               (GTK_TOGGLE_BUTTON(all_checkbtn));
+               (GTK_TOGGLE_BUTTON(search_window.case_checkbtn));
 
        if (case_sens)
                str_find_func = str_find;
        else
                str_find_func = str_case_find;
 
-       from_str    = gtk_entry_get_text(GTK_ENTRY(from_entry));
-       to_str      = gtk_entry_get_text(GTK_ENTRY(to_entry));
-       subject_str = gtk_entry_get_text(GTK_ENTRY(subject_entry));
-       body_str    = gtk_entry_get_text(GTK_ENTRY(body_entry));
+       from_str    = gtk_entry_get_text(GTK_ENTRY(search_window.from_entry));
+       to_str      = gtk_entry_get_text(GTK_ENTRY(search_window.to_entry));
+       subject_str = gtk_entry_get_text(GTK_ENTRY(search_window.subject_entry));
+       body_str    = gtk_entry_get_text(GTK_ENTRY(search_window.body_entry));
 
        if (search_all) {
                gtk_clist_freeze(GTK_CLIST(ctree));
@@ -317,8 +375,11 @@ static void summary_search_execute(GtkButton *button, gpointer data)
                        }
 
                        if (all_searched) {
-                               alertpanel_notice
-                                       (_("Search string not found."));
+                               alertpanel_with_type
+                                       (_("Search failed"),
+                                        _("Search string not found."),
+                                        NULL, NULL, NULL, NULL,
+                                        ALERT_WARNING);
                                break;
                        }
 
@@ -339,7 +400,7 @@ static void summary_search_execute(GtkButton *button, gpointer data)
 
                                all_searched = TRUE;
 
-                               manage_window_focus_in(window, NULL, NULL);
+                               manage_window_focus_in(search_window.window, NULL, NULL);
                        } else
                                break;
                }
@@ -433,44 +494,55 @@ static void summary_search_execute(GtkButton *button, gpointer data)
 
 static void summary_search_clear(GtkButton *button, gpointer data)
 {
-       gtk_editable_delete_text(GTK_EDITABLE(from_entry),    0, -1);
-       gtk_editable_delete_text(GTK_EDITABLE(to_entry),      0, -1);
-       gtk_editable_delete_text(GTK_EDITABLE(subject_entry), 0, -1);
-       gtk_editable_delete_text(GTK_EDITABLE(body_entry),    0, -1);
+       gtk_editable_delete_text(GTK_EDITABLE(search_window.from_entry),
+                                0, -1);
+       gtk_editable_delete_text(GTK_EDITABLE(search_window.to_entry),
+                                0, -1);
+       gtk_editable_delete_text(GTK_EDITABLE(search_window.subject_entry),
+                                0, -1);
+       gtk_editable_delete_text(GTK_EDITABLE(search_window.body_entry),
+                                0, -1);
+}
+
+static void summary_search_prev_clicked(GtkButton *button, gpointer data)
+{
+       summary_search_execute(TRUE, FALSE);
+}
+
+static void summary_search_next_clicked(GtkButton *button, gpointer data)
+{
+       summary_search_execute(FALSE, FALSE);
+}
+
+static void summary_search_all_clicked(GtkButton *button, gpointer data)
+{
+       summary_search_execute(FALSE, TRUE);
 }
 
 static void from_activated(void)
 {
-       gtk_widget_grab_focus(to_entry);
+       gtk_widget_grab_focus(search_window.to_entry);
 }
 
 static void to_activated(void)
 {
-       gtk_widget_grab_focus(subject_entry);
+       gtk_widget_grab_focus(search_window.subject_entry);
 }
 
 static void subject_activated(void)
 {
-       gtk_button_clicked(GTK_BUTTON(search_btn));
+       gtk_button_clicked(GTK_BUTTON(search_window.next_btn));
 }
 
 static void body_activated(void)
 {
-       gtk_button_clicked(GTK_BUTTON(search_btn));
-}
-
-static gboolean all_clicked(GtkButton *button)
-{
-       if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)))
-               gtk_widget_set_sensitive(backward_checkbtn, FALSE);
-       else
-               gtk_widget_set_sensitive(backward_checkbtn, TRUE);
-       return FALSE;
+       gtk_button_clicked(GTK_BUTTON(search_window.next_btn));
 }
 
-static gboolean key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
+static gboolean key_pressed(GtkWidget *widget, GdkEventKey *event,
+                           gpointer data)
 {
        if (event && event->keyval == GDK_Escape)
-               gtk_widget_hide(window);
+               gtk_widget_hide(search_window.window);
        return FALSE;
 }
index 5c3111f..86b49b2 100644 (file)
@@ -1340,7 +1340,9 @@ void textview_write_link(TextView *textview, const gchar *str,
        gchar *bufp;
        RemoteURI *r_uri;
 
-       if (*str == '\0')
+       if (!str || *str == '\0')
+               return;
+       if (!uri)
                return;
 
        text = GTK_TEXT_VIEW(textview->text);
@@ -1352,12 +1354,23 @@ void textview_write_link(TextView *textview, const gchar *str,
        else if (conv_convert(conv, buf, sizeof(buf), str) < 0)
                conv_utf8todisp(buf, sizeof(buf), str);
 
+       if (g_utf8_validate(buf, -1, NULL) == FALSE) {
+               g_free(buf);
+               return;
+       }
+
        strcrchomp(buf);
 
        gtk_text_buffer_get_end_iter(buffer, &iter);
+       for (bufp = buf; *bufp != '\0'; bufp = g_utf8_next_char(bufp)) {
+               gunichar ch;
 
-       for (bufp = buf; isspace(*(guchar *)bufp); bufp++)
-               gtk_text_buffer_insert(buffer, &iter, bufp, 1);
+               ch = g_utf8_get_char(bufp);
+               if (!g_unichar_isspace(ch))
+                       break;
+       }
+       if (bufp > buf)
+               gtk_text_buffer_insert(buffer, &iter, buf, bufp - buf);
 
        if (prefs_common.enable_color) {
                link_color = &uri_color;