2005-11-01 [colin] 1.9.99cvs2
authorColin Leroy <colin@colino.net>
Tue, 1 Nov 2005 06:53:28 +0000 (06:53 +0000)
committerColin Leroy <colin@colino.net>
Tue, 1 Nov 2005 06:53:28 +0000 (06:53 +0000)
* src/compose.c
Fix replying to ml wen confirming subscription
* src/messageview.c
* src/mimeview.c
* src/mimeview.h
* src/privacy.h
* src/summaryview.c
Make key check non blocking

ChangeLog
PATCHSETS
configure.ac
src/compose.c
src/messageview.c
src/mimeview.c
src/mimeview.h
src/privacy.h
src/summaryview.c

index 6d43834..77a0f14 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2005-11-01 [colin]     1.9.99cvs2
+
+       * src/compose.c
+               Fix replying to ml wen confirming subscription
+       * src/messageview.c
+       * src/mimeview.c
+       * src/mimeview.h
+       * src/privacy.h
+       * src/summaryview.c
+               Make key check non blocking
+
 2005-10-31 [paul]      1.9.99cvs1
 
        * tools/claws.i18n.status.pl
index 20b7264..1cbd283 100644 (file)
--- a/PATCHSETS
+++ b/PATCHSETS
 ( cvs diff -u -r 1.1.2.6 -r 1.1.2.7 po/ca.po;  cvs diff -u -r 1.58.2.14 -r 1.58.2.15 po/de.po;  cvs diff -u -r 1.12.2.6 -r 1.12.2.7 po/en_GB.po;  cvs diff -u -r 1.42.2.16 -r 1.42.2.17 po/fr.po;  cvs diff -u -r 1.34.2.12 -r 1.34.2.13 po/it.po;  cvs diff -u -r 1.50.2.12 -r 1.50.2.13 po/pt_BR.po;  cvs diff -u -r 1.2.2.17 -r 1.2.2.18 po/sk.po;  cvs diff -u -r 1.17.2.14 -r 1.17.2.15 po/sr.po;  cvs diff -u -r 1.5.2.10 -r 1.5.2.11 po/zh_CN.po;  ) > 1.9.15cvs129.patchset
 ( cvs diff -u -r 1.34.2.13 -r 1.34.2.14 po/it.po;  ) > 1.9.15cvs130.patchset
 ( cvs diff -u -r 1.1.2.3 -r 1.1.2.4 tools/claws.i18n.status.pl;  ) > 1.9.99cvs1.patchset
+( cvs diff -u -r 1.382.2.191 -r 1.382.2.192 src/compose.c;  cvs diff -u -r 1.94.2.69 -r 1.94.2.70 src/messageview.c;  cvs diff -u -r 1.83.2.50 -r 1.83.2.51 src/mimeview.c;  cvs diff -u -r 1.20.2.5 -r 1.20.2.6 src/mimeview.h;  cvs diff -u -r 1.10.2.5 -r 1.10.2.6 src/privacy.h;  cvs diff -u -r 1.395.2.145 -r 1.395.2.146 src/summaryview.c;  ) > 1.9.99cvs2.patchset
index ae12fdb..8cca70d 100644 (file)
@@ -11,7 +11,7 @@ MINOR_VERSION=9
 MICRO_VERSION=99
 INTERFACE_AGE=0
 BINARY_AGE=0
-EXTRA_VERSION=1
+EXTRA_VERSION=2
 EXTRA_RELEASE=
 EXTRA_GTK2_VERSION=
 
index 57b0047..7d23ad4 100644 (file)
@@ -2194,6 +2194,59 @@ static gchar *compose_quote_fmt(Compose *compose, MsgInfo *msginfo,
        return buf;
 }
 
+/* if ml_post is of type addr@host and from is of type
+ * addr-anything@host, return TRUE
+ */
+static gboolean is_subscription(const gchar *ml_post, const gchar *from)
+{
+       gchar *left_ml = NULL;
+       gchar *right_ml = NULL;
+       gchar *left_from = NULL;
+       gchar *right_from = NULL;
+       gboolean result = FALSE;
+       
+       if (!ml_post || !from)
+               return FALSE;
+       
+       left_ml = g_strdup(ml_post);
+       if (strstr(left_ml, "@")) {
+               right_ml = strstr(left_ml, "@")+1;
+               *(strstr(left_ml, "@")) = '\0';
+       }
+       
+       left_from = g_strdup(from);
+       if (strstr(left_from, "@")) {
+               right_from = strstr(left_from, "@")+1;
+               *(strstr(left_from, "@")) = '\0';
+       }
+       
+       if (left_ml && left_from && right_ml && right_from
+       &&  !strncmp(left_from, left_ml, strlen(left_ml))
+       &&  !strcmp(right_from, right_ml)) {
+               result = TRUE;
+       }
+       g_free(left_ml);
+       g_free(left_from);
+       
+       return result;
+}
+
+static gboolean same_address(const gchar *addr1, const gchar *addr2)
+{
+       gchar *my_addr1, *my_addr2;
+       
+       if (!addr1 || !addr2)
+               return FALSE;
+
+       Xstrdup_a(my_addr1, addr1, return FALSE);
+       Xstrdup_a(my_addr2, addr2, return FALSE);
+       
+       extract_address(my_addr1);
+       extract_address(my_addr2);
+       
+       return !strcmp(my_addr1, my_addr2);
+}
+
 static void compose_reply_set_entry(Compose *compose, MsgInfo *msginfo,
                                    gboolean to_all, gboolean to_ml,
                                    gboolean to_sender,
@@ -2205,32 +2258,45 @@ static void compose_reply_set_entry(Compose *compose, MsgInfo *msginfo,
        gchar *replyto = NULL;
        GHashTable *to_table;
 
+       gboolean reply_to_ml = FALSE;
+       gboolean default_reply_to = FALSE;
+
        g_return_if_fail(compose->account != NULL);
        g_return_if_fail(msginfo != NULL);
 
+       reply_to_ml = to_ml && compose->ml_post;
+
+       default_reply_to = msginfo->folder && 
+               msginfo->folder->prefs->enable_default_reply_to;
+
        if (compose->account->protocol != A_NNTP) {
-               if (to_ml && compose->ml_post
-                   && !(msginfo->folder && 
-                        msginfo->folder->prefs->enable_default_reply_to)) {
-                       compose_entry_append(compose,
+               if (reply_to_ml && !default_reply_to) {
+                       
+                       gboolean is_subscr = is_subscription(compose->ml_post,
+                                                            msginfo->from);
+                       if (!is_subscr) {
+                               /* normal answer to ml post with a reply-to */
+                               compose_entry_append(compose,
                                           compose->ml_post,
                                           COMPOSE_TO);
-                       if (compose->replyto) {
-                               gchar *tmp1 = NULL, *tmp2 = NULL;
-                               Xstrdup_a(tmp1, compose->replyto, return);
-                               if (compose->ml_post)
-                                       Xstrdup_a(tmp2, compose->ml_post, return);
-                               extract_address(tmp1);
-                               extract_address(tmp2);
-                               if (tmp1 && tmp2 && strcmp(tmp1, tmp2))
+                               if (compose->replyto
+                               &&  !same_address(compose->ml_post, compose->replyto))
+                                       compose_entry_append(compose,
+                                               compose->replyto,
+                                               COMPOSE_CC);
+                       } else {
+                               /* answer to subscription confirmation */
+                               if (compose->replyto)
+                                       compose_entry_append(compose,
+                                               compose->replyto,
+                                               COMPOSE_TO);
+                               else if (msginfo->from)
                                        compose_entry_append(compose,
-                                                       compose->replyto,
-                                                       COMPOSE_CC);
+                                               msginfo->from,
+                                               COMPOSE_TO);
                        }
                }
-               else if (!(to_all || to_sender)
-                        && msginfo->folder
-                        && msginfo->folder->prefs->enable_default_reply_to) {
+               else if (!(to_all || to_sender) && default_reply_to) {
                        compose_entry_append(compose,
                            msginfo->folder->prefs->default_reply_to,
                            COMPOSE_TO);
index 5774e2f..26d779a 100644 (file)
@@ -1079,6 +1079,8 @@ static gboolean key_pressed(GtkWidget *widget, GdkEventKey *event,
                messageview_destroy(messageview);
                return TRUE;
        }
+       g_signal_stop_emission_by_name(G_OBJECT(widget),
+                                       "key_press_event");
        mimeview_pass_key_press_event(messageview->mimeview, event);
        return FALSE;
 }
index 57e53c7..2fe43e6 100644 (file)
@@ -356,6 +356,26 @@ void mimeview_show_message(MimeView *mimeview, MimeInfo *mimeinfo,
        }
 }
 
+#ifdef USE_PTHREAD
+static void mimeview_check_sig_cancel_now(MimeView *mimeview);
+#endif
+
+static void mimeview_free_mimeinfo(MimeView *mimeview)
+{
+       gboolean defer = FALSE;
+#ifdef USE_PTHREAD
+       defer = (mimeview->check_data != NULL);
+       if (defer)
+               mimeview->check_data->free_after_use = TRUE;
+#endif
+       if (mimeview->mimeinfo != NULL && !defer)
+               procmime_mimeinfo_free_all(mimeview->mimeinfo);
+       else if (defer) {
+               debug_print("deferring free(mimeinfo) and cancelling check\n");
+               mimeview_check_sig_cancel_now(mimeview);
+       }
+}
+
 void mimeview_destroy(MimeView *mimeview)
 {
        GSList *cur;
@@ -369,11 +389,18 @@ void mimeview_destroy(MimeView *mimeview)
        g_slist_free(mimeview->viewers);
        gtk_target_list_unref(mimeview->target_list);
 
-       procmime_mimeinfo_free_all(mimeview->mimeinfo);
-       g_free(mimeview->file);
-       g_free(mimeview);
-
-       mimeviews = g_slist_remove(mimeviews, mimeview);
+       mimeview_free_mimeinfo(mimeview);
+#ifdef USE_PTHREAD
+       if (mimeview->check_data) {
+               mimeview->check_data->destroy_mimeview = TRUE;
+               debug_print("deferring destroy\n");
+       } else 
+#endif
+       {
+               g_free(mimeview->file);
+               g_free(mimeview);
+               mimeviews = g_slist_remove(mimeviews, mimeview);
+       }
        
 }
 
@@ -606,7 +633,7 @@ static void mimeview_change_view_type(MimeView *mimeview, MimeViewType type)
 void mimeview_clear(MimeView *mimeview)
 {
        GtkCList *clist = GTK_CLIST(mimeview->ctree);
-
+       
        noticeview_hide(mimeview->siginfoview);
 
        gtk_clist_clear(clist);
@@ -614,8 +641,8 @@ void mimeview_clear(MimeView *mimeview)
        if (mimeview->mimeviewer != NULL)
                mimeview->mimeviewer->clear_viewer(mimeview->mimeviewer);
 
-       if (mimeview->mimeinfo != NULL)
-               procmime_mimeinfo_free_all(mimeview->mimeinfo);
+       mimeview_free_mimeinfo(mimeview);
+
        mimeview->mimeinfo = NULL;
 
        mimeview->opened = NULL;
@@ -630,16 +657,23 @@ static void check_signature_cb(GtkWidget *widget, gpointer user_data);
 void mimeview_check_signature(MimeView *mimeview);
 static void display_full_info_cb(GtkWidget *widget, gpointer user_data);
 
-static void update_signature_noticeview(MimeView *mimeview, MimeInfo *mimeinfo)
+static void update_signature_noticeview(MimeView *mimeview, MimeInfo *mimeinfo, 
+                                       gboolean special, SignatureStatus code)
 {
        gchar *text = NULL, *button_text = NULL;
        void  *func = NULL;
        StockPixmap icon = STOCK_PIXMAP_PRIVACY_SIGNED;
-
+       SignatureStatus mycode = SIGNATURE_UNCHECKED;
+       
        g_return_if_fail(mimeview != NULL);
        g_return_if_fail(mimeinfo != NULL);
        
-       switch (privacy_mimeinfo_get_sig_status(mimeinfo)) {
+       if (special)
+               mycode = code;
+       else 
+               mycode = privacy_mimeinfo_get_sig_status(mimeinfo);
+
+       switch (mycode) {
        case SIGNATURE_UNCHECKED:
                button_text = _("Check signature");
                func = check_signature_cb;
@@ -664,16 +698,24 @@ static void update_signature_noticeview(MimeView *mimeview, MimeInfo *mimeinfo)
                button_text = _("Check again");
                func = check_signature_cb;
                icon = STOCK_PIXMAP_PRIVACY_UNKNOWN;
+       case SIGNATURE_CHECK_TIMEOUT:
+               button_text = _("Check again");
+               func = check_signature_cb;
+               icon = STOCK_PIXMAP_PRIVACY_UNKNOWN;
        default:
                break;
        }
-       if (privacy_mimeinfo_get_sig_status(mimeinfo) == SIGNATURE_UNCHECKED) {
+       if (mycode == SIGNATURE_UNCHECKED) {
                gchar *tmp = privacy_mimeinfo_sig_info_short(mimeinfo);
                text = g_strdup_printf("%s %s",
                        tmp, _("Click the icon or hit 'C' to check it."));
                g_free(tmp);
-       } else
+       } else if (mycode != SIGNATURE_CHECK_TIMEOUT) {
                text = privacy_mimeinfo_sig_info_short(mimeinfo);
+       } else if (mycode == SIGNATURE_CHECK_TIMEOUT) {
+               text = g_strdup(_("Timeout checking the signature. Click the icon or hit 'C' to try again."));
+       }
+
        noticeview_set_text(mimeview->siginfoview, text);
        g_free(text);
        noticeview_set_button_text(mimeview->siginfoview, NULL);
@@ -685,6 +727,189 @@ static void update_signature_noticeview(MimeView *mimeview, MimeInfo *mimeinfo)
        noticeview_set_tooltip(mimeview->siginfoview, button_text);
 }
 
+#ifdef USE_PTHREAD
+
+/* reset all thread stuff, and do the cleanups we've been left to do */
+static void mimeview_check_data_reset(MimeView *mimeview)
+{
+       if (!mimeview->check_data)
+               return;
+
+       if (mimeview->check_data->free_after_use) {
+               debug_print("freeing deferred mimeinfo\n");
+               procmime_mimeinfo_free_all(mimeview->check_data->siginfo);
+       }
+       if (mimeview->check_data->destroy_mimeview) {
+               debug_print("freeing deferred mimeview\n");
+               g_free(mimeview->file);
+               g_free(mimeview);
+               mimeviews = g_slist_remove(mimeviews, mimeview);
+       }
+
+       g_free(mimeview->check_data);
+       mimeview->check_data = NULL;
+}
+
+/* GUI update once the checker thread is done or killed */
+static gboolean mimeview_check_sig_thread_cb(void *data)
+{
+       MimeView *mimeview = (MimeView *) data;
+       MimeInfo *mimeinfo = mimeview->siginfo;
+
+       debug_print("mimeview_check_sig_thread_cb\n");
+       
+       if (mimeinfo == NULL) {
+               /* message changed !? */
+               g_warning("no more siginfo!\n");
+               goto end;
+       }
+       
+       if (!mimeview->check_data) {
+               g_warning("nothing to check\n");
+               return FALSE;
+       }
+
+       if (mimeview->check_data->siginfo != mimeinfo) {
+               /* message changed !? */
+               g_warning("different siginfo!\n");
+               goto end;
+       }
+
+       if (mimeview->check_data->destroy_mimeview ||
+           mimeview->check_data->free_after_use) {
+               debug_print("not bothering, we're changing message\n"); 
+               goto end;
+       }
+       
+       /* update status */
+       if (mimeview->check_data->timeout) 
+               update_signature_noticeview(mimeview, mimeview->siginfo, 
+                       TRUE, SIGNATURE_CHECK_TIMEOUT);
+       else
+               update_signature_noticeview(mimeview, mimeview->siginfo, 
+                       FALSE, 0);
+       icon_list_clear(mimeview);
+       icon_list_create(mimeview, mimeview->mimeinfo);
+       
+end:
+       mimeview_check_data_reset(mimeview);
+       return FALSE;
+}
+
+/* sig checker thread */
+static void *mimeview_check_sig_worker_thread(void *data)
+{
+       MimeView *mimeview = (MimeView *)data;
+       MimeInfo *mimeinfo = mimeview->siginfo;
+       
+       debug_print("checking...\n");
+
+       if (!mimeview->check_data)
+               return NULL;
+
+       if (mimeinfo && mimeinfo == mimeview->check_data->siginfo)
+               privacy_mimeinfo_check_signature(mimeinfo);
+       else {
+               /* that's strange! we changed message without 
+                * getting killed. */
+               g_warning("different siginfo!\n");
+               mimeview_check_data_reset(mimeview);
+               return NULL;
+       }
+
+       /* use g_timeout so that GUI updates is done from the
+        * correct thread */
+       g_timeout_add(0,mimeview_check_sig_thread_cb,mimeview);
+       
+       return NULL;
+}
+
+/* killer thread - acts when the checker didn't work fast
+ * enough. */
+static void *mimeview_check_sig_cancel_thread(void *data)
+{
+       MimeView *mimeview = (MimeView *)data;
+       
+       if (!mimeview->check_data)
+               return NULL; /* nothing to kill ! */
+
+       /* wait for a few seconds... */
+       debug_print("waiting a while\n");
+
+       sleep(5);
+       
+       if (!mimeview->check_data)
+               return NULL; /* nothing to kill, it's done in time :) */
+       
+       /* too late, go away checker thread */
+       debug_print("killing checker thread\n");
+       pthread_cancel(mimeview->check_data->th);
+       
+       /* tell upstream it was a timeout */
+       mimeview->check_data->timeout = TRUE;
+       /* use g_timeout so that GUI updates is done from the
+        * correct thread */
+       g_timeout_add(0,mimeview_check_sig_thread_cb,mimeview);
+
+       return NULL;
+}
+
+/* get rid of the checker thread right now - used when changing the
+ * displayed message for example. */
+static void mimeview_check_sig_cancel_now(MimeView *mimeview)
+{
+       if (!mimeview->check_data)
+               return;
+       debug_print("killing checker thread NOW\n");
+       pthread_cancel(mimeview->check_data->th);
+
+       /* tell upstream it was a timeout */
+       mimeview->check_data->timeout = TRUE;
+       mimeview_check_sig_thread_cb(mimeview);
+       return;
+}
+
+/* creates a thread to check the signature, and a second one
+ * to kill the first one after a timeout */
+static void mimeview_check_sig_in_thread(MimeView *mimeview)
+{
+       pthread_t th, th2;
+       pthread_attr_t detach, detach2;
+       
+       if (mimeview->check_data) {
+               g_warning("already checking it");
+               return;
+       }
+       
+       mimeview->check_data = g_new0(SigCheckData, 1);
+       mimeview->check_data->siginfo = mimeview->siginfo;
+       debug_print("creating thread\n");
+
+       pthread_attr_init(&detach);
+       pthread_attr_setdetachstate(&detach, TRUE);
+
+       pthread_attr_init(&detach2);
+       pthread_attr_setdetachstate(&detach2, TRUE);
+
+       /* create the checker thread */
+       if (pthread_create(&th, &detach, 
+                       mimeview_check_sig_worker_thread, 
+                       mimeview) != 0) {
+               /* arh. We'll do it synchronously. */
+               g_warning("can't create thread");
+               g_free(mimeview->check_data);
+               mimeview->check_data = NULL;
+               return;
+       } else 
+               mimeview->check_data->th = th;
+
+       /* create the killer thread */
+       pthread_create(&th2, &detach2, 
+                       mimeview_check_sig_cancel_thread, 
+                       mimeview);
+}
+#endif
+
 static void check_signature_cb(GtkWidget *widget, gpointer user_data)
 {
        MimeView *mimeview = (MimeView *) user_data;
@@ -692,13 +917,24 @@ static void check_signature_cb(GtkWidget *widget, gpointer user_data)
        
        if (mimeinfo == NULL)
                return;
-
+#ifdef USE_PTHREAD
+       if (mimeview->check_data)
+               return;
+#endif
        noticeview_set_text(mimeview->siginfoview, _("Checking signature..."));
        GTK_EVENTS_FLUSH();
-       privacy_mimeinfo_check_signature(mimeinfo);
-       update_signature_noticeview(mimeview, mimeview->siginfo);
-       icon_list_clear(mimeview);
-       icon_list_create(mimeview, mimeview->mimeinfo);
+#if (defined USE_PTHREAD && defined __GLIBC__ && (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 3)))
+       /* let's do it non-blocking */
+       mimeview_check_sig_in_thread(mimeview);
+       if (!mimeview->check_data) /* let's check syncronously */
+#endif
+       {
+               debug_print("checking without thread\n");
+               privacy_mimeinfo_check_signature(mimeinfo);
+               update_signature_noticeview(mimeview, mimeview->siginfo, FALSE, 0);
+               icon_list_clear(mimeview);
+               icon_list_create(mimeview, mimeview->mimeinfo);
+       }
 }
 
 void mimeview_check_signature(MimeView *mimeview)
@@ -764,7 +1000,7 @@ static void update_signature_info(MimeView *mimeview, MimeInfo *selected)
                return;
        }
        
-       update_signature_noticeview(mimeview, siginfo);
+       update_signature_noticeview(mimeview, siginfo, FALSE, 0);
        noticeview_show(mimeview->siginfoview);
 }
 
@@ -1652,6 +1888,7 @@ static void icon_list_append_icon (MimeView *mimeview, MimeInfo *mimeinfo)
                switch (privacy_mimeinfo_get_sig_status(siginfo)) {
                case SIGNATURE_UNCHECKED:
                case SIGNATURE_CHECK_FAILED:
+               case SIGNATURE_CHECK_TIMEOUT:
                        pixmap = stock_pixmap_widget_with_overlay(mimeview->mainwin->window, stockp,
                            STOCK_PIXMAP_PRIVACY_EMBLEM_SIGNED, OVERLAY_BOTTOM_RIGHT, 6, 3);
                        break;
index 6cc48e1..301eac8 100644 (file)
@@ -29,6 +29,9 @@ typedef struct _MimeViewer            MimeViewer;
 #include <gtk/gtkwidget.h>
 #include <gtk/gtkctree.h>
 #include <gtk/gtktooltips.h>
+#ifdef USE_PTHREAD
+#include <pthread.h>
+#endif
 
 #include "textview.h"
 #include "messageview.h"
@@ -41,6 +44,18 @@ typedef enum
        MIMEVIEW_VIEWER
 } MimeViewType;
 
+#ifdef USE_PTHREAD
+typedef struct _SigCheckData SigCheckData;
+struct _SigCheckData
+{
+       pthread_t th;
+       MimeInfo *siginfo;
+       gboolean free_after_use;
+       gboolean destroy_mimeview;
+       gboolean timeout;
+};
+#endif
+
 struct _MimeView
 {
        GtkWidget *hbox;
@@ -81,6 +96,9 @@ struct _MimeView
 
        NoticeView *siginfoview;
        MimeInfo *siginfo;
+#ifdef USE_PTHREAD
+       SigCheckData *check_data;
+#endif
 };
 
 struct _MimeViewerFactory
index 3adb599..bca39fb 100644 (file)
@@ -28,7 +28,8 @@ typedef enum {
        SIGNATURE_OK,
        SIGNATURE_WARN,
        SIGNATURE_INVALID,
-       SIGNATURE_CHECK_FAILED
+       SIGNATURE_CHECK_FAILED,
+       SIGNATURE_CHECK_TIMEOUT
 } SignatureStatus;
 
 #include <glib.h>
index 8094319..6a6cc3d 100644 (file)
@@ -4746,6 +4746,8 @@ static gboolean summary_key_pressed(GtkWidget *widget, GdkEventKey *event,
        case GDK_l:
        case GDK_c:
                if ((event->state & (GDK_MOD1_MASK|GDK_CONTROL_MASK)) == 0) {
+                       g_signal_stop_emission_by_name(G_OBJECT(widget), 
+                                       "key_press_event");
                        mimeview_pass_key_press_event(messageview->mimeview,
                                                      event);
                        break;