balsa r7872 - in branches/mailbox-gsequence: . libbalsa src



Author: PeterB
Date: Thu Feb 28 02:41:51 2008
New Revision: 7872
URL: http://svn.gnome.org/viewvc/balsa?rev=7872&view=rev

Log:
port changes from trunk

Modified:
   branches/mailbox-gsequence/configure.in
   branches/mailbox-gsequence/libbalsa/filter-funcs.c
   branches/mailbox-gsequence/libbalsa/identity.c
   branches/mailbox-gsequence/libbalsa/identity.h
   branches/mailbox-gsequence/libbalsa/libbalsa.c
   branches/mailbox-gsequence/libbalsa/libbalsa_private.h
   branches/mailbox-gsequence/libbalsa/mailbox.c
   branches/mailbox-gsequence/libbalsa/mailbox.h
   branches/mailbox-gsequence/libbalsa/rfc3156.c
   branches/mailbox-gsequence/libbalsa/rfc3156.h
   branches/mailbox-gsequence/src/balsa-index.c
   branches/mailbox-gsequence/src/balsa-mblist.c
   branches/mailbox-gsequence/src/balsa-mblist.h
   branches/mailbox-gsequence/src/balsa-message.c
   branches/mailbox-gsequence/src/balsa-message.h
   branches/mailbox-gsequence/src/filter-edit-callbacks.c
   branches/mailbox-gsequence/src/mailbox-conf.c
   branches/mailbox-gsequence/src/mailbox-node.c
   branches/mailbox-gsequence/src/main-window.c
   branches/mailbox-gsequence/src/message-window.c
   branches/mailbox-gsequence/src/save-restore.c
   branches/mailbox-gsequence/src/save-restore.h
   branches/mailbox-gsequence/src/sendmsg-window.c

Modified: branches/mailbox-gsequence/configure.in
==============================================================================
--- branches/mailbox-gsequence/configure.in	(original)
+++ branches/mailbox-gsequence/configure.in	Thu Feb 28 02:41:51 2008
@@ -766,6 +766,8 @@
 if test -d "${srcdir}/.svn" ; then
 	BALSA_FROM_SVN=yes
 	BALSA_CFLAGS="$BALSA_CFLAGS -Wall -Werror"
+	BALSA_CFLAGS="$BALSA_CFLAGS -pg"
+	BALSA_LIBS="$BALSA_LIBS -pg"
 else
 	BALSA_FROM_SVN=no
 fi

Modified: branches/mailbox-gsequence/libbalsa/filter-funcs.c
==============================================================================
--- branches/mailbox-gsequence/libbalsa/filter-funcs.c	(original)
+++ branches/mailbox-gsequence/libbalsa/filter-funcs.c	Thu Feb 28 02:41:51 2008
@@ -481,12 +481,20 @@
 /* Helper to compare conditions, a bit obscure at first glance
    but we have to compare complex structure, so we must check
    all fields.
+   NULL conditions are OK, and compare equal only if both are NULL.
 */
 
 gboolean
 libbalsa_condition_compare(LibBalsaCondition *c1,LibBalsaCondition *c2)
 {
     gboolean res = FALSE;
+
+    if (c1 == c2) 
+        return TRUE;
+
+    if (c1 == NULL || c2 == NULL)
+        return FALSE;
+
     switch (c1->type) {
     case CONDITION_STRING:
         res = (c2->type == CONDITION_STRING ||

Modified: branches/mailbox-gsequence/libbalsa/identity.c
==============================================================================
--- branches/mailbox-gsequence/libbalsa/identity.c	(original)
+++ branches/mailbox-gsequence/libbalsa/identity.c	Thu Feb 28 02:41:51 2008
@@ -113,6 +113,7 @@
     ident->gpg_sign = FALSE;
     ident->gpg_encrypt = FALSE;
     ident->always_trust = FALSE;
+    ident->warn_send_plain = TRUE;
     ident->crypt_protocol = LIBBALSA_PROTECT_OPENPGP;
 #endif
     ident->request_mdn = FALSE;
@@ -1037,7 +1038,7 @@
 #endif
     /* create the "Security" tab */
     table =
-        append_ident_notebook_page(notebook, 4, _("Security"), footnote);
+        append_ident_notebook_page(notebook, 5, _("Security"), footnote);
     row = 0;
     ident_dialog_add_checkbutton(table, row++, dialog, 
                                  _("sign messages by default"),
@@ -1051,6 +1052,9 @@
     ident_dialog_add_checkbutton(table, row++, dialog,
                                  _("always trust GnuPG keys when encrypting"),
                                  "identity-trust-always", TRUE);
+    ident_dialog_add_checkbutton(table, row++, dialog,
+                                 _("remind me if messages can be encrypted"),
+                                 "identity-warn-send-plain", TRUE);
 #ifndef HAVE_GPGME
     gtk_widget_set_sensitive(table, FALSE);
 #endif
@@ -1491,6 +1495,7 @@
     id->gpg_sign        = ident_dialog_get_bool(dlg, "identity-gpgsign");
     id->gpg_encrypt     = ident_dialog_get_bool(dlg, "identity-gpgencrypt");
     id->always_trust    = ident_dialog_get_bool(dlg, "identity-trust-always");
+    id->warn_send_plain = ident_dialog_get_bool(dlg, "identity-warn-send-plain");
     id->crypt_protocol  = GPOINTER_TO_INT(ident_dialog_get_value
                                           (dlg, "identity-crypt-protocol"));
 #endif
@@ -1871,6 +1876,8 @@
                               ident->gpg_encrypt);    
     display_frame_set_boolean(dialog, "identity-trust-always", 
                               ident->always_trust);    
+    display_frame_set_boolean(dialog, "identity-warn-send-plain", 
+                              ident->warn_send_plain);    
     display_frame_set_gpg_mode(dialog, "identity-crypt-protocol",
 			   &ident->crypt_protocol);
 #endif
@@ -1971,6 +1978,7 @@
     ident->gpg_sign = libbalsa_conf_get_bool("GpgSign");
     ident->gpg_encrypt = libbalsa_conf_get_bool("GpgEncrypt");
     ident->always_trust = libbalsa_conf_get_bool("GpgTrustAlways");
+    ident->warn_send_plain = libbalsa_conf_get_bool("GpgWarnSendPlain=true");
     ident->crypt_protocol = libbalsa_conf_get_int("CryptProtocol=16");
 #endif
 
@@ -2016,6 +2024,7 @@
     libbalsa_conf_set_bool("GpgSign", ident->gpg_sign);
     libbalsa_conf_set_bool("GpgEncrypt", ident->gpg_encrypt);
     libbalsa_conf_set_bool("GpgTrustAlways", ident->always_trust);
+    libbalsa_conf_set_bool("GpgWarnSendPlain", ident->warn_send_plain);
     libbalsa_conf_set_int("CryptProtocol", ident->crypt_protocol);
 #endif
 

Modified: branches/mailbox-gsequence/libbalsa/identity.h
==============================================================================
--- branches/mailbox-gsequence/libbalsa/identity.h	(original)
+++ branches/mailbox-gsequence/libbalsa/identity.h	Thu Feb 28 02:41:51 2008
@@ -84,6 +84,7 @@
 	gboolean gpg_sign;
 	gboolean gpg_encrypt;
 	gboolean always_trust;
+	gboolean warn_send_plain;
 	gint crypt_protocol;
 #endif
 #if ENABLE_ESMTP

Modified: branches/mailbox-gsequence/libbalsa/libbalsa.c
==============================================================================
--- branches/mailbox-gsequence/libbalsa/libbalsa.c	(original)
+++ branches/mailbox-gsequence/libbalsa/libbalsa.c	Thu Feb 28 02:41:51 2008
@@ -750,7 +750,7 @@
     self = pthread_self();
 
     if (libbalsa_threads_lock == 0 || self != libbalsa_threads_id) {
-	g_warning("Not holding gdk lock!!!");
+        g_warning("%s: Not holding gdk lock!!!", __func__);
 	return;
     }
 

Modified: branches/mailbox-gsequence/libbalsa/libbalsa_private.h
==============================================================================
--- branches/mailbox-gsequence/libbalsa/libbalsa_private.h	(original)
+++ branches/mailbox-gsequence/libbalsa/libbalsa_private.h	Thu Feb 28 02:41:51 2008
@@ -40,13 +40,6 @@
 #ifdef BALSA_USE_THREADS
     unsigned idle_pending:1;
 #endif                          /* BALSA_USE_THREADS */
-#define CACHE_UNSEEN_CHILD FALSE
-#if CACHE_UNSEEN_CHILD
-    /* Code for managing this cached bit is incomplete; if calculating
-     * has-unseen-child status on the fly is a performance hit, we'll
-     * have to finish it. */
-    unsigned has_unseen_child:1;
-#endif /* CACHE_UNSEEN_CHILD */
 } ;
 
 #ifdef BALSA_USE_THREADS

Modified: branches/mailbox-gsequence/libbalsa/mailbox.c
==============================================================================
--- branches/mailbox-gsequence/libbalsa/mailbox.c	(original)
+++ branches/mailbox-gsequence/libbalsa/mailbox.c	Thu Feb 28 02:41:51 2008
@@ -35,6 +35,7 @@
 #include "mailbox-filter.h"
 #include "message.h"
 #include "misc.h"
+#include "filter-funcs.h"
 #include "libbalsa_private.h"
 #include <glib/gi18n.h>
 
@@ -2080,17 +2081,22 @@
                                  LibBalsaCondition *cond,
                                  gboolean update_immediately)
 {
-    gboolean retval = update_immediately;
+    gboolean retval = FALSE;
 
     libbalsa_lock_mailbox(mailbox);
 
+    if (!mailbox->view_filter_pending
+        && !libbalsa_condition_compare(mailbox->view_filter, cond))
+        mailbox->view_filter_pending = TRUE;
+
     libbalsa_condition_unref(mailbox->view_filter);
     mailbox->view_filter = libbalsa_condition_ref(cond);
 
-    if (update_immediately) {
+    if (update_immediately && mailbox->view_filter_pending) {
         LIBBALSA_MAILBOX_GET_CLASS(mailbox)->update_view_filter(mailbox,
                                                                 cond);
         retval = lbm_set_threading(mailbox, mailbox->view->threading_type);
+        mailbox->view_filter_pending = FALSE;
     }
 
     libbalsa_unlock_mailbox(mailbox);

Modified: branches/mailbox-gsequence/libbalsa/mailbox.h
==============================================================================
--- branches/mailbox-gsequence/libbalsa/mailbox.h	(original)
+++ branches/mailbox-gsequence/libbalsa/mailbox.h	Thu Feb 28 02:41:51 2008
@@ -224,7 +224,12 @@
     LibBalsaCondition *view_filter; /* to choose a subset of messages
                                      * to be displayed, e.g., only
                                      * undeleted. */
-    LibBalsaCondition *persistent_view_filter;
+    LibBalsaCondition *persistent_view_filter; /* the part of the view 
+                                                * filter that will persist 
+                                                * to the next time the
+                                                * mailbox is opened */
+    gboolean view_filter_pending;  /* a view filter has been set
+                                    * but the view has not been updated */
 
     /* info fields */
     gboolean has_unread_messages;

Modified: branches/mailbox-gsequence/libbalsa/rfc3156.c
==============================================================================
--- branches/mailbox-gsequence/libbalsa/rfc3156.c	(original)
+++ branches/mailbox-gsequence/libbalsa/rfc3156.c	Thu Feb 28 02:41:51 2008
@@ -65,6 +65,8 @@
 				     GMimeGpgmeContext * ctx);
 static gboolean gpg_updates_trustdb(void);
 static gchar *fix_EMail_info(gchar * str);
+static gboolean have_pub_key_for(gpgme_ctx_t gpgme_ctx,
+				 InternetAddressList * recipients);
 
 
 /* ==== public functions =================================================== */
@@ -141,6 +143,43 @@
 }
 
 
+/* return TRUE if we can encrypt for every recipient in the recipients list
+ * using protocol */
+gboolean
+libbalsa_can_encrypt_for_all(InternetAddressList * recipients,
+			     gpgme_protocol_t protocol)
+{
+    gpgme_ctx_t gpgme_ctx;
+    gboolean result;
+
+    /* silent paranoia checks */
+    if (!recipients)
+	return TRUE;  /* we can of course encrypt for nobody... */
+#ifndef HAVE_SMIME
+    if (protocol == GPGME_PROTOCOL_OpenPGP)
+	return FALSE;
+#endif
+
+    /* check if gpg is currently available */
+    if (protocol == GPGME_PROTOCOL_OpenPGP && gpg_updates_trustdb())
+	return FALSE;
+
+    /* create the gpgme context and set the protocol */
+    if (gpgme_new(&gpgme_ctx) != GPG_ERR_NO_ERROR)
+	return FALSE;
+    if (gpgme_set_protocol(gpgme_ctx, protocol) != GPG_ERR_NO_ERROR) {
+	gpgme_release(gpgme_ctx);
+	return FALSE;
+    }
+
+    /* loop over all recipients and try to find valid keys */
+    result = have_pub_key_for(gpgme_ctx, recipients);
+    gpgme_release(gpgme_ctx);
+
+    return result;
+}
+
+
 /*
  * Check if body (and eventually its subparts) are RFC 2633 or RFC 3156 signed
  * or encrypted.
@@ -1692,4 +1731,49 @@
 	return FALSE;
 }
 
+
+/* check if the context contains a public key for the passed recipients */
+#define KEY_IS_OK(k)   (!((k)->expired || (k)->revoked || \
+                          (k)->disabled || (k)->invalid))
+static gboolean
+have_pub_key_for(gpgme_ctx_t gpgme_ctx, InternetAddressList * recipients)
+{
+    gpgme_key_t key;
+    gboolean result = TRUE;
+    time_t now = time(NULL);
+
+    for (; result && recipients; recipients = recipients->next) {
+        InternetAddress *ia = recipients->address;
+
+	/* check all entries in the list, handle groups recursively */
+	if (ia->type == INTERNET_ADDRESS_GROUP)
+	    result = have_pub_key_for(gpgme_ctx, ia->value.members);
+	else if (recipients->address->type == INTERNET_ADDRESS_NAME) {
+	    if (gpgme_op_keylist_start(gpgme_ctx, ia->value.addr, FALSE) !=
+		GPG_ERR_NO_ERROR)
+		return FALSE;
+
+	    result = FALSE;
+	    while (!result &&
+		   gpgme_op_keylist_next(gpgme_ctx, &key) == GPG_ERR_NO_ERROR) {
+		/* check if this key and the relevant subkey are usable */
+		if (KEY_IS_OK(key)) {
+		    gpgme_subkey_t subkey = key->subkeys;
+
+		    while (subkey && !subkey->can_encrypt)
+			subkey = subkey->next;
+
+		    if (subkey && KEY_IS_OK(subkey) && 
+			(subkey->expires == 0 || subkey->expires > now))
+			result = TRUE;
+		}
+		gpgme_key_unref(key);
+	    }
+	    gpgme_op_keylist_end(gpgme_ctx);
+	}
+    }
+
+    return result;
+}
+
 #endif				/* HAVE_GPGME */

Modified: branches/mailbox-gsequence/libbalsa/rfc3156.h
==============================================================================
--- branches/mailbox-gsequence/libbalsa/rfc3156.h	(original)
+++ branches/mailbox-gsequence/libbalsa/rfc3156.h	Thu Feb 28 02:41:51 2008
@@ -58,6 +58,8 @@
 gboolean libbalsa_check_crypto_engine(gpgme_protocol_t protocol);
 
 gint libbalsa_message_body_protection(LibBalsaMessageBody * body);
+gboolean libbalsa_can_encrypt_for_all(InternetAddressList * recipients,
+				      gpgme_protocol_t protocol);
 
 /* routines dealing with RFC 2633 and RFC 3156 stuff */
 gboolean libbalsa_sign_mime_object(GMimeObject ** content,

Modified: branches/mailbox-gsequence/src/balsa-index.c
==============================================================================
--- branches/mailbox-gsequence/src/balsa-index.c	(original)
+++ branches/mailbox-gsequence/src/balsa-index.c	Thu Feb 28 02:41:51 2008
@@ -1856,6 +1856,41 @@
  * set sensitivity of menuitems on the popup
  * menu, and populate the mru submenu
  */
+
+/* If the menu is popped up in response to a keystroke, center it
+ * below the headers of the tree-view.
+ */
+static void
+bndx_popup_position_func(GtkMenu * menu, gint * x, gint * y,
+                         gboolean * push_in, gpointer user_data)
+{
+    GtkWidget *bindex = GTK_WIDGET(user_data);
+    GdkScreen *screen = gtk_widget_get_screen(bindex);
+    GtkRequisition req;
+    gint monitor_num;
+    GdkRectangle monitor;
+
+    g_return_if_fail(GTK_WIDGET_REALIZED(bindex));
+
+    gdk_window_get_origin(gtk_tree_view_get_bin_window
+                          (GTK_TREE_VIEW(bindex)), x, y);
+
+    gtk_widget_size_request(GTK_WIDGET(menu), &req);
+
+    *x += (bindex->allocation.width - req.width) / 2;
+
+    monitor_num = gdk_screen_get_monitor_at_point(screen, *x, *y);
+    gtk_menu_set_monitor(menu, monitor_num);
+    gdk_screen_get_monitor_geometry(screen, monitor_num, &monitor);
+
+    *x = CLAMP(*x, monitor.x,
+               monitor.x + MAX(0, monitor.width - req.width));
+    *y = CLAMP(*y, monitor.y,
+               monitor.y + MAX(0, monitor.height - req.height));
+
+    *push_in = FALSE;
+}
+
 static void
 bndx_do_popup(BalsaIndex * index, GdkEventButton * event)
 {
@@ -1866,8 +1901,6 @@
     gboolean any;
     gboolean any_deleted = FALSE;
     gboolean any_not_deleted = FALSE;
-    gint event_button;
-    guint event_time;
     GArray *selected = balsa_index_selected_msgnos_new(index);
     guint i;
 
@@ -1914,15 +1947,13 @@
 
     gtk_widget_show_all(menu);
 
-    if (event) {
-        event_button = event->button;
-        event_time = event->time;
-    } else {
-        event_button = 0;
-        event_time = gtk_get_current_event_time();
-    }
-    gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL,
-                   event_button, event_time);
+    if (event)
+        gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL,
+                       event->button, event->time);
+    else
+        gtk_menu_popup(GTK_MENU(menu), NULL, NULL,
+                       bndx_popup_position_func, index,
+                       0, gtk_get_current_event_time());
 }
 
 static GtkWidget *

Modified: branches/mailbox-gsequence/src/balsa-mblist.c
==============================================================================
--- branches/mailbox-gsequence/src/balsa-mblist.c	(original)
+++ branches/mailbox-gsequence/src/balsa-mblist.c	Thu Feb 28 02:41:51 2008
@@ -956,7 +956,9 @@
     if (event->type != GDK_BUTTON_PRESS
             /* keyboard navigation */
         || event->button.button != 1
-            /* soft select */ ) {
+            /* soft select */
+        || event->button.window != gtk_tree_view_get_bin_window(tree_view)
+            /* click on a different widget */ ) {
         gdk_event_free(event);
         return;
     }
@@ -2342,6 +2344,24 @@
 /* Make a new row for mbnode in balsa_app.mblist_tree_store; the row
  * will be a child to the row for root, if we find it, and a top-level
  * row otherwise. */
+static gboolean
+bmbl_sort_idle(gpointer data)
+{
+    GtkTreeSortable *sortable = data;
+
+    gdk_threads_enter();
+
+    gtk_tree_sortable_set_sort_column_id(sortable,
+                                         balsa_app.mblist->sort_column_id,
+                                         GTK_SORT_ASCENDING);
+    balsa_app.mblist->sort_idle_id = 0;
+    g_object_unref(sortable);
+
+    gdk_threads_leave();
+
+    return FALSE;
+}
+
 void 
 balsa_mblist_mailbox_node_append(BalsaMailboxNode * root,
 				 BalsaMailboxNode * mbnode)
@@ -2354,9 +2374,21 @@
     gdk_threads_enter();
 
     model = GTK_TREE_MODEL(balsa_app.mblist_tree_store);
+
+    if (!balsa_app.mblist->sort_idle_id) {
+        GtkTreeSortable *sortable = GTK_TREE_SORTABLE(model);
+        gtk_tree_sortable_get_sort_column_id
+            (sortable, &balsa_app.mblist->sort_column_id, NULL);
+        gtk_tree_sortable_set_sort_column_id
+            (sortable, GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID,
+                       GTK_SORT_ASCENDING);
+        balsa_app.mblist->sort_idle_id =
+            g_idle_add(bmbl_sort_idle, g_object_ref(sortable));
+    }
+
     if (root && balsa_find_iter_by_data(&parent, root))
 	parent_iter = &parent;
-    gtk_tree_store_append(balsa_app.mblist_tree_store, &iter, parent_iter);
+    gtk_tree_store_prepend(balsa_app.mblist_tree_store, &iter, parent_iter);
     bmbl_store_redraw_mbnode(&iter, mbnode);
 
     if (parent_iter) {

Modified: branches/mailbox-gsequence/src/balsa-mblist.h
==============================================================================
--- branches/mailbox-gsequence/src/balsa-mblist.h	(original)
+++ branches/mailbox-gsequence/src/balsa-mblist.h	Thu Feb 28 02:41:51 2008
@@ -40,6 +40,10 @@
     gboolean display_info;
     /* signal handler id */
     gulong toggled_handler_id;
+
+    /* to set sort order in an idle callback */
+    gint  sort_column_id;
+    guint sort_idle_id;
 };
 
 struct _BalsaMBListClass {

Modified: branches/mailbox-gsequence/src/balsa-message.c
==============================================================================
--- branches/mailbox-gsequence/src/balsa-message.c	(original)
+++ branches/mailbox-gsequence/src/balsa-message.c	Thu Feb 28 02:41:51 2008
@@ -54,6 +54,24 @@
 #  include "gmime-part-rfc2440.h"
 #endif
 
+#if HAVE_GTKSOURCEVIEW
+/* Use GtkSourceIter's case-insensitive search functions. */
+#  include <gtksourceview/gtksourceiter.h>
+#  define FORWARD_SEARCH(iter, text, match_begin, match_end)            \
+    gtk_source_iter_forward_search((iter), (text),                      \
+    GTK_SOURCE_SEARCH_CASE_INSENSITIVE, (match_begin), (match_end), NULL)
+#  define BACKWARD_SEARCH(iter, text, match_begin, match_end)           \
+    gtk_source_iter_backward_search((iter), (text),                     \
+    GTK_SOURCE_SEARCH_CASE_INSENSITIVE, (match_begin), (match_end), NULL)
+#else                           /* HAVE_GTKSOURCEVIEW */
+#  define FORWARD_SEARCH(iter, text, match_begin, match_end)            \
+    gtk_text_iter_forward_search((iter), (text),                        \
+    0, (match_begin), (match_end), NULL)
+#  define BACKWARD_SEARCH(iter, text, match_begin, match_end)           \
+    gtk_text_iter_backward_search((iter), (text),                       \
+    0, (match_begin), (match_end), NULL)
+#endif                          /* HAVE_GTKSOURCEVIEW */
+
 enum {
     SELECT_PART,
     LAST_SIGNAL,
@@ -368,9 +386,258 @@
     gtk_container_foreach (GTK_CONTAINER(widget), balsa_mime_widget_image_resize_all, NULL);
 }
 
+/*
+ * Callbacks and helpers for the find bar.
+ */
+
+typedef enum {
+    BM_FIND_STATUS_INIT,
+    BM_FIND_STATUS_FOUND,
+    BM_FIND_STATUS_WRAPPED,
+    BM_FIND_STATUS_NOT_FOUND
+} BalsaMessageFindStatus;
+
+static void
+bm_find_set_status(BalsaMessage * bm, BalsaMessageFindStatus status)
+{
+    const gchar *text = "";
+    gboolean sensitive = FALSE;
+
+    switch (status) {
+        default:
+        case BM_FIND_STATUS_INIT:
+            break;
+        case BM_FIND_STATUS_FOUND:
+            sensitive = TRUE;
+            break;
+        case BM_FIND_STATUS_WRAPPED:
+            text = _("Wrapped");
+            sensitive = TRUE;
+            break;
+        case BM_FIND_STATUS_NOT_FOUND:
+            text = _("Not found");
+            break;
+    }
+
+    gtk_label_set_text(GTK_LABEL(bm->find_label), text);
+    gtk_separator_tool_item_set_draw(GTK_SEPARATOR_TOOL_ITEM
+                                     (bm->find_sep), text[0] != '\0');
+    gtk_widget_set_sensitive(bm->find_prev, sensitive);
+    gtk_widget_set_sensitive(bm->find_next, sensitive);
+}
+
+static void
+bm_find_scroll_to_iter(BalsaMessage * bm,
+                       GtkTextView  * text_view,
+                       GtkTextIter  * iter)
+{
+    GtkAdjustment *adj = GTK_VIEWPORT(bm->cont_viewport)->vadjustment;
+    GdkRectangle location;
+    gdouble y;
+
+    gtk_text_view_get_iter_location(text_view, iter, &location);
+    gtk_text_view_buffer_to_window_coords(text_view,
+                                          GTK_TEXT_WINDOW_WIDGET,
+                                          location.x, location.y,
+                                          NULL, &location.y);
+    gtk_widget_translate_coordinates(GTK_WIDGET(text_view),
+                                     bm->bm_widget->widget,
+                                     location.x, location.y,
+                                     NULL, &location.y);
+
+    y = location.y;
+    gtk_adjustment_clamp_page(adj, y, y + location.height);
+}
+
+static void
+bm_find_entry_changed_cb(GtkEditable * editable, gpointer data)
+{
+    const gchar *text = gtk_entry_get_text(GTK_ENTRY(editable));
+    BalsaMessage *bm = data;
+    GtkTextView *text_view =
+        GTK_TEXT_VIEW(bm->current_part->mime_widget->widget);
+    GtkTextBuffer *buffer = gtk_text_view_get_buffer(text_view);
+    GtkTextIter match_begin, match_end;
+    gboolean found;
+
+    if (bm->find_forward) {
+        found = FORWARD_SEARCH(&bm->find_iter, text,
+                               &match_begin, &match_end);
+        if (!found) {
+            /* Silently wrap to the top. */
+            gtk_text_buffer_get_start_iter(buffer, &bm->find_iter);
+            found = FORWARD_SEARCH(&bm->find_iter, text,
+                                   &match_begin, &match_end);
+        }
+    } else {
+        found = BACKWARD_SEARCH(&bm->find_iter, text,
+                                &match_begin, &match_end);
+        if (!found) {
+            /* Silently wrap to the bottom. */
+            gtk_text_buffer_get_end_iter(buffer, &bm->find_iter);
+            found = BACKWARD_SEARCH(&bm->find_iter, text,
+                                    &match_begin, &match_end);
+        }
+    }
+
+    if (found) {
+        gtk_text_buffer_select_range(buffer, &match_begin, &match_end);
+        bm_find_scroll_to_iter(bm, text_view, &match_begin);
+        bm->find_iter = match_begin;
+    }
+    bm_find_set_status(bm, found ?
+                       BM_FIND_STATUS_FOUND : BM_FIND_STATUS_NOT_FOUND);
+}
+
+static void
+bm_find_again(BalsaMessage * bm, gboolean find_forward)
+{
+    const gchar *text = gtk_entry_get_text(GTK_ENTRY(bm->find_entry));
+    GtkTextView *text_view =
+        GTK_TEXT_VIEW(bm->current_part->mime_widget->widget);
+    GtkTextBuffer *buffer = gtk_text_view_get_buffer(text_view);
+    GtkTextIter match_begin, match_end;
+    gboolean found;
+
+    if (find_forward) {
+        gtk_text_iter_forward_char(&bm->find_iter);
+        found = FORWARD_SEARCH(&bm->find_iter, text,
+                               &match_begin, &match_end);
+        if (!found) {
+            gtk_text_buffer_get_start_iter(buffer, &bm->find_iter);
+            found = FORWARD_SEARCH(&bm->find_iter, text,
+                                   &match_begin, &match_end);
+        }
+    } else {
+        gtk_text_iter_backward_char(&bm->find_iter);
+        found = BACKWARD_SEARCH(&bm->find_iter, text,
+                                &match_begin, &match_end);
+        if (!found) {
+            gtk_text_buffer_get_end_iter(buffer, &bm->find_iter);
+            found = BACKWARD_SEARCH(&bm->find_iter, text,
+                                    &match_begin, &match_end);
+        }
+    }
+    bm_find_set_status(bm, found ?
+                       BM_FIND_STATUS_FOUND : BM_FIND_STATUS_WRAPPED);
+
+    gtk_text_buffer_select_range(buffer, &match_begin, &match_end);
+    bm_find_scroll_to_iter(bm, text_view, &match_begin);
+    bm->find_iter = match_begin;
+    bm->find_forward = find_forward;
+}
+
+static void
+bm_find_prev_cb(GtkToolButton * prev_button, gpointer data)
+{
+    bm_find_again((BalsaMessage *) data, FALSE);
+}
+
+static void
+bm_find_next_cb(GtkToolButton * prev_button, gpointer data)
+{
+    bm_find_again((BalsaMessage *) data, TRUE);
+}
+
+static GtkWidget *
+bm_find_bar_new(BalsaMessage * bm)
+{
+    GtkWidget *toolbar;
+    GtkWidget *hbox;
+    GtkToolItem *tool_item;
+
+    toolbar = gtk_toolbar_new();
+    gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), GTK_TOOLBAR_BOTH_HORIZ);
+
+    hbox = gtk_hbox_new(FALSE, 6);
+    gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new(_("Find:")),
+                       FALSE, FALSE, 0);
+    bm->find_entry = gtk_entry_new();
+    g_signal_connect(bm->find_entry, "changed",
+                     G_CALLBACK(bm_find_entry_changed_cb), bm);
+    gtk_box_pack_start(GTK_BOX(hbox), bm->find_entry, FALSE, FALSE, 0);
+
+    tool_item = gtk_tool_item_new();
+    gtk_container_add(GTK_CONTAINER(tool_item), hbox);
+    gtk_toolbar_insert(GTK_TOOLBAR(toolbar), tool_item, -1);
+
+    tool_item =
+        gtk_tool_button_new(gtk_arrow_new(GTK_ARROW_LEFT, GTK_SHADOW_NONE),
+                            _("Previous"));
+    bm->find_prev = GTK_WIDGET(tool_item);
+    gtk_tool_item_set_is_important(tool_item, TRUE);
+    g_signal_connect(tool_item, "clicked", G_CALLBACK(bm_find_prev_cb), bm);
+    gtk_toolbar_insert(GTK_TOOLBAR(toolbar), tool_item, -1);
+
+    tool_item =
+        gtk_tool_button_new(gtk_arrow_new(GTK_ARROW_RIGHT, GTK_SHADOW_NONE),
+                            _("Next"));
+    bm->find_next = GTK_WIDGET(tool_item);
+    gtk_tool_item_set_is_important(tool_item, TRUE);
+    g_signal_connect(tool_item, "clicked", G_CALLBACK(bm_find_next_cb), bm);
+    gtk_toolbar_insert(GTK_TOOLBAR(toolbar), tool_item, -1);
+
+    bm->find_sep = GTK_WIDGET(gtk_separator_tool_item_new());
+    gtk_toolbar_insert(GTK_TOOLBAR(toolbar), GTK_TOOL_ITEM(bm->find_sep), -1);
+
+    bm->find_label = gtk_label_new("");
+    tool_item = gtk_tool_item_new();
+    gtk_container_add(GTK_CONTAINER(tool_item), bm->find_label);
+    gtk_toolbar_insert(GTK_TOOLBAR(toolbar), tool_item, -1);
+
+    gtk_widget_hide(toolbar);
+
+    return toolbar;
+}
+
+static void bm_disable_find_entry(BalsaMessage * bm);
+
+static gboolean
+bm_find_pass_to_entry(BalsaMessage * bm, GdkEventKey * event)
+{
+    gboolean res = TRUE;
+
+    switch (event->keyval) {
+    case GDK_Escape:
+    case GDK_Return:
+    case GDK_KP_Enter:
+        bm_disable_find_entry(bm);
+        return res;
+    case GDK_g:
+        if ((event->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK)) ==
+            GDK_CONTROL_MASK && GTK_WIDGET_SENSITIVE(bm->find_next)) {
+            bm_find_again(bm, bm->find_forward);
+            return res;
+        }
+    default:
+        break;
+    }
+
+    res = FALSE;
+    if (GTK_WIDGET_HAS_FOCUS(bm->find_entry))
+        g_signal_emit_by_name(bm->find_entry, "key-press-event", event,
+                              &res, NULL);
+
+    return res;
+}
+
+static void
+bm_disable_find_entry(BalsaMessage * bm)
+{
+    g_signal_handlers_disconnect_by_func
+        (gtk_widget_get_toplevel(GTK_WIDGET(bm)),
+         G_CALLBACK(bm_find_pass_to_entry), bm);
+    gtk_widget_hide(bm->find_bar);
+}
+
+/*
+ * End of callbacks and helpers for the find bar.
+ */
+
 static void
 balsa_message_init(BalsaMessage * bm)
 {
+    GtkWidget *vbox;
     GtkWidget *scroll;
     GtkWidget *label;
     GtkTreeStore *model;
@@ -379,6 +646,11 @@
 
     gtk_notebook_set_show_border(GTK_NOTEBOOK(bm), FALSE);
 
+    /* Box to hold the scrolled window and the find bar */
+    vbox = gtk_vbox_new(FALSE, 0);
+    label = gtk_label_new(_("Content"));
+    gtk_notebook_append_page(GTK_NOTEBOOK(bm), vbox, label);
+
     /* scrolled window for the contents */
     bm->scroll = scroll = gtk_scrolled_window_new(NULL, NULL);
     gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll),
@@ -386,8 +658,7 @@
                                    GTK_POLICY_AUTOMATIC);
     g_signal_connect(scroll, "key_press_event",
 		     G_CALLBACK(balsa_mime_widget_key_press_event), bm);
-    label = gtk_label_new(_("Content"));
-    gtk_notebook_append_page(GTK_NOTEBOOK(bm), scroll, label);
+    gtk_box_pack_start(GTK_BOX(vbox), scroll, TRUE, TRUE, 0);
     bm->cont_viewport = gtk_viewport_new(NULL, NULL);
     gtk_container_add(GTK_CONTAINER(scroll), bm->cont_viewport);
     gtk_widget_show_all(scroll);
@@ -396,6 +667,10 @@
     g_signal_connect(bm->cont_viewport, "size-allocate",
 		     G_CALLBACK(on_content_size_alloc), NULL);
 
+    /* Find-in-message toolbar */
+    bm->find_bar = bm_find_bar_new(bm);
+    gtk_box_pack_start(GTK_BOX(vbox), bm->find_bar, FALSE, FALSE, 0);
+
     /* Widget to hold headers */
     bm->bm_widget = balsa_mime_widget_new_message_tl(bm, bm_header_tl_buttons(bm));
 
@@ -480,6 +755,9 @@
     bm->shown_headers = balsa_app.shown_headers;
     bm->show_all_headers = FALSE;
     bm->close_with_msg = FALSE;
+
+    gtk_widget_show_all(GTK_WIDGET(bm));
+    gtk_widget_hide(bm->find_bar);
 }
 
 static void
@@ -778,6 +1056,7 @@
     g_return_val_if_fail(bm != NULL, FALSE);
 
     gtk_widget_hide(GTK_WIDGET(bm));
+    bm_disable_find_entry(bm);
     select_part(bm, NULL);
     if (bm->message != NULL) {
         libbalsa_message_body_unref(bm->message);
@@ -2857,3 +3136,32 @@
 }
 
 #endif  /* HAVE_GPGME */
+
+/*
+ * Public method for find-in-message.
+ */
+
+void
+balsa_message_find_in_message(BalsaMessage * bm)
+{
+    GtkWidget *w;
+
+    if (bm->current_part
+        && (w = bm->current_part->mime_widget->widget)
+        && GTK_IS_TEXT_VIEW(w)) {
+        GtkTextView *text_view = (GtkTextView *) w;
+        GtkTextBuffer *buffer = gtk_text_view_get_buffer(text_view);
+
+        bm->find_forward = TRUE;
+        gtk_text_buffer_get_start_iter(buffer, &bm->find_iter);
+        gtk_entry_set_text(GTK_ENTRY(bm->find_entry), "");
+        g_signal_connect_swapped(gtk_widget_get_toplevel(GTK_WIDGET(bm)),
+                                 "key-press-event",
+                                 G_CALLBACK(bm_find_pass_to_entry), bm);
+
+        bm_find_set_status(bm, BM_FIND_STATUS_INIT);
+
+        gtk_widget_show(bm->find_bar);
+        gtk_widget_grab_focus(bm->find_entry);
+    }
+}

Modified: branches/mailbox-gsequence/src/balsa-message.h
==============================================================================
--- branches/mailbox-gsequence/src/balsa-message.h	(original)
+++ branches/mailbox-gsequence/src/balsa-message.h	Thu Feb 28 02:41:51 2008
@@ -80,6 +80,16 @@
 	gboolean close_with_msg;
 
         BalsaMessageFocusState focus_state;
+
+        /* Find-in-message stuff */
+        GtkWidget  *find_bar;
+        GtkWidget  *find_entry;
+        GtkWidget  *find_next;
+        GtkWidget  *find_prev;
+        GtkWidget  *find_sep;
+        GtkWidget  *find_label;
+        GtkTextIter find_iter;
+        gboolean    find_forward;
 };
 
 struct _BalsaMessageClass {
@@ -125,6 +135,8 @@
 				  guint max_ref);
 #endif
 
+void balsa_message_find_in_message (BalsaMessage * bm);
+
 #ifdef __cplusplus
 }
 #endif				/* __cplusplus */

Modified: branches/mailbox-gsequence/src/filter-edit-callbacks.c
==============================================================================
--- branches/mailbox-gsequence/src/filter-edit-callbacks.c	(original)
+++ branches/mailbox-gsequence/src/filter-edit-callbacks.c	Thu Feb 28 02:41:51 2008
@@ -48,10 +48,12 @@
 extern option_list fe_search_type[4];
 extern GList * fe_user_headers_list;
 
+#if REGULAR_EXPRESSION_FILTERING_IS_IMPLEMENTED
 static void fe_add_pressed(GtkWidget * widget, gpointer throwaway);
 static void fe_remove_pressed(GtkWidget * widget, gpointer throwaway);
 static void fe_regexs_selection_changed(GtkTreeSelection * selection,
                                         gpointer user_data);
+#endif                  /* REGULAR_EXPRESSION_FILTERING_IS_IMPLEMENTED */
 static void fe_free_associated_filters(void);
 static void fe_free_associated_conditions(void);
 static GtkWidget *fe_date_sample(void);
@@ -242,6 +244,7 @@
 
 /**************** Conditions *************************/
 
+#if REGULAR_EXPRESSION_FILTERING_IS_IMPLEMENTED
 /* Callback function to fill the regex entry with the selected regex */
 
 static void
@@ -262,6 +265,7 @@
     else gtk_entry_set_text(GTK_ENTRY(fe_type_regex_entry),"");
     gtk_widget_set_sensitive(fe_regex_remove_button, selected);
 }
+#endif                  /* REGULAR_EXPRESSION_FILTERING_IS_IMPLEMENTED */
 
 /* Helper. */
 static gint
@@ -293,11 +297,16 @@
 
     switch (type) {
     case CONDITION_STRING:
+#if REGULAR_EXPRESSION_FILTERING_IS_IMPLEMENTED
     case CONDITION_REGEX:
+#endif                  /* REGULAR_EXPRESSION_FILTERING_IS_IMPLEMENTED */
         gtk_widget_show(field_frame);
         break;
     case CONDITION_DATE:
     case CONDITION_FLAG:
+#if !REGULAR_EXPRESSION_FILTERING_IS_IMPLEMENTED
+    case CONDITION_REGEX:
+#endif                  /* REGULAR_EXPRESSION_FILTERING_IS_IMPLEMENTED */
         gtk_widget_hide(field_frame);
     default:
         break;
@@ -480,9 +489,11 @@
     const gchar *c_str;
     gint row, col;
     struct tm date;
+#if REGULAR_EXPRESSION_FILTERING_IS_IMPLEMENTED
     GtkTreeModel *model =
         gtk_tree_view_get_model(fe_type_regex_list);
     GtkTreeIter iter;
+#endif                  /* REGULAR_EXPRESSION_FILTERING_IS_IMPLEMENTED */
 
 
     /* Sanity checks, prevent "empty" condition */
@@ -535,12 +546,14 @@
         }
         break;
     case CONDITION_REGEX:
+#if REGULAR_EXPRESSION_FILTERING_IS_IMPLEMENTED
         if (!gtk_tree_model_get_iter_first(model, &iter)) {
             balsa_information(LIBBALSA_INFORMATION_ERROR,
                               _("You must provide at least one "
                                 "regular expression"));
             return FALSE;
         }
+#endif                  /* REGULAR_EXPRESSION_FILTERING_IS_IMPLEMENTED */
         break;
     case CONDITION_DATE:
         c_str = gtk_entry_get_text(GTK_ENTRY(fe_type_date_low_entry));
@@ -629,12 +642,16 @@
 static void
 clear_condition_widgets()
 {
+#if REGULAR_EXPRESSION_FILTERING_IS_IMPLEMENTED
     GtkTreeModel *model =
         gtk_tree_view_get_model(fe_type_regex_list);
+#endif                  /* REGULAR_EXPRESSION_FILTERING_IS_IMPLEMENTED */
 
     gtk_entry_set_text(GTK_ENTRY(fe_type_simple_entry),"");
+#if REGULAR_EXPRESSION_FILTERING_IS_IMPLEMENTED
     gtk_entry_set_text(GTK_ENTRY(fe_type_regex_entry),"");          
     gtk_list_store_clear(GTK_LIST_STORE(model));
+#endif                  /* REGULAR_EXPRESSION_FILTERING_IS_IMPLEMENTED */
     gtk_entry_set_text(GTK_ENTRY(fe_type_date_low_entry),"");
     gtk_entry_set_text(GTK_ENTRY(fe_type_date_high_entry),"");
 }
@@ -682,8 +699,10 @@
 static void
 fill_condition_widgets(LibBalsaCondition* cnd)
 {
+#if REGULAR_EXPRESSION_FILTERING_IS_IMPLEMENTED
     GtkTreeModel *model =
         gtk_tree_view_get_model(fe_type_regex_list);
+#endif                  /* REGULAR_EXPRESSION_FILTERING_IS_IMPLEMENTED */
     gchar str[20];
     struct tm date;
     gint row,col;
@@ -698,7 +717,9 @@
     if (cnd->type!=CONDITION_REGEX)
         gtk_entry_set_text(GTK_ENTRY(fe_type_regex_entry),"");      
 
+#if REGULAR_EXPRESSION_FILTERING_IS_IMPLEMENTED
     gtk_list_store_clear(GTK_LIST_STORE(model));
+#endif                  /* REGULAR_EXPRESSION_FILTERING_IS_IMPLEMENTED */
 
     gtk_notebook_set_current_page(GTK_NOTEBOOK(fe_type_notebook),
                                   cnd->type - 1);
@@ -938,7 +959,11 @@
 build_type_notebook()
 {
     GtkWidget *page,*frame;
+#if REGULAR_EXPRESSION_FILTERING_IS_IMPLEMENTED
     GtkWidget *scroll;
+#else                   /* REGULAR_EXPRESSION_FILTERING_IS_IMPLEMENTED */
+    const gchar *msg;
+#endif                  /* REGULAR_EXPRESSION_FILTERING_IS_IMPLEMENTED */
     GtkWidget *box;
     GtkWidget *button, *table;
     gint row,col;
@@ -986,11 +1011,12 @@
     /* The regex page of the type notebook */
     box = gtk_vbox_new(FALSE, 5);
 
+    gtk_notebook_append_page(GTK_NOTEBOOK(fe_type_notebook), box, NULL);
+
+#if REGULAR_EXPRESSION_FILTERING_IS_IMPLEMENTED
     page = gtk_table_new(5, 6, FALSE);
     gtk_box_pack_start_defaults(GTK_BOX(box), page);
 
-    gtk_notebook_append_page(GTK_NOTEBOOK(fe_type_notebook), box, NULL);
-
     fe_type_regex_label = 
         gtk_label_new_with_mnemonic(_("_One of the regular expressions matches"));
     gtk_table_attach(GTK_TABLE(page),
@@ -1037,6 +1063,10 @@
                      fe_type_regex_entry,
                      0, 5, 5, 6,
                      GTK_FILL | GTK_SHRINK | GTK_EXPAND, GTK_SHRINK, 2, 2);
+#else                   /* REGULAR_EXPRESSION_FILTERING_IS_IMPLEMENTED */
+    msg = _("Filtering using regular expressions is not yet implemented.");
+    gtk_box_pack_start_defaults(GTK_BOX(box), gtk_label_new(msg));
+#endif                  /* REGULAR_EXPRESSION_FILTERING_IS_IMPLEMENTED */
 
     /* The date page of the notebook */
 
@@ -1506,6 +1536,7 @@
     set_button_sensitivities(TRUE);
 }
 
+#if REGULAR_EXPRESSION_FILTERING_IS_IMPLEMENTED
 /*
  * fe_add_pressed()
  *
@@ -1559,6 +1590,7 @@
     gtk_tree_path_free(path);
     condition_has_changed=TRUE;
 }                       /* end fe_remove_pressed() */
+#endif                  /* REGULAR_EXPRESSION_FILTERING_IS_IMPLEMENTED */
 
 /************************************************************/
 /******** Functions handling filters ************************/

Modified: branches/mailbox-gsequence/src/mailbox-conf.c
==============================================================================
--- branches/mailbox-gsequence/src/mailbox-conf.c	(original)
+++ branches/mailbox-gsequence/src/mailbox-conf.c	Thu Feb 28 02:41:51 2008
@@ -53,6 +53,8 @@
 
 #include "libbalsa.h"
 #include "imap-server.h"
+#include "mailbox-filter.h"
+#include "libbalsa-conf.h"
 #include <glib/gi18n.h>
 
 struct _BalsaMailboxConfView {
@@ -371,6 +373,7 @@
     gint button;
     GtkWidget *ask;
     LibBalsaMailbox* mailbox = mbnode->mailbox;
+    gchar *url, *group;
 
     if(BALSA_IS_MAILBOX_SPECIAL(mailbox)) {
 	balsa_information(
@@ -449,6 +452,9 @@
     if ( button < 0)
 	return;
 
+    /* Save the mailbox URL */
+    url = g_strdup(mailbox->url ? mailbox->url : mailbox->name);
+
     /* Delete it from the config file and internal nodes */
     config_mailbox_delete(mailbox);
 
@@ -492,6 +498,18 @@
     } else
 	balsa_mblist_mailbox_node_remove(mbnode);
     update_mail_servers();
+
+    /* Clean up filters */
+    group = mailbox_filters_section_lookup(url);
+    if (group) {
+        libbalsa_conf_remove_group(group);
+        g_free(group);
+    }
+
+    /* Remove view */
+    config_view_remove(url);
+
+    g_free(url);
 }
 
 #define MCW_RESPONSE 1

Modified: branches/mailbox-gsequence/src/mailbox-node.c
==============================================================================
--- branches/mailbox-gsequence/src/mailbox-node.c	(original)
+++ branches/mailbox-gsequence/src/mailbox-node.c	Thu Feb 28 02:41:51 2008
@@ -1215,7 +1215,9 @@
 	    g_print(_("Local mailbox %s loaded as: %s\n"),
 		    mailbox->name,
 		    g_type_name(G_OBJECT_TYPE(mailbox)));
-	if (balsa_app.check_mail_upon_startup) {
+        if (balsa_app.check_mail_upon_startup
+            && libbalsa_mailbox_get_subscribe(mailbox) !=
+            LB_MAILBOX_SUBSCRIBE_NO) {
             g_object_ref(mailbox);
             g_idle_add((GSourceFunc) mailbox_check_idle, mailbox);
         }

Modified: branches/mailbox-gsequence/src/main-window.c
==============================================================================
--- branches/mailbox-gsequence/src/main-window.c	(original)
+++ branches/mailbox-gsequence/src/main-window.c	Thu Feb 28 02:41:51 2008
@@ -194,6 +194,7 @@
 #if !defined(ENABLE_TOUCH_UI)
 static void bw_message_copy_cb            (GtkAction * action, gpointer data);
 static void bw_message_select_all_cb      (GtkAction * action, gpointer data);
+static void bw_find_in_message_cb         (GtkAction * action, gpointer data);
 #endif /* ENABLE_TOUCH_UI */
 static void bw_mark_all_cb                (GtkAction * action, gpointer data);
 
@@ -521,7 +522,10 @@
     {"CopyMessage", GTK_STOCK_COPY, N_("_Copy"), "<control>C",
      N_("Copy message"), G_CALLBACK(bw_message_copy_cb)},
     {"SelectText", NULL, N_("_Select Text"), NULL,
-     N_("Select entire mail"), G_CALLBACK(bw_message_select_all_cb)}
+     N_("Select entire mail"), G_CALLBACK(bw_message_select_all_cb)},
+    {"FindInMessage", NULL, N_("_Find in message"), "slash",
+     N_("Find a string in this message"),
+     G_CALLBACK(bw_find_in_message_cb)}
 #endif /* ENABLE_TOUCH_UI */
 };
 
@@ -669,6 +673,7 @@
 "      <separator/>"
 "      <menuitem action='Find'/>"
 "      <menuitem action='FindNext'/>"
+"      <menuitem action='FindInMessage'/>"
 "      <separator/>"
 "      <menuitem action='Filters'/>"
 "      <menuitem action='ExportFilters'/>"
@@ -1511,6 +1516,7 @@
 
     window = g_object_new(BALSA_TYPE_WINDOW, NULL);
     window->vbox = gtk_vbox_new(FALSE, 0);
+    gtk_widget_show(window->vbox);
     gtk_container_add(GTK_CONTAINER(window), window->vbox);
 
     gtk_window_set_title(GTK_WINDOW(window), "Balsa");
@@ -1559,6 +1565,7 @@
                      G_CALLBACK(bw_window_state_event_cb),
                      window->statusbar);
     gtk_box_pack_start(GTK_BOX(hbox), window->statusbar, TRUE, TRUE, 0);
+    gtk_widget_show_all(hbox);
 
 #if 0
     gnome_app_install_appbar_menu_hints(GNOME_APPBAR(balsa_app.appbar),
@@ -1696,7 +1703,7 @@
                      G_CALLBACK(bw_cancel_new_mail_notification), NULL);
 #endif
 
-    gtk_widget_show_all(GTK_WIDGET(window));
+    gtk_widget_show(GTK_WIDGET(window));
     return GTK_WIDGET(window);
 }
 
@@ -4168,6 +4175,14 @@
 }
 
 static void
+bw_find_in_message_cb(GtkAction * action,gpointer data)
+{
+    BalsaWindow *window = data;
+    if (balsa_app.previewpane)
+        balsa_message_find_in_message(BALSA_MESSAGE(window->preview));
+}
+
+static void
 bw_filter_dlg_cb(GtkAction * action, gpointer data)
 {
     filters_edit_dialog();

Modified: branches/mailbox-gsequence/src/message-window.c
==============================================================================
--- branches/mailbox-gsequence/src/message-window.c	(original)
+++ branches/mailbox-gsequence/src/message-window.c	Thu Feb 28 02:41:51 2008
@@ -58,6 +58,7 @@
 
 static void copy_cb                    (GtkAction * action, MessageWindow * mw);
 static void select_all_cb              (GtkAction * action, gpointer);
+static void mw_find_in_message_cb      (GtkAction * action, gpointer data);
 
 static void mw_header_activate_cb      (GtkAction * action, gpointer data);
 
@@ -251,6 +252,9 @@
      G_CALLBACK(copy_cb)},
     {"SelectAll", NULL, N_("Select _All"), "<control>A", NULL,
      G_CALLBACK(select_all_cb)},
+    {"FindInMessage", NULL, N_("_Find in message"), "slash",
+     N_("Find a string in this message"),
+     G_CALLBACK(mw_find_in_message_cb)},
 #ifdef HAVE_GTKHTML
     {"ZoomIn", GTK_STOCK_ZOOM_IN, N_("Zoom _In"), "<control>plus",
      N_("Increase magnification"), G_CALLBACK(mw_zoom_in_cb)},
@@ -339,6 +343,8 @@
 "    <menu action='EditMenu'>"
 "      <menuitem action='Copy'/>"
 "      <menuitem action='SelectAll'/>"
+"      <separator/>"
+"      <menuitem action='FindInMessage'/>"
 "    </menu>"
 "    <menu action='ViewMenu'>"
 "      <menuitem action='Wrap'/>"
@@ -883,6 +889,14 @@
 }
 
 static void
+mw_find_in_message_cb(GtkAction * action, gpointer data)
+{
+    MessageWindow *mw = (MessageWindow *) (data);
+
+    balsa_message_find_in_message(BALSA_MESSAGE(mw->bmessage));
+}
+
+static void
 mw_set_selected(MessageWindow * mw, void (*select_func) (BalsaIndex *))
 {
     guint msgno;

Modified: branches/mailbox-gsequence/src/save-restore.c
==============================================================================
--- branches/mailbox-gsequence/src/save-restore.c	(original)
+++ branches/mailbox-gsequence/src/save-restore.c	Thu Feb 28 02:41:51 2008
@@ -1830,22 +1830,33 @@
                                 GINT_TO_POINTER(FALSE));
 }
 
+/* Get viewByUrl prefix */
+static gchar *
+view_by_url_prefix(const gchar * url)
+{
+    gchar *url_enc;
+    gchar *prefix;
+
+    url_enc = libbalsa_urlencode(url);
+    prefix = g_strconcat(VIEW_BY_URL_SECTION_PREFIX, url_enc, NULL);
+    g_free(url_enc);
+
+    return prefix;
+}
+
 /* config_views_save:
    iterates over all mailbox views.
 */
 static void
 save_view(const gchar * url, LibBalsaMailboxView * view)
 {
-    gchar *url_enc;
     gchar *prefix;
 
     if (!view || (view->in_sync && view->used))
 	return;
     view->in_sync = TRUE;
 
-    url_enc = libbalsa_urlencode(url);
-    prefix = g_strconcat(VIEW_BY_URL_SECTION_PREFIX, url_enc, NULL);
-    g_free(url_enc);
+    prefix = view_by_url_prefix(url);
 
     /* Remove the view--it will be recreated if any member needs to be
      * saved. */
@@ -1911,6 +1922,15 @@
 			 NULL);
 }
 
+void
+config_view_remove(const gchar * url)
+{
+    gchar *prefix = view_by_url_prefix(url);
+    libbalsa_conf_remove_group(prefix);
+    g_free(prefix);
+    g_hash_table_remove(libbalsa_mailbox_view_table, url);
+}
+
 static void
 save_color(gchar * key, GdkColor * color)
 {

Modified: branches/mailbox-gsequence/src/save-restore.h
==============================================================================
--- branches/mailbox-gsequence/src/save-restore.h	(original)
+++ branches/mailbox-gsequence/src/save-restore.h	Thu Feb 28 02:41:51 2008
@@ -57,6 +57,7 @@
 void config_identities_save(void);
 void config_views_load(void);
 void config_views_save(void);
+void config_view_remove(const gchar * url);
 
 void config_filters_save(void);
 void config_mailbox_filters_save(LibBalsaMailbox * mbox);

Modified: branches/mailbox-gsequence/src/sendmsg-window.c
==============================================================================
--- branches/mailbox-gsequence/src/sendmsg-window.c	(original)
+++ branches/mailbox-gsequence/src/sendmsg-window.c	Thu Feb 28 02:41:51 2008
@@ -1433,6 +1433,9 @@
                                               ident->replyto);
         gtk_widget_show(bsmsg->replyto[0]);
         gtk_widget_show(bsmsg->replyto[1]);
+    } else if (!sw_get_active(bsmsg, "ReplyTo")) {
+        gtk_widget_hide(bsmsg->replyto[0]);
+        gtk_widget_hide(bsmsg->replyto[1]);
     }
 #endif
 
@@ -5676,6 +5679,116 @@
     return response == GTK_RESPONSE_OK;
 }
 
+#ifdef HAVE_GPGME
+static gboolean
+check_suggest_encryption(BalsaSendmsg * bsmsg)
+{
+    InternetAddressList * ia_list;
+    gboolean can_encrypt;
+    InternetAddressList * from_list;
+    InternetAddressList * cc_list;
+    gpgme_protocol_t protocol;
+
+    /* check if the user wants to see the message */
+    if (!bsmsg->ident->warn_send_plain)
+	return TRUE;
+
+    /* nothing to do if encryption is already enabled */
+    if ((bsmsg->gpg_mode & LIBBALSA_PROTECT_ENCRYPT) != 0)
+	return TRUE;
+
+    /* we can not encrypt if we have bcc recipients */
+    if ((ia_list = libbalsa_address_view_get_list(bsmsg->recipient_view, "Bcc:"))) {
+	internet_address_list_destroy(ia_list);
+	return TRUE;
+    }
+
+    /* collect all to and cc recipients */
+    ia_list = libbalsa_address_view_get_list(bsmsg->recipient_view, "To:");
+    cc_list = libbalsa_address_view_get_list(bsmsg->recipient_view, "Cc:");
+    from_list = internet_address_list_prepend(NULL, bsmsg->ident->ia);
+    protocol = bsmsg->gpg_mode & LIBBALSA_PROTECT_SMIMEV3 ?
+	GPGME_PROTOCOL_CMS : GPGME_PROTOCOL_OpenPGP;
+    can_encrypt = libbalsa_can_encrypt_for_all(from_list, protocol) &
+	libbalsa_can_encrypt_for_all(ia_list, protocol) &
+	libbalsa_can_encrypt_for_all(cc_list, protocol);
+    internet_address_list_destroy(from_list);
+    internet_address_list_destroy(ia_list);
+    internet_address_list_destroy(cc_list);
+
+    /* ask the user if we could encrypt this message */
+    if (can_encrypt) {
+	GtkWidget *dialog;
+	gint choice;
+	gchar * message;
+	GtkWidget *dialog_action_area;
+	GtkWidget *button;
+	GtkWidget *alignment;
+	GtkWidget *hbox;
+	GtkWidget *image;
+	GtkWidget *label;
+
+	message =
+	    g_strdup_printf(_("You did not select encryption for this message, although "
+			      "%s public keys are available for all recipients. In order "
+			      "to protect your privacy, the message could be %s encrypted."),
+			    gpgme_get_protocol_name(protocol),
+			    gpgme_get_protocol_name(protocol));
+	dialog = gtk_message_dialog_new
+	    (GTK_WINDOW(bsmsg->window),
+	     GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL,
+	     GTK_MESSAGE_QUESTION,
+	     GTK_BUTTONS_NONE,
+	     message);
+
+	dialog_action_area = GTK_DIALOG(dialog)->action_area;
+	gtk_button_box_set_layout(GTK_BUTTON_BOX(dialog_action_area), GTK_BUTTONBOX_END);
+ 
+	button = gtk_button_new();
+	gtk_dialog_add_action_widget(GTK_DIALOG(dialog), button, GTK_RESPONSE_YES);
+	GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
+	gtk_widget_grab_focus(button);
+	alignment = gtk_alignment_new (0.5, 0.5, 0, 0);
+	gtk_container_add(GTK_CONTAINER(button), alignment);
+
+	hbox = gtk_hbox_new(FALSE, 2);
+	gtk_container_add(GTK_CONTAINER(alignment), hbox);
+	image = gtk_image_new_from_stock(BALSA_PIXMAP_GPG_ENCRYPT, GTK_ICON_SIZE_BUTTON);
+	gtk_box_pack_start(GTK_BOX(hbox), image, FALSE, FALSE, 0);
+	label = gtk_label_new_with_mnemonic(_("Send _encrypted"));
+	gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
+	gtk_widget_show_all(button);
+
+	button = gtk_button_new();
+	gtk_dialog_add_action_widget(GTK_DIALOG(dialog), button, GTK_RESPONSE_NO);
+	GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
+	alignment = gtk_alignment_new (0.5, 0.5, 0, 0);
+	gtk_container_add(GTK_CONTAINER(button), alignment);
+
+	hbox = gtk_hbox_new(FALSE, 2);
+	gtk_container_add(GTK_CONTAINER(alignment), hbox);
+	image = gtk_image_new_from_stock(BALSA_PIXMAP_SEND, GTK_ICON_SIZE_BUTTON);
+	gtk_box_pack_start(GTK_BOX(hbox), image, FALSE, FALSE, 0);
+	label = gtk_label_new_with_mnemonic(_("Send _plain"));
+	gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
+	gtk_widget_show_all(button);
+
+	button = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
+	gtk_widget_show(button);
+	gtk_dialog_add_action_widget(GTK_DIALOG(dialog), button, GTK_RESPONSE_CANCEL);
+	GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
+
+	choice = gtk_dialog_run(GTK_DIALOG(dialog));
+	gtk_widget_destroy(dialog);
+	if (choice == GTK_RESPONSE_YES)
+	    bsmsg_setup_gpg_ui_by_mode(bsmsg, bsmsg->gpg_mode | LIBBALSA_PROTECT_ENCRYPT);
+	else if (choice == GTK_RESPONSE_CANCEL || choice == GTK_RESPONSE_DELETE_EVENT)
+	    return FALSE;
+    }
+
+    return TRUE;
+}
+#endif
 
 /* "send message" menu and toolbar callback.
  */
@@ -5697,6 +5810,9 @@
 	return FALSE;
 
 #ifdef HAVE_GPGME
+    if (!check_suggest_encryption(bsmsg))
+	return FALSE;
+
     if ((bsmsg->gpg_mode & LIBBALSA_PROTECT_OPENPGP) != 0 &&
         (bsmsg->gpg_mode & LIBBALSA_PROTECT_MODE) != 0 &&
 	gtk_tree_model_get_iter_first(BALSA_MSG_ATTACH_MODEL(bsmsg), &iter)) {



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]