Index: libbalsa/filter.c
===================================================================
RCS file: /cvs/gnome/balsa/libbalsa/filter.c,v
retrieving revision 1.25
diff -u -r1.25 filter.c
--- libbalsa/filter.c	23 Feb 2003 19:11:20 -0000	1.25
+++ libbalsa/filter.c	27 Feb 2003 09:18:09 -0000
@@ -46,7 +46,6 @@
  *  code. */
 static LibBalsaMailbox* filters_trash_mbox = NULL;
 
-static UrlToMailboxMapper url_to_mailbox_mapper = NULL;
 static GSList** filter_list = NULL;
 void
 libbalsa_filters_set_trash(LibBalsaMailbox* new_trash)
@@ -55,11 +54,6 @@
 }
 
 void
-libbalsa_filters_set_url_mapper(UrlToMailboxMapper u2mm)
-{
-    url_to_mailbox_mapper = u2mm;
-}
-void
 libbalsa_filters_set_filter_list(GSList** list)
 {
     filter_list = list;
@@ -531,7 +525,6 @@
     gboolean result=FALSE;
     LibBalsaMailbox *mbox;
 
-    g_return_val_if_fail(url_to_mailbox_mapper, FALSE);
     if (!filter_list) return FALSE;
 
     for (lst=filter_list;lst;lst=g_slist_next(lst)) {
@@ -545,15 +538,18 @@
         }
         switch (filt->action) {
         case FILTER_COPY:
-            mbox = url_to_mailbox_mapper(filt->action_string);
-            if (!mbox)
+            mbox = libbalsa_mailbox_from_url(filt->action_string);
+            if (!mbox) {
                 libbalsa_information(LIBBALSA_INFORMATION_ERROR,
                                      _("Bad mailbox name for filter: %s"),
                                      filt->name);
-            else if (!libbalsa_messages_copy(filt->matching_messages,mbox))
+                break;
+            }
+            if (!libbalsa_messages_copy(filt->matching_messages,mbox))
                 libbalsa_information(LIBBALSA_INFORMATION_ERROR,
                                      _("Error when copying messages"));
             else if (mbox==filters_trash_mbox) result=TRUE;
+            g_object_unref(mbox);
             break;
         case FILTER_TRASH:
             if (!filters_trash_mbox || 
@@ -564,15 +560,18 @@
             else result=TRUE;
             break;
         case FILTER_MOVE:
-            mbox = url_to_mailbox_mapper(filt->action_string);
-            if (!mbox)
+            mbox = libbalsa_mailbox_from_url(filt->action_string);
+            if (!mbox) {
                 libbalsa_information(LIBBALSA_INFORMATION_ERROR,
                                      _("Bad mailbox name for filter: %s"),
                                      filt->name);
-            else if (!libbalsa_messages_move(filt->matching_messages,mbox))
+                break;
+            }
+            if (!libbalsa_messages_move(filt->matching_messages,mbox))
                 libbalsa_information(LIBBALSA_INFORMATION_ERROR,
                                      _("Error when moving messages"));
             else if (mbox==filters_trash_mbox) result=TRUE;
+            g_object_unref(mbox);
             break;
         case FILTER_PRINT:
             /* FIXME : to be implemented */
Index: libbalsa/filter.h
===================================================================
RCS file: /cvs/gnome/balsa/libbalsa/filter.h,v
retrieving revision 1.25
diff -u -r1.25 filter.h
--- libbalsa/filter.h	23 Feb 2003 19:11:20 -0000	1.25
+++ libbalsa/filter.h	27 Feb 2003 09:18:09 -0000
@@ -249,8 +249,6 @@
 filters_export_dialog(void);
 
 void libbalsa_filters_set_trash(LibBalsaMailbox* new_trash);
-typedef LibBalsaMailbox* (*UrlToMailboxMapper)(const gchar* url);
-void libbalsa_filters_set_url_mapper(UrlToMailboxMapper u2mm);
 void libbalsa_filters_set_filter_list(GSList** list);
 
 /*
Index: libbalsa/libbalsa-marshal.list
===================================================================
RCS file: /cvs/gnome/balsa/libbalsa/libbalsa-marshal.list,v
retrieving revision 1.2
diff -u -r1.2 libbalsa-marshal.list
--- libbalsa/libbalsa-marshal.list	20 Jan 2003 23:01:26 -0000	1.2
+++ libbalsa/libbalsa-marshal.list	27 Feb 2003 09:18:09 -0000
@@ -4,6 +4,7 @@
 INT:POINTER,POINTER
 POINTER:INT,POINTER
 POINTER:OBJECT
+POINTER:POINTER
 POINTER:POINTER,POINTER
 POINTER:VOID
 VOID:INT,INT,INT,STRING
Index: libbalsa/mailbox.c
===================================================================
RCS file: /cvs/gnome/balsa/libbalsa/mailbox.c,v
retrieving revision 1.216
diff -u -r1.216 mailbox.c
--- libbalsa/mailbox.c	15 Feb 2003 08:54:32 -0000	1.216
+++ libbalsa/mailbox.c	27 Feb 2003 09:18:10 -0000
@@ -26,7 +26,6 @@
 
 #include "libbalsa.h"
 #include "mailbackend.h"
-#include "libbalsa-marshal.h"
 #include "message.h"
 
 #include <libgnome/gnome-config.h> 
@@ -91,6 +90,8 @@
     SET_UNREAD_MESSAGES_FLAG,
     SAVE_CONFIG,
     LOAD_CONFIG,
+    GET_MESSAGE_INFO,
+    GET_MESSAGE_FROM_INFO,
     LAST_SIGNAL
 };
 
@@ -271,6 +272,26 @@
                      g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1,
                      G_TYPE_POINTER);
 
+    libbalsa_mailbox_signals[GET_MESSAGE_INFO] =
+	g_signal_new("get-message-info",
+                     G_TYPE_FROM_CLASS(object_class),
+                     G_SIGNAL_RUN_LAST | G_SIGNAL_NO_HOOKS,
+                     G_STRUCT_OFFSET(LibBalsaMailboxClass,
+                                     get_message_info),
+                     NULL, NULL,
+                     libbalsa_POINTER__POINTER,
+                     G_TYPE_POINTER, 1, G_TYPE_POINTER);
+
+    libbalsa_mailbox_signals[GET_MESSAGE_FROM_INFO] =
+	g_signal_new("get-message-from-info",
+                     G_TYPE_FROM_CLASS(object_class),
+                     G_SIGNAL_RUN_LAST | G_SIGNAL_NO_HOOKS,
+                     G_STRUCT_OFFSET(LibBalsaMailboxClass,
+                                     get_message_from_info),
+                     NULL, NULL,
+                     libbalsa_POINTER__POINTER,
+                     G_TYPE_POINTER, 1, G_TYPE_POINTER);
+
     object_class->dispose = libbalsa_mailbox_dispose;
     object_class->finalize = libbalsa_mailbox_finalize;
 
@@ -1131,13 +1152,150 @@
     }
 }
 
-void libbalsa_mailbox_messages_status_changed(LibBalsaMailbox * mbox,
-					      GList * messages,
-					      gint flag)
+void
+libbalsa_mailbox_messages_status_changed(LibBalsaMailbox * mbox,
+					 GList * messages,
+                                         gint flag)
 {
     g_return_if_fail(mbox && messages);
 
     g_signal_emit(G_OBJECT(mbox),
 		  libbalsa_mailbox_signals[MESSAGES_STATUS_CHANGED], 0,
 		  messages, flag);
+}
+
+/* Message URL methods. */
+gchar *
+libbalsa_mailbox_get_message_info(LibBalsaMailbox * mailbox,
+                                  LibBalsaMessage * message)
+{
+    gchar *message_info;
+
+    if (!mailbox || !message)
+        return NULL;
+
+    g_signal_emit(G_OBJECT(mailbox), 
+		  libbalsa_mailbox_signals[GET_MESSAGE_INFO], 0,
+                  message, &message_info);
+
+    return message_info;
+}
+
+LibBalsaMessage *
+libbalsa_mailbox_get_message_from_info(LibBalsaMailbox * mailbox,
+                                       gchar * message_info)
+{
+    LibBalsaMessage *message;
+
+    if (!mailbox || !message_info)
+        return NULL;
+
+    g_signal_emit(G_OBJECT(mailbox), 
+		  libbalsa_mailbox_signals[GET_MESSAGE_FROM_INFO], 0,
+                  message_info, &message);
+
+    return message;
+}
+
+/* Mailbox URL methods. */
+
+static pthread_mutex_t mailbox_table_lock = PTHREAD_MUTEX_INITIALIZER;
+static GHashTable *mailbox_table;
+
+/* Set the url for a mailbox, and update the hash table. */
+void
+libbalsa_mailbox_update_url(LibBalsaMailbox * mailbox, gchar * url)
+{
+    pthread_mutex_lock(&mailbox_table_lock);
+
+    if (mailbox_table) {
+        if (mailbox->url) {
+            g_hash_table_remove(mailbox_table, mailbox->url);
+            g_free(mailbox->url);
+        }
+    } else
+        mailbox_table = g_hash_table_new_full(g_str_hash, g_str_equal,
+                                              NULL, g_object_unref);
+
+    g_hash_table_insert(mailbox_table, url, mailbox);
+    mailbox->url = url;
+    g_object_ref(mailbox);
+
+    pthread_mutex_unlock(&mailbox_table_lock);
+}
+
+/* Get the mailbox for a URL.
+ * NOTE: either refs an existing mailbox, or creates a new one; in
+ * either case, the caller must unref it. */
+LibBalsaMailbox *
+libbalsa_mailbox_from_url(const gchar * url)
+{
+    LibBalsaMailbox *mailbox = NULL;
+    const gchar *path;
+
+    if (!url || !*url)
+        return NULL;
+
+    pthread_mutex_lock(&mailbox_table_lock);
+    if (mailbox_table)
+        mailbox = g_hash_table_lookup(mailbox_table, url);
+    pthread_mutex_unlock(&mailbox_table_lock);
+
+    if (mailbox) {
+        g_object_ref(mailbox);
+        return mailbox;
+    }
+
+    if (strncmp(url, "file:", 5) == 0 && (path = url + 5)) {
+        GType type = libbalsa_mailbox_type_from_path(path);
+
+        if (type == LIBBALSA_TYPE_MAILBOX_MH)
+            mailbox =
+                LIBBALSA_MAILBOX(libbalsa_mailbox_mh_new(path, FALSE));
+        else if (type == LIBBALSA_TYPE_MAILBOX_MBOX)
+            mailbox =
+                LIBBALSA_MAILBOX(libbalsa_mailbox_mbox_new(path, FALSE));
+        else if (type == LIBBALSA_TYPE_MAILBOX_MAILDIR)
+            mailbox =
+                LIBBALSA_MAILBOX(libbalsa_mailbox_maildir_new(path,
+                                                              FALSE));
+        else                    /* type is not a valid local mailbox type. */
+            g_assert_not_reached();
+
+        /* We can't guess what the display name would be, so we'll just
+         * use the base name of the path. */
+        mailbox->name = g_path_get_basename(path);
+    } else if ((strncmp(url, "imap:", 5) == 0 && (path = url + 5))
+               || (strncmp(url, "imaps:", 6) == 0 && (path = url + 6))) {
+        LibBalsaServer *server;
+        gchar *tmp;
+
+        mailbox = LIBBALSA_MAILBOX(libbalsa_mailbox_imap_new());
+
+        path = strchr(path, '@');
+        g_assert(path != NULL);
+        path = strchr(path, '/');
+        g_assert(path != NULL);
+        tmp = g_strndup(url, path - url);
+        server = libbalsa_server_from_url(tmp);
+        g_free(tmp);
+        libbalsa_mailbox_remote_set_server(LIBBALSA_MAILBOX_REMOTE
+                                           (mailbox), server);
+        libbalsa_mailbox_imap_set_path(LIBBALSA_MAILBOX_IMAP(mailbox),
+                                       ++path);
+        /* We can't guess what the display name would be, so we'll just
+         * use the path. */
+        mailbox->name = g_strdup(path);
+    }
+
+    return mailbox;
+}
+
+void
+libbalsa_mailbox_table_destroy(void)
+{
+    pthread_mutex_lock(&mailbox_table_lock);
+    g_hash_table_destroy(mailbox_table);
+    mailbox_table = NULL;
+    pthread_mutex_unlock(&mailbox_table_lock);
 }
Index: libbalsa/mailbox.h
===================================================================
RCS file: /cvs/gnome/balsa/libbalsa/mailbox.h,v
retrieving revision 1.96
diff -u -r1.96 mailbox.h
--- libbalsa/mailbox.h	1 Feb 2003 19:22:19 -0000	1.96
+++ libbalsa/mailbox.h	27 Feb 2003 09:18:11 -0000
@@ -178,6 +178,10 @@
                                 int op, GSList* conditions);
     void (*save_config) (LibBalsaMailbox * mailbox, const gchar * prefix);
     void (*load_config) (LibBalsaMailbox * mailbox, const gchar * prefix);
+    gchar *(*get_message_info) (LibBalsaMailbox * mailbox,
+                                LibBalsaMessage * message);
+    LibBalsaMessage *(*get_message_from_info) (LibBalsaMailbox * mailbox,
+                                               gchar * message_info);
 };
 
 
@@ -232,4 +236,18 @@
 void libbalsa_mailbox_messages_status_changed(LibBalsaMailbox * mbox,
 					      GList * messages,
 					      gint flag);
+
+/* Mailbox URL methods. */
+void libbalsa_mailbox_update_url(LibBalsaMailbox * mailbox, gchar * url);
+LibBalsaMailbox *libbalsa_mailbox_from_url(const gchar * url);
+void libbalsa_mailbox_table_destroy(void);
+
+/* Message URLs. */
+gchar *libbalsa_mailbox_get_message_info(LibBalsaMailbox * mailbox,
+                                         LibBalsaMessage * message);
+LibBalsaMessage *libbalsa_mailbox_get_message_from_info(LibBalsaMailbox *
+                                                        mailbox,
+                                                        gchar * info);
+
+
 #endif				/* __LIBBALSA_MAILBOX_H__ */
Index: libbalsa/mailbox_imap.c
===================================================================
RCS file: /cvs/gnome/balsa/libbalsa/mailbox_imap.c,v
retrieving revision 1.81
diff -u -r1.81 mailbox_imap.c
--- libbalsa/mailbox_imap.c	14 Feb 2003 14:24:40 -0000	1.81
+++ libbalsa/mailbox_imap.c	27 Feb 2003 09:18:11 -0000
@@ -85,6 +85,14 @@
 #endif
 					    LibBalsaMailbox * mailbox);
 
+/* Message URL methods. */
+static gchar *libbalsa_mailbox_imap_get_message_info(LibBalsaMailbox *
+                                                     mailbox,
+                                                     LibBalsaMessage *
+                                                     message);
+static LibBalsaMessage
+    *libbalsa_mailbox_imap_get_message_from_info(LibBalsaMailbox *
+                                                 mailbox, gchar * info);
 
 GType
 libbalsa_mailbox_imap_get_type(void)
@@ -140,6 +148,10 @@
     libbalsa_mailbox_class->load_config =
 	libbalsa_mailbox_imap_load_config;
 
+    libbalsa_mailbox_class->get_message_info =
+        libbalsa_mailbox_imap_get_message_info;
+    libbalsa_mailbox_class->get_message_from_info =
+        libbalsa_mailbox_imap_get_message_from_info;
     ImapCheckTimeout = 10;
 }
 
@@ -211,19 +223,26 @@
    for the folder scanner, which has to go around libmutt limitations.
 */
 void
-libbalsa_mailbox_imap_update_url(LibBalsaMailboxImap* mailbox)
+libbalsa_mailbox_imap_update_url(LibBalsaMailboxImap * mailbox)
 {
-    LibBalsaServer* s = LIBBALSA_MAILBOX_REMOTE_SERVER(mailbox);
-    gchar* enc = libbalsa_urlencode(s->user);
-    g_free(LIBBALSA_MAILBOX(mailbox)->url);
-    LIBBALSA_MAILBOX(mailbox)->url =  
-        g_strdup_printf("imap%s://%s@%s/%s", 
+    LibBalsaServer *s = LIBBALSA_MAILBOX_REMOTE_SERVER(mailbox);
+    gchar *enc = libbalsa_urlencode(s->user);
+
 #ifdef USE_SSL
-                        s->use_ssl ? "s" : "",
+    libbalsa_mailbox_update_url(LIBBALSA_MAILBOX(mailbox),
+                                g_strdup_printf("imap%s://%s@%s/%s",
+                                                s->use_ssl ? "s" : "", enc,
+                                                s->host,
+                                                mailbox->path ? mailbox->
+                                                path : ""));
 #else
-                        "",
+    libbalsa_mailbox_update_url(LIBBALSA_MAILBOX(mailbox),
+                                g_strdup_printf("imap://%s@%s/%s", enc,
+                                                s->host,
+                                                mailbox->path ? mailbox->
+                                                path : ""));
 #endif
-                        enc, s->host, mailbox->path? mailbox->path : "");
+
     g_free(enc);
 }
 
@@ -980,5 +999,39 @@
     libbalsa_mailbox_imap_close(LIBBALSA_MAILBOX(mailbox));
 }
 
+#define LIBBALSA_MAILBOX_IMAP_INFO_FORMAT "UIDVALIDITY=%d/;UID=%d"
+static gchar *
+libbalsa_mailbox_imap_get_message_info(LibBalsaMailbox * mailbox,
+                                       LibBalsaMessage * message)
+{
+    return g_strdup_printf(LIBBALSA_MAILBOX_IMAP_INFO_FORMAT,
+                           LIBBALSA_MAILBOX_IMAP(mailbox)->uid_validity,
+                           IMAP_MESSAGE_UID(message));
+}
+
+static LibBalsaMessage *
+libbalsa_mailbox_imap_get_message_from_info(LibBalsaMailbox * mailbox,
+                                            gchar * info)
+{
+    ImapUID uid_validity, uid;
+    GList *list;
+    LibBalsaMessage *message;
+
+    if (sscanf(info, LIBBALSA_MAILBOX_IMAP_INFO_FORMAT, &uid_validity,
+               &uid) != 2
+        || uid_validity != LIBBALSA_MAILBOX_IMAP(mailbox)->uid_validity)
+        return NULL;
+
+    message = NULL;
+    libbalsa_mailbox_open(mailbox);
+    for (list = mailbox->message_list; list; list = g_list_next(list)) {
+        LibBalsaMessage *tmp_message = list->data;
+        if (IMAP_MESSAGE_UID(tmp_message) == uid) {
+            message = tmp_message;
+            break;
+        }
+    }
+    libbalsa_mailbox_close(mailbox);
 
-
+    return message;
+}
Index: libbalsa/mailbox_local.c
===================================================================
RCS file: /cvs/gnome/balsa/libbalsa/mailbox_local.c,v
retrieving revision 1.56
diff -u -r1.56 mailbox_local.c
--- libbalsa/mailbox_local.c	14 Feb 2003 14:24:40 -0000	1.56
+++ libbalsa/mailbox_local.c	27 Feb 2003 09:18:11 -0000
@@ -58,6 +58,15 @@
 					       const gchar * prefix);
 static void run_filters_on_reception(LibBalsaMailbox * mailbox);
 
+/* Message URL methods. */
+static gchar *libbalsa_mailbox_local_get_message_info(LibBalsaMailbox *
+                                                      mailbox,
+                                                      LibBalsaMessage *
+                                                      message);
+static LibBalsaMessage
+    *libbalsa_mailbox_local_get_message_from_info(LibBalsaMailbox *
+                                                  mailbox, gchar * info);
+
 GType
 libbalsa_mailbox_local_get_type(void)
 {
@@ -117,6 +126,11 @@
     libbalsa_mailbox_class->load_config =
 	libbalsa_mailbox_local_load_config;
 
+    libbalsa_mailbox_class->get_message_info =
+	libbalsa_mailbox_local_get_message_info;
+    libbalsa_mailbox_class->get_message_from_info =
+	libbalsa_mailbox_local_get_message_from_info;
+        
     klass->remove_files = NULL;
 }
 
@@ -181,8 +195,8 @@
     /* update mailbox data */
     if(!i) {
 	libbalsa_notify_unregister_mailbox(LIBBALSA_MAILBOX(mailbox));
-	g_free(LIBBALSA_MAILBOX(mailbox)->url);
-	LIBBALSA_MAILBOX(mailbox)->url = g_strconcat("file://", path, NULL);
+        libbalsa_mailbox_update_url(LIBBALSA_MAILBOX(mailbox),
+                                    g_strconcat("file://", path, NULL));
 	libbalsa_notify_register_mailbox(LIBBALSA_MAILBOX(mailbox));
 	return 0;
     } else
@@ -389,14 +403,53 @@
 
     local = LIBBALSA_MAILBOX_LOCAL(mailbox);
 
-    g_free(mailbox->url);
-
     path = gnome_config_get_string("Path");
-    mailbox->url = g_strconcat("file://", path, NULL);
+    libbalsa_mailbox_update_url(LIBBALSA_MAILBOX(mailbox),
+                                g_strconcat("file://", path, NULL));
     g_free(path);
 
     if (LIBBALSA_MAILBOX_CLASS(parent_class)->load_config)
 	LIBBALSA_MAILBOX_CLASS(parent_class)->load_config(mailbox, prefix);
 
     libbalsa_notify_register_mailbox(mailbox);
+}
+
+#define LIBBALSA_MAILBOX_LOCAL_INFO "PATH="
+static gchar *
+libbalsa_mailbox_local_get_message_info(LibBalsaMailbox * mailbox,
+                                        LibBalsaMessage * message)
+{
+    gchar *message_info;
+
+    message_info =
+        g_strdup_printf(LIBBALSA_MAILBOX_LOCAL_INFO "%s",
+                        libbalsa_message_pathname(message));
+
+    return message_info;
+}
+
+static LibBalsaMessage *
+libbalsa_mailbox_local_get_message_from_info(LibBalsaMailbox *
+                                             mailbox, gchar * info)
+{
+    gint len = strlen(LIBBALSA_MAILBOX_LOCAL_INFO);
+    LibBalsaMessage *message;
+    GList *list;
+
+    if (strncmp(info, LIBBALSA_MAILBOX_LOCAL_INFO, len))
+        return NULL;
+    info += len;
+
+    message = NULL;
+    libbalsa_mailbox_open(mailbox);
+    for (list = mailbox->message_list; list; list = g_list_next(list)) {
+        LibBalsaMessage *tmp_message = list->data;
+        if (!strcmp(libbalsa_message_pathname(tmp_message), info)) {
+            message = tmp_message;
+            break;
+        }
+    }
+    libbalsa_mailbox_close(mailbox);
+
+    return message;
 }
Index: libbalsa/mailbox_maildir.c
===================================================================
RCS file: /cvs/gnome/balsa/libbalsa/mailbox_maildir.c,v
retrieving revision 1.12
diff -u -r1.12 mailbox_maildir.c
--- libbalsa/mailbox_maildir.c	20 Jan 2003 23:01:28 -0000	1.12
+++ libbalsa/mailbox_maildir.c	27 Feb 2003 09:18:11 -0000
@@ -170,7 +170,8 @@
     
     mailbox->is_directory = TRUE;
 	
-    LIBBALSA_MAILBOX(mailbox)->url = g_strconcat("file://", path, NULL);
+    libbalsa_mailbox_update_url(LIBBALSA_MAILBOX(mailbox),
+                                g_strconcat("file://", path, NULL));
 
     
     if(libbalsa_mailbox_maildir_create(path, create) < 0) {
Index: libbalsa/mailbox_mbox.c
===================================================================
RCS file: /cvs/gnome/balsa/libbalsa/mailbox_mbox.c,v
retrieving revision 1.9
diff -u -r1.9 mailbox_mbox.c
--- libbalsa/mailbox_mbox.c	20 Jan 2003 23:01:28 -0000	1.9
+++ libbalsa/mailbox_mbox.c	27 Feb 2003 09:18:12 -0000
@@ -41,7 +41,17 @@
 						       LibBalsaMessage *message);
 static void libbalsa_mailbox_mbox_remove_files(LibBalsaMailboxLocal *mailbox);
 
-GType libbalsa_mailbox_mbox_get_type(void)
+/* Message URL methods. */
+static gchar *libbalsa_mailbox_mbox_get_message_info(LibBalsaMailbox *
+                                                     mailbox,
+                                                     LibBalsaMessage *
+                                                     message);
+static LibBalsaMessage
+    *libbalsa_mailbox_mbox_get_message_from_info(LibBalsaMailbox *
+                                                 mailbox, gchar * info);
+
+GType
+libbalsa_mailbox_mbox_get_type(void)
 {
     static GType mailbox_type = 0;
 
@@ -85,6 +95,11 @@
     libbalsa_mailbox_class->get_message_stream =
 	libbalsa_mailbox_mbox_get_message_stream;
 
+    libbalsa_mailbox_class->get_message_info =
+        libbalsa_mailbox_mbox_get_message_info;
+    libbalsa_mailbox_class->get_message_from_info =
+        libbalsa_mailbox_mbox_get_message_from_info;
+
     libbalsa_mailbox_local_class->remove_files = 
 	libbalsa_mailbox_mbox_remove_files;
 }
@@ -137,7 +152,8 @@
     mailbox = g_object_new(LIBBALSA_TYPE_MAILBOX_MBOX, NULL);
     mailbox->is_directory = FALSE;
 	
-    mailbox->url = g_strconcat("file://", path, NULL);
+    libbalsa_mailbox_update_url(mailbox,
+                                g_strconcat("file://", path, NULL));
     if( libbalsa_mailbox_mbox_create(path, create) < 0 ) {
 	g_object_unref(G_OBJECT(mailbox));
 	return NULL;
@@ -178,4 +194,44 @@
 			     _("Could not remove %s:\n%s"), 
 			     libbalsa_mailbox_local_get_path(mailbox), 
 			     strerror(errno));
+}
+
+#define LIBBALSA_MAILBOX_MBOX_INFO "MESSAGEID="
+static gchar *
+libbalsa_mailbox_mbox_get_message_info(LibBalsaMailbox * mailbox,
+                                       LibBalsaMessage * message)
+{
+    gchar *message_info = NULL;
+
+    if (message->message_id)
+        message_info = g_strdup_printf(LIBBALSA_MAILBOX_MBOX_INFO "%s",
+                                       message->message_id);
+
+    return message_info;
+}
+
+static LibBalsaMessage *
+libbalsa_mailbox_mbox_get_message_from_info(LibBalsaMailbox * mailbox,
+                                            gchar * info)
+{
+    gint len = strlen(LIBBALSA_MAILBOX_MBOX_INFO);
+    GList *list;
+    LibBalsaMessage *message;
+
+    if (strncmp(info, LIBBALSA_MAILBOX_MBOX_INFO, len) || !*(info += len))
+        return NULL;
+
+    message = NULL;
+    libbalsa_mailbox_open(mailbox);
+    for (list = mailbox->message_list; list; list = g_list_next(list)) {
+        LibBalsaMessage *tmp_message = list->data;
+        if (tmp_message->message_id
+            && !strcmp(tmp_message->message_id, info)) {
+            message = tmp_message;
+            break;
+        }
+    }
+    libbalsa_mailbox_close(mailbox);
+
+    return message;
 }
Index: libbalsa/mailbox_mh.c
===================================================================
RCS file: /cvs/gnome/balsa/libbalsa/mailbox_mh.c,v
retrieving revision 1.11
diff -u -r1.11 mailbox_mh.c
--- libbalsa/mailbox_mh.c	20 Jan 2003 23:01:28 -0000	1.11
+++ libbalsa/mailbox_mh.c	27 Feb 2003 09:18:12 -0000
@@ -149,7 +149,8 @@
     
     mailbox->is_directory = TRUE;
     
-    mailbox->url = g_strconcat("file://", path, NULL);
+    libbalsa_mailbox_update_url(mailbox,
+                                g_strconcat("file://", path, NULL));
     
     if(libbalsa_mailbox_mh_create(path, create) < 0) {
 	g_object_unref(G_OBJECT(mailbox));
Index: libbalsa/message.c
===================================================================
RCS file: /cvs/gnome/balsa/libbalsa/message.c,v
retrieving revision 1.100
diff -u -r1.100 message.c
--- libbalsa/message.c	3 Feb 2003 20:26:36 -0000	1.100
+++ libbalsa/message.c	27 Feb 2003 09:18:14 -0000
@@ -1294,3 +1294,52 @@
     return tmp;
 }
 
+/* Message URLs. */
+/* Get the URL for a message; returns NULL if !message->mailbox, or if
+ * the message has no info from which it can be identified. */
+gchar *
+libbalsa_message_get_url(LibBalsaMessage * message)
+{
+    gchar *info;
+    gchar *message_url = NULL;
+
+    info = libbalsa_mailbox_get_message_info(message->mailbox, message);
+    if (info) {
+        message_url = g_strdup_printf("%s;%s", message->mailbox->url, info);
+        g_free(info);
+    }
+
+    return message_url;
+}
+
+/* Get the message identified by a URL; returns NULL if the message
+ * couldn't be found, or if the URL didn't contain the info needed to
+ * identify it.
+ * NOTE: message->mailbox has been ref'ed and opened, but message has
+ * not been ref'ed; the caller must close and unref the mailbox, but not
+ * unref the message without first ref'ing it.
+ */
+LibBalsaMessage *
+libbalsa_message_from_url(gchar * message_url)
+{
+    gchar *info;
+    gchar *mailbox_url;
+    LibBalsaMailbox *mailbox;
+
+    g_return_val_if_fail(message_url != NULL, NULL);
+
+    info = strchr(message_url, ';');
+    if (!info)
+        return NULL;
+
+    mailbox_url = g_strndup(message_url, info - message_url);
+    mailbox = libbalsa_mailbox_from_url(mailbox_url);
+    g_free(mailbox_url);
+
+    if (!mailbox)
+        return NULL;
+
+    libbalsa_mailbox_open(mailbox);
+
+    return libbalsa_mailbox_get_message_from_info(mailbox, ++info);
+}
Index: libbalsa/message.h
===================================================================
RCS file: /cvs/gnome/balsa/libbalsa/message.h,v
retrieving revision 1.46
diff -u -r1.46 message.h
--- libbalsa/message.h	20 Jan 2003 23:01:29 -0000	1.46
+++ libbalsa/message.h	27 Feb 2003 09:18:14 -0000
@@ -202,8 +202,8 @@
 #endif
 gboolean libbalsa_message_postpone(LibBalsaMessage * message,
 				   LibBalsaMailbox * draftbox,
-				   LibBalsaMessage * reply_message,
-				   gchar * fcc, gint encoding, 
+				   gchar * reply_message_url,
+				   gchar * fcc_url, gint encoding, 
 				   gboolean flow);
 
 /*
@@ -241,4 +241,9 @@
 #endif
 glong libbalsa_message_get_no(LibBalsaMessage* msg);
 void libbalsa_message_headers_update(LibBalsaMessage * message);
+
+/* Message URL methods. */
+gchar *libbalsa_message_get_url(LibBalsaMessage * message);
+LibBalsaMessage *libbalsa_message_from_url(gchar * message_url);
+
 #endif				/* __LIBBALSA_MESSAGE_H__ */
Index: libbalsa/send.c
===================================================================
RCS file: /cvs/gnome/balsa/libbalsa/send.c,v
retrieving revision 1.163
diff -u -r1.163 send.c
--- libbalsa/send.c	18 Feb 2003 21:15:20 -0000	1.163
+++ libbalsa/send.c	27 Feb 2003 09:18:16 -0000
@@ -355,7 +355,8 @@
    return -1 on failure, 0 on success.
 */
 static int
-write_remote_fcc(LibBalsaMailbox* fccbox, HEADER* m_msg)
+write_remote_fcc(LibBalsaMailbox* fccbox, HEADER* m_msg,
+                 gchar * reply_message_url, gchar * fcc)
 {
     LibBalsaServer* server = LIBBALSA_MAILBOX_REMOTE(fccbox)->server;
     g_return_val_if_fail(LIBBALSA_IS_MAILBOX_IMAP(fccbox), -1);
@@ -381,7 +382,8 @@
     /* Passwords are guaranteed to be set now */
     
     return mutt_write_fcc(LIBBALSA_MAILBOX(fccbox)->url,
-                          m_msg, NULL, 0, NULL);
+                          m_msg, reply_message_url,
+                          reply_message_url || fcc, fcc);
 }
 /* libbalsa_message_queue:
    places given message in the outbox. If fcc message field is set, saves
@@ -408,7 +410,7 @@
 	        mutt_write_fcc(libbalsa_mailbox_local_get_path(fccbox),
 			       mqi->message, NULL, 0, NULL);
 	    else if (LIBBALSA_IS_MAILBOX_IMAP(fccbox))
-                write_remote_fcc(fccbox, mqi->message);
+                write_remote_fcc(fccbox, mqi->message, NULL, NULL);
 	}
 	libbalsa_unlock_mutt();
 	libbalsa_mailbox_check(outbox);
@@ -1283,12 +1285,11 @@
 gboolean
 libbalsa_message_postpone(LibBalsaMessage * message,
 			  LibBalsaMailbox * draftbox,
-			  LibBalsaMessage * reply_message,
+			  gchar * reply_message_url,
 			  gchar * fcc, gint encoding,
 			  gboolean flow) {
     HEADER *msg;
     BODY *last, *newbdy;
-    gchar *tmp;
     LibBalsaMessageBody *body;
     int thereturn; 
 
@@ -1388,27 +1389,14 @@
 	libbalsa_unlock_mutt();
     } 
     
-    if ((reply_message != NULL) && (reply_message->mailbox != NULL))
-	/* Just saves the message ID, mailbox type and mailbox name. We could
-	 * search all mailboxes for the ID but that would not be too fast. We
-	 * could also add more stuff ID like path, server, ... without this
-	 * if you change the name of the mailbox the flag will not be set. 
-	 CHBM: unbreak this in 1.3 - use URL */
-	tmp = g_strdup_printf("%s\r%s",
-			      reply_message->message_id,
-			      reply_message->mailbox->name);
-    else
-	tmp = NULL;
-
     libbalsa_lock_mutt();
     if (LIBBALSA_IS_MAILBOX_LOCAL(draftbox)) {
 	thereturn = mutt_write_fcc(libbalsa_mailbox_local_get_path(draftbox),
-				   msg, tmp, 1, fcc);
+				   msg, reply_message_url, 1, fcc);
     } else if (LIBBALSA_IS_MAILBOX_IMAP(draftbox)) {
-        thereturn = write_remote_fcc(draftbox, msg);
+        thereturn = write_remote_fcc(draftbox, msg, reply_message_url, fcc);
     } else 
 	thereturn = -1;
-    g_free(tmp);
     mutt_free_header(&msg);
     libbalsa_unlock_mutt();
 
Index: libbalsa/server.c
===================================================================
RCS file: /cvs/gnome/balsa/libbalsa/server.c,v
retrieving revision 1.21
diff -u -r1.21 server.c
--- libbalsa/server.c	20 Jan 2003 23:01:29 -0000	1.21
+++ libbalsa/server.c	27 Feb 2003 09:18:16 -0000
@@ -1,7 +1,7 @@
 /* -*-mode:c; c-style:k&r; c-basic-offset:4; -*- */
 /* Balsa E-Mail Client
  *
- * Copyright (C) 1997-2002 Stuart Parmenter and others,
+ * Copyright (C) 1997-2003 Stuart Parmenter and others,
  *                         See the file AUTHORS for a list.
  *
  * This program is free software; you can redistribute it and/or modify
@@ -25,6 +25,7 @@
 #include "libbalsa.h"
 #include "libbalsa_private.h"
 #include "libbalsa-marshal.h"
+#include "misc.h"
 
 #include <libgnome/gnome-config.h> 
 #include <libgnome/gnome-i18n.h> 
@@ -45,6 +46,7 @@
 #endif
 					  );
 /* static gchar* libbalsa_server_real_get_password(LibBalsaServer *server); */
+static void libbalsa_server_insert(LibBalsaServer * server);
 
 enum {
     SET_USERNAME,
@@ -334,6 +336,8 @@
 	g_free(server->passwd);
 	server->passwd = buff;
     }
+
+    libbalsa_server_insert(server);
 }
 
 void
@@ -351,4 +355,66 @@
 #ifdef USE_SSL
     gnome_config_set_bool("SSL", server->use_ssl);
 #endif
+}
+
+/* Server URL methods. */
+
+static pthread_mutex_t server_table_lock = PTHREAD_MUTEX_INITIALIZER;
+static GHashTable *server_table;
+
+/* Insert the server into the hash table, with a URL that corresponds
+ * the leading part of an IMAP mailbox URL (protocol, user, and host).
+ */
+static void
+libbalsa_server_insert(LibBalsaServer * server)
+{
+    gchar *enc = libbalsa_urlencode(server->user);
+    gchar *url;
+
+    url = g_strdup_printf(
+#ifdef USE_SSL
+                             server->use_ssl ?
+                             "imaps://%s@%s" : "imap://%s@%s",
+#else
+                             "imap://%s@%s",
+#endif
+                             enc, server->host);
+
+    pthread_mutex_lock(&server_table_lock);
+
+    if (!server_table)
+        server_table = g_hash_table_new_full(g_str_hash, g_str_equal,
+                                             g_free, g_object_unref);
+
+    g_hash_table_insert(server_table, url, server);
+    g_object_ref(server);
+
+    pthread_mutex_unlock(&server_table_lock);
+}
+
+/* Get the server from its URL.
+ * NOTE: refs the server, so the caller must unref it. */
+LibBalsaServer *
+libbalsa_server_from_url(const gchar * url)
+{
+    LibBalsaServer *server = NULL;
+
+    pthread_mutex_lock(&server_table_lock);
+    if (server_table)
+        server = g_hash_table_lookup(server_table, url);
+    pthread_mutex_unlock(&server_table_lock);
+
+    if (server)
+        g_object_ref(server);
+
+    return server;
+}
+
+void
+libbalsa_server_table_destroy(void)
+{
+    pthread_mutex_lock(&server_table_lock);
+    g_hash_table_destroy(server_table);
+    server_table = NULL;
+    pthread_mutex_unlock(&server_table_lock);
 }
Index: libbalsa/server.h
===================================================================
RCS file: /cvs/gnome/balsa/libbalsa/server.h,v
retrieving revision 1.12
diff -u -r1.12 server.h
--- libbalsa/server.h	20 Jan 2003 23:01:29 -0000	1.12
+++ libbalsa/server.h	27 Feb 2003 09:18:16 -0000
@@ -91,4 +91,8 @@
 void libbalsa_server_load_config(LibBalsaServer * server);
 void libbalsa_server_save_config(LibBalsaServer * server);
 
+/* Server URL methods. */
+LibBalsaServer *libbalsa_server_from_url(const gchar * url);
+void libbalsa_server_table_destroy(void);
+
 #endif				/* __LIBBALSA_SERVER_H__ */
Index: src/balsa-app.c
===================================================================
RCS file: /cvs/gnome/balsa/src/balsa-app.c,v
retrieving revision 1.231
diff -u -r1.231 balsa-app.c
--- src/balsa-app.c	26 Feb 2003 11:03:22 -0000	1.231
+++ src/balsa-app.c	27 Feb 2003 09:18:17 -0000
@@ -493,7 +493,12 @@
     g_object_unref(G_OBJECT(balsa_app.sentbox));
     g_object_unref(G_OBJECT(balsa_app.draftbox));
     g_object_unref(G_OBJECT(balsa_app.trash));
+
+    /* Some libbalsa cleanup. */
     libbalsa_imap_close_all_connections();
+    libbalsa_mailbox_table_destroy();
+    libbalsa_server_table_destroy();
+
     /* g_slist_free(opt_attach_list); */
     g_object_unref(balsa_app.colormap);
     if(balsa_app.debug) g_print("balsa_app: Finished cleaning up.\n");
Index: src/balsa-index.c
===================================================================
RCS file: /cvs/gnome/balsa/src/balsa-index.c,v
retrieving revision 1.256
diff -u -r1.256 balsa-index.c
--- src/balsa-index.c	25 Feb 2003 18:37:06 -0000	1.256
+++ src/balsa-index.c	27 Feb 2003 09:18:19 -0000
@@ -1815,7 +1815,7 @@
 static void
 mru_menu_cb(gchar * url, BalsaIndex * index)
 {
-    LibBalsaMailbox *mailbox = balsa_find_mailbox_by_url(url);
+    LibBalsaMailbox *mailbox = libbalsa_mailbox_from_url(url);
 
     g_return_if_fail(mailbox != NULL);
 
@@ -1824,6 +1824,8 @@
         balsa_index_transfer(index, messages, mailbox, FALSE);
         g_list_free(messages);
     }
+
+    g_object_unref(mailbox);
 }
 
 /*
Index: src/balsa-mblist.c
===================================================================
RCS file: /cvs/gnome/balsa/src/balsa-mblist.c,v
retrieving revision 1.151
diff -u -r1.151 balsa-mblist.c
--- src/balsa-mblist.c	25 Feb 2003 18:37:06 -0000	1.151
+++ src/balsa-mblist.c	27 Feb 2003 09:18:21 -0000
@@ -1714,7 +1714,7 @@
 
     for (list = *url_list; list; list = g_list_next(list)) {
         gchar *url = list->data;
-        LibBalsaMailbox *mailbox = balsa_find_mailbox_by_url(url);
+        LibBalsaMailbox *mailbox = libbalsa_mailbox_from_url(url);
 
         if (mailbox || (allow_empty && !*url)) {
             mru = bmbl_mru_new(url_list, user_func, user_data, url);
@@ -1726,6 +1726,9 @@
                                   (GClosureNotify) g_free,
                                   (GConnectFlags) 0);
         }
+
+        if (mailbox)
+            g_object_unref(mailbox);
     }
 
     gtk_menu_shell_append(GTK_MENU_SHELL(menu),
Index: src/main.c
===================================================================
RCS file: /cvs/gnome/balsa/src/main.c,v
retrieving revision 1.136
diff -u -r1.136 main.c
--- src/main.c	22 Feb 2003 12:54:05 -0000	1.136
+++ src/main.c	27 Feb 2003 09:18:21 -0000
@@ -373,7 +373,6 @@
 
     /* Initialize libbalsa */
     libbalsa_init((LibBalsaInformationFunc) balsa_information);
-    libbalsa_filters_set_url_mapper(balsa_find_mailbox_by_url);
     libbalsa_filters_set_filter_list(&balsa_app.filters);
     
     /* checking for valid config files */
Index: src/message-window.c
===================================================================
RCS file: /cvs/gnome/balsa/src/message-window.c,v
retrieving revision 1.48
diff -u -r1.48 message-window.c
--- src/message-window.c	22 Feb 2003 12:54:05 -0000	1.48
+++ src/message-window.c	27 Feb 2003 09:18:21 -0000
@@ -1,6 +1,6 @@
 /* -*-mode:c; c-style:k&r; c-basic-offset:4; -*- */
 /* Balsa E-Mail Client
- * Copyright (C) 1997-2000 Stuart Parmenter and others,
+ * Copyright (C) 1997-2003 Stuart Parmenter and others,
  *                         See the file AUTHORS for a list.
  *
  * This program is free software; you can redistribute it and/or modify
@@ -201,7 +201,7 @@
 static void
 mru_menu_cb(gchar * url, gpointer data)
 {
-    LibBalsaMailbox *mailbox = balsa_find_mailbox_by_url(url);
+    LibBalsaMailbox *mailbox = libbalsa_mailbox_from_url(url);
     MessageWindow *mw = data;
     GList *list;
     BalsaIndex* bindex;
@@ -218,6 +218,7 @@
     g_list_free_1(list);
     
     close_message_window(NULL, (gpointer) mw);
+    g_object_unref(mailbox);
 }
 
 /* FIXME: any protection for destroying message window before idle
Index: src/sendmsg-window.c
===================================================================
RCS file: /cvs/gnome/balsa/src/sendmsg-window.c,v
retrieving revision 1.381
diff -u -r1.381 sendmsg-window.c
--- src/sendmsg-window.c	22 Feb 2003 12:54:05 -0000	1.381
+++ src/sendmsg-window.c	27 Feb 2003 09:18:26 -0000
@@ -71,6 +71,14 @@
     BalsaSendmsg *msg;
 } balsa_edit_with_gnome_data;
 
+/* bsmsg->reply_ref and bsmsg->draft_ref are pointers to instances of this
+ * struct: */
+struct _BalsaSendmsgReference {
+    LibBalsaMessage *message;
+    char *message_url;
+    void (*action)(LibBalsaMessage * message);
+    gboolean mailbox_opened;
+};
 
 static gchar *read_signature(BalsaSendmsg *msg);
 static gint include_file_cb(GtkWidget *, BalsaSendmsg *);
@@ -143,6 +151,25 @@
 /* helper */
 static gboolean sw_do_popup(GnomeIconList * ilist, GdkEventButton * event);
 
+/* BalsaSendmsgReference methods. */
+static BalsaSendmsgReference *sw_ref_new_from_message(LibBalsaMessage *
+                                                      message,
+                                                      void (*action)
+                                                      (LibBalsaMessage *
+                                                       message));
+static BalsaSendmsgReference *sw_ref_new_from_ref(LibBalsaMessage *
+                                                  message,
+                                                  void (*action)
+                                                  (LibBalsaMessage *
+                                                   message));
+static BalsaSendmsgReference *sw_ref_copy(BalsaSendmsgReference * ref);
+static void sw_ref_free(BalsaSendmsgReference * msg);
+/* Message actions when the mailbox might be closed. */
+static void sw_ref_action(BalsaSendmsgReference * msg);
+static void sw_ref_action_reopen(BalsaSendmsgReference * msg);
+/* Convenience method for deleting a single message. */
+static void sw_message_delete(LibBalsaMessage * message);
+
 /* Standard DnD types */
 enum {
     TARGET_MESSAGES,
@@ -631,14 +658,8 @@
                                 bsm->delete_sig_id);
     if(balsa_app.debug) g_message("balsa_sendmsg_destroy()_handler: Start.");
 
-    if (bsm->orig_message) {
-	if (bsm->orig_message->mailbox)
-	    libbalsa_mailbox_close(bsm->orig_message->mailbox);
-        /* check again! */
-	if (bsm->orig_message->mailbox)
-	    g_object_unref(G_OBJECT(bsm->orig_message->mailbox));
-	g_object_unref(G_OBJECT(bsm->orig_message));
-    }
+    sw_ref_free(bsm->reply_ref);
+    sw_ref_free(bsm->draft_ref);
 
     if (balsa_app.debug)
 	printf("balsa_sendmsg_destroy_handler: Freeing bsm\n");
@@ -1852,9 +1873,9 @@
         balsa_mblist_mru_add(&balsa_app.fcc_mru, "");
         balsa_app.fcc_mru = g_list_reverse(balsa_app.fcc_mru);
     }
-    if (type == SEND_CONTINUE && msg->orig_message->fcc_url)
+    if (msg->draft_ref && msg->draft_ref->message->fcc_url)
         balsa_mblist_mru_add(&balsa_app.fcc_mru,
-                             msg->orig_message->fcc_url);
+                             msg->draft_ref->message->fcc_url);
     msg->fcc[1] =
         balsa_mblist_mru_option_menu(GTK_WINDOW(msg->window),
                                      &balsa_app.fcc_mru);
@@ -2170,7 +2191,7 @@
 	}
     } else {
 	if (date)
-	    str = g_strdup_printf(_("On %s %s wrote:\n"), date, personStr);
+	    str = g_strdup_printf(_("On %s, %s wrote:\n"), date, personStr);
 	else
 	    str = g_strdup_printf(_("%s wrote:\n"), personStr);
 	body = content2reply(message,
@@ -2410,10 +2431,14 @@
 set_identity_from_mailbox(BalsaSendmsg* msg)
 {
     gchar *identity;
-    LibBalsaMessage *message = msg->orig_message;
+    LibBalsaMessage *message;
     LibBalsaIdentity* ident;
     GList *ilist;
 
+    if (!msg->reply_ref)
+        return FALSE;
+
+    message = msg->reply_ref->message;
     if( message && message->mailbox && balsa_app.identities) {
         identity = message->mailbox->identity_name;
         if(!identity) return FALSE;
@@ -2443,10 +2468,15 @@
 {
     gboolean done = FALSE;
     GList *alist;
-    LibBalsaMessage *message = msg->orig_message;
-    if( !message || !message->to_list || !balsa_app.identities)
+    LibBalsaMessage *message;
+
+    if (!msg->reply_ref)
         return FALSE; /* use default */
 
+    message = msg->reply_ref->message;
+    if( !message || !message->to_list || !balsa_app.identities)
+        return FALSE;
+
     /*
      * Loop through all the addresses in the message's To:
      * field, and look for an identity that matches one of them.
@@ -2572,28 +2602,20 @@
     msg->modified = FALSE; 
     msg->flow = balsa_app.wordwrap && balsa_app.send_rfc2646_format_flowed;
     msg->quit_on_close = FALSE;
-    msg->orig_message = message;
+    msg->reply_ref = NULL;
+    msg->draft_ref = NULL;
     msg->window = window = gnome_app_new("balsa", NULL);
     msg->type = type;
 
-    if (message) {
-        /* ref message so we don't lose it even if it is deleted */
-	g_object_ref(G_OBJECT(message));
-	/* reference the original mailbox so we don't loose the
-	   mail even if the mailbox is closed. Alternatively,
-	   one could try using weak references or destroy notification
-	   to take care of it. In such a case, the orig_message field
-	   would be cleared
-
-           we'll reference it both by opening it, in caseit's closed
-           elsewhere, and by ref'ing it, in case the mbnode that owns
-           it is destroyed in a rescan
-	*/
-	if (message->mailbox) {
-	    libbalsa_mailbox_open(message->mailbox);
-            g_object_ref(G_OBJECT(message->mailbox));
-        }
-    }
+    if (type == SEND_CONTINUE) {
+        msg->draft_ref =
+            sw_ref_new_from_message(message, sw_message_delete);
+        msg->reply_ref =
+            sw_ref_new_from_ref(message, libbalsa_message_reply);
+    } else if (type == SEND_REPLY || msg->type == SEND_REPLY_ALL
+             || type == SEND_REPLY_GROUP)
+        msg->reply_ref =
+            sw_ref_new_from_message(message, libbalsa_message_reply);
 
     g_signal_connect(G_OBJECT(msg->window), "delete-event",
 		     G_CALLBACK(delete_event_cb), msg);
@@ -2665,8 +2687,7 @@
 
     if (type == SEND_CONTINUE)
 	setup_headers_from_message(msg, message);
-
-    if (type == SEND_REPLY_ALL) {
+    else if (type == SEND_REPLY_ALL) {
 	tmp = libbalsa_make_string_from_list(message->to_list);
 
 	gtk_entry_set_text(GTK_ENTRY(msg->cc[1]), tmp);
@@ -2717,12 +2738,11 @@
 	if(!attach_message(msg, message))
                 libbalsa_information(LIBBALSA_INFORMATION_WARNING,
                                      _("Attaching message failed.\n"
-                                       "Possible reason: not enough temporary space"));
-    }
-
-    if (type == SEND_CONTINUE
-        && gnome_icon_list_get_num_icons(GNOME_ICON_LIST
-                                         (msg->attachments[1])))
+                                       "Possible reason: "
+                                       "not enough temporary space"));
+    } else if (type == SEND_CONTINUE
+               && gnome_icon_list_get_num_icons(GNOME_ICON_LIST
+                                                (msg->attachments[1])))
         gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM
                                        (msg->view_checkitems
                                         [MENU_TOGGLE_ATTACHMENTS_POS]),
@@ -3085,8 +3105,6 @@
     GList *list;
     gchar *tmp;
     const gchar *ctmp;
-    gchar recvtime[50];
-    struct tm *footime;
     GtkTextBuffer *buffer =
         gtk_text_view_get_buffer(GTK_TEXT_VIEW(bsmsg->text));
     GtkTextIter start, end;
@@ -3121,30 +3139,43 @@
     if (balsa_app.req_dispnotify)
 	libbalsa_message_set_dispnotify(message, bsmsg->ident->address);
 
-    if (bsmsg->orig_message != NULL) {
+    if (bsmsg->reply_ref) {
+        /* This is a reply. */
+        LibBalsaMessage *orig_msg;
+
+        if ((orig_msg = bsmsg->reply_ref->message)) {
+            /* A simple reply, no save, no postpones: if the original
+             * had a message-id, add the id to the references and
+             * make an In-Reply-To header. */
+            if (orig_msg->message_id) {
+                gchar recvtime[50];
+                struct tm *footime;
+
+                message->references =
+                    g_list_prepend(message->references,
+                                   g_strdup(orig_msg->message_id));
+
+                footime = localtime(&orig_msg->date);
+                strftime(recvtime, sizeof(recvtime),
+                         "%a, %b %d, %Y at %H:%M:%S %z", footime);
+                message->in_reply_to =
+                    g_strconcat(orig_msg->message_id, "; from ",
+                                (gchar *) orig_msg->from->address_list->
+                                data, " on ", recvtime, NULL);
+            }
+        } else {
+            /* Reply was saved or postponed, so we pick up the
+             * In-ReplyoTo header from the draft; the references already
+             * contain the original's message-id. */
+            orig_msg = bsmsg->draft_ref->message;
+            if (orig_msg->in_reply_to)
+                message->in_reply_to = g_strdup(orig_msg->in_reply_to);
+        }
 
-	if (bsmsg->orig_message->references != NULL) {
-	    for (list = bsmsg->orig_message->references; list;
-		 list = list->next) {
-		message->references =
-		    g_list_prepend(message->references,
-				  g_strdup(list->data));
-	    }
-	    message->references = g_list_reverse(message->references);
-	}
-	footime = localtime(&bsmsg->orig_message->date);
-	strftime(recvtime, sizeof(recvtime),
-		 "%a, %b %d, %Y at %H:%M:%S %z", footime);
-
-	if (bsmsg->orig_message->message_id) {
-	  message->references = g_list_prepend(
-	    message->references, g_strdup(bsmsg->orig_message->message_id));
-	    message->in_reply_to =
-		g_strconcat(bsmsg->orig_message->message_id, "; from ",
-			    (gchar *) bsmsg->orig_message->
-			    from->address_list->data, " on ", recvtime,
-			    NULL);
-	}
+        for (list = orig_msg->references; list; list = list->next)
+            message->references =
+                g_list_prepend(message->references, g_strdup(list->data));
+        message->references = g_list_reverse(message->references);
     }
 
     body = libbalsa_message_body_new(message);
@@ -3226,24 +3257,26 @@
 		    &bytes_read, &bytes_written, &err);
 
     g_free(res);
-    if(err) {
-	gchar *err_msg = 
-	    g_strdup_printf(_("The message cannot be encoded in charset %s.\n"
-			      "Please choose a language for this message."),
-			    bsmsg->charset);
-	GtkWidget* msgbox = gtk_message_dialog_new(GTK_WINDOW(bsmsg->window),
-						   GTK_DIALOG_MODAL,
-						   GTK_MESSAGE_ERROR,
-						   GTK_BUTTONS_OK,
-						   err_msg);
-	gtk_dialog_run(GTK_DIALOG(msgbox));
+    if (err) {
+        GtkWidget *msgbox =
+            gtk_message_dialog_new(GTK_WINDOW(bsmsg->window),
+                                   GTK_DIALOG_DESTROY_WITH_PARENT,
+                                   GTK_MESSAGE_ERROR,
+                                   GTK_BUTTONS_OK,
+                                   _("The message cannot be encoded "
+                                     "in charset %s.\n"
+                                     "Please choose a language "
+                                     "for this message."),
+                                   bsmsg->charset);
+
+        gtk_dialog_run(GTK_DIALOG(msgbox));
         gtk_widget_destroy(msgbox);
-	g_error_free(err);
-	return FALSE;
+        g_error_free(err);
+        return FALSE;
     }
 
     message = bsmsg2message(bsmsg);
-    fcc = balsa_find_mailbox_by_url(bsmsg->fcc_url);
+    fcc = libbalsa_mailbox_from_url(bsmsg->fcc_url);
 
     if(queue_only)
 	libbalsa_message_queue(message, balsa_app.outbox, fcc,
@@ -3262,20 +3295,14 @@
 					   balsa_app.encoding_style,
 					   bsmsg->flow); 
 #endif
-    if (successful && bsmsg->orig_message
-        && bsmsg->orig_message->mailbox) {
-	if (bsmsg->type == SEND_REPLY || bsmsg->type == SEND_REPLY_ALL ||
-	    bsmsg->type == SEND_REPLY_GROUP) {
-	    libbalsa_message_reply(bsmsg->orig_message);
-	} else if (bsmsg->type == SEND_CONTINUE) {
-	    GList * messages = g_list_prepend(NULL, bsmsg->orig_message);
-
-	    libbalsa_messages_delete(messages, TRUE);
-	    g_list_free(messages);
-	}
+    if (successful) {
+        sw_ref_action(bsmsg->reply_ref);
+        sw_ref_action(bsmsg->draft_ref);
     }
 
-    g_object_unref(G_OBJECT(message));
+    if (fcc)
+        g_object_unref(fcc);
+    g_object_unref(message);
     gtk_widget_destroy(bsmsg->window);
 
     return TRUE;
@@ -3323,31 +3350,22 @@
 message_postpone(BalsaSendmsg * bsmsg)
 {
     gboolean successp;
-    LibBalsaMessage *message;
-    message = bsmsg2message(bsmsg);
+    LibBalsaMessage *message = bsmsg2message(bsmsg);
+    gchar *reply_message_url = NULL;
 
-    if ((bsmsg->type == SEND_REPLY || bsmsg->type == SEND_REPLY_ALL ||
-        bsmsg->type == SEND_REPLY_GROUP))
-	successp = libbalsa_message_postpone(message, balsa_app.draftbox,
-                                             bsmsg->orig_message,
-                                             bsmsg->fcc_url,
-                                             balsa_app.encoding_style,
-                                             bsmsg->flow);
-    else
-	successp = libbalsa_message_postpone(message, balsa_app.draftbox, 
-                                             NULL,
-                                             bsmsg->fcc_url,
-                                             balsa_app.encoding_style,
-                                             bsmsg->flow);
-    if(successp) {
-	if (bsmsg->type == SEND_CONTINUE && bsmsg->orig_message) {
-	    GList * messages = g_list_prepend(NULL, bsmsg->orig_message);
+    if (bsmsg->reply_ref)
+        reply_message_url =
+            g_strdup_printf("<%s>", bsmsg->reply_ref->message_url);
+    successp = libbalsa_message_postpone(message, balsa_app.draftbox,
+                                         reply_message_url, bsmsg->fcc_url,
+                                         balsa_app.encoding_style,
+                                         bsmsg->flow);
+    if (successp)
+        sw_ref_action(bsmsg->draft_ref);
 
-	    libbalsa_messages_delete(messages, TRUE);
-	    g_list_free(messages);
-	}
-    }
     g_object_unref(G_OBJECT(message));
+    g_free(reply_message_url);
+
     return successp;
 }
 
@@ -3366,28 +3384,21 @@
 save_message_cb(GtkWidget * widget, BalsaSendmsg * bsmsg)
 {
     gboolean thereturn;
-    
-    thereturn = message_postpone(bsmsg);
 
-    if(thereturn) {
-	GList *draft_entry;
+    thereturn = message_postpone(bsmsg);
 
-	if(bsmsg->orig_message) {
-	    if(bsmsg->orig_message->mailbox)
-		libbalsa_mailbox_close(bsmsg->orig_message->mailbox);
-            /* check again! */
-	    if(bsmsg->orig_message->mailbox)
-	        g_object_unref(G_OBJECT(bsmsg->orig_message->mailbox));
-	    g_object_unref(G_OBJECT(bsmsg->orig_message));
-	}
-	bsmsg->type=SEND_CONTINUE;
-
-	libbalsa_mailbox_open(balsa_app.draftbox);
-	draft_entry=g_list_last(balsa_app.draftbox->message_list);
-	bsmsg->orig_message=LIBBALSA_MESSAGE(draft_entry->data);
-	bsmsg->orig_message->mailbox=balsa_app.draftbox;
-	g_object_ref(G_OBJECT(bsmsg->orig_message));
-    
+    if (thereturn) {
+        GList *draft_ref_entry;
+        LibBalsaMessage *message;
+
+        sw_ref_free(bsmsg->draft_ref);
+
+        libbalsa_mailbox_open(balsa_app.draftbox);
+        draft_ref_entry = g_list_last(balsa_app.draftbox->message_list);
+        message = LIBBALSA_MESSAGE(draft_ref_entry->data);
+        bsmsg->draft_ref =
+            sw_ref_new_from_message(message, sw_message_delete);
+        libbalsa_mailbox_close(balsa_app.draftbox);
     }
 }
 
@@ -3781,7 +3792,7 @@
 static void
 set_list_post_address(BalsaSendmsg * msg)
 {
-    LibBalsaMessage *message = msg->orig_message;
+    LibBalsaMessage *message = msg->reply_ref->message;
 
     if (message->mailbox->mailing_list_address) {
         gchar *tmp =
@@ -3943,4 +3954,166 @@
                             gtk_entry_get_text(GTK_ENTRY(msg->subject[1])));
     gtk_window_set_title(GTK_WINDOW(msg->window), title);
     g_free(title);
+}
+
+/* BalsaSendmsgReference methods. */
+static void
+sw_ref_free(BalsaSendmsgReference * ref)
+{
+    if (!ref)
+        return;
+
+    if (ref->message) {
+        if (ref->mailbox_opened && ref->message->mailbox)
+            libbalsa_mailbox_close(ref->message->mailbox);
+        g_object_unref(ref->message);
+    }
+    g_free(ref->message_url);
+    g_free(ref);
+}
+
+static BalsaSendmsgReference *
+sw_ref_new_from_message(LibBalsaMessage * message,
+                        void (*action) (LibBalsaMessage * message))
+{
+    BalsaSendmsgReference *ref;
+
+    if (!message)
+        return NULL;
+
+    ref = g_new(BalsaSendmsgReference, 1);
+    ref->message = message;
+    g_object_ref(message);
+    ref->message_url = libbalsa_message_get_url(message);
+    if (!ref->message_url) {
+        libbalsa_mailbox_open(message->mailbox);
+        ref->mailbox_opened = TRUE;
+    } else
+        ref->mailbox_opened = FALSE;
+    ref->action = action;
+
+    return ref;
+}
+
+static BalsaSendmsgReference *
+sw_ref_new_from_ref(LibBalsaMessage * message,
+                    void (*action) (LibBalsaMessage * message))
+{
+    GList *reply_to =
+        libbalsa_message_find_user_hdr(message, "X-Mutt-References");
+    gchar **pair;
+    BalsaSendmsgReference *ref;
+
+    if (!reply_to)
+        return NULL;
+
+    ref = g_new0(BalsaSendmsgReference, 1);
+    pair = reply_to->data;
+    ref->message_url = g_strndup(pair[1] + 1, strlen(pair[1]) - 2);
+    ref->action = action;
+
+    return ref;
+}
+
+static BalsaSendmsgReference *
+sw_ref_copy(BalsaSendmsgReference * ref)
+{
+    BalsaSendmsgReference *copy = g_new0(BalsaSendmsgReference, 1);
+
+    copy->message_url = g_strdup(ref->message_url);
+    copy->action = ref->action;
+
+    return copy;
+}
+
+/* sw_ref_action:
+ * Take an action on a message (either set
+ * LIBBALSA_MESSAGE_FLAG_REPLIED, or delete the message). If the
+ * message's mailbox has been closed, reopen it, find the correct
+ * message, and take the appropriate action.  */
+static void
+sw_ref_action(BalsaSendmsgReference * ref)
+{
+    if (!ref)
+        return;
+    if (ref->message && ref->message->mailbox)
+        ref->action(ref->message);
+    else
+        sw_ref_action_reopen(ref);
+}
+
+#ifdef BALSA_USE_THREADS
+
+/* Forward references: */
+static void sw_ref_action_thread(BalsaSendmsgReference * ref);
+static void sw_ref_action_idle(BalsaSendmsgReference * ref);
+
+static void
+sw_ref_action_reopen(BalsaSendmsgReference * ref)
+{
+    pthread_t action_thread;
+    BalsaSendmsgReference *copy = sw_ref_copy(ref);
+
+    pthread_create(&action_thread, NULL,
+                   (void *(*)(void *)) sw_ref_action_thread, copy);
+    pthread_detach(action_thread);
+}
+
+static void
+sw_ref_action_thread(BalsaSendmsgReference * ref)
+{
+    gdk_threads_enter();
+    ref->message = libbalsa_message_from_url(ref->message_url);
+    if (ref->message)
+        g_object_ref(G_OBJECT(ref->message));
+    g_idle_add((GSourceFunc) sw_ref_action_idle, ref);
+    gdk_threads_leave();
+}
+
+static void
+sw_ref_action_idle(BalsaSendmsgReference * ref)
+{
+    gdk_threads_enter();
+    if (ref->message) {
+        LibBalsaMailbox *mailbox = ref->message->mailbox;
+        ref->action(ref->message);
+        libbalsa_mailbox_close(mailbox);
+        g_object_unref(mailbox);
+    } else
+        balsa_information(LIBBALSA_INFORMATION_WARNING,
+                          _("Couldn't find message with URL \"%s\"."),
+                          ref->message_url);
+    sw_ref_free(ref);
+    gdk_threads_leave();
+}
+
+#else
+
+static void
+sw_ref_action_reopen(BalsaSendrefReference * ref)
+{
+    LibBalsaMessage *message = libbalsa_message_from_url(ref->message_url);
+
+    if (message) {
+        LibBalsaMailbox *mailbox = message->mailbox;
+        ref->action(message);
+        libbalsa_mailbox_close(mailbox);
+        g_object_unref(mailbox);
+    } else
+        balsa_information(LIBBALSA_INFORMATION_WARNING,
+                          _("Couldn't find message with URL \"%s\"."),
+                          ref->message_url);
+}
+
+#endif                          /* BALSA_USE_THREADS */
+/* End of sw_ref_action. */
+
+/* Delete a message from its mailbox. */
+static void
+sw_message_delete(LibBalsaMessage * message)
+{
+    GList *messages = g_list_prepend(NULL, message);
+
+    libbalsa_messages_delete(messages, TRUE);
+    g_list_free(messages);
 }
Index: src/sendmsg-window.h
===================================================================
RCS file: /cvs/gnome/balsa/src/sendmsg-window.h,v
retrieving revision 1.52
diff -u -r1.52 sendmsg-window.h
--- src/sendmsg-window.h	20 Jan 2003 23:02:13 -0000	1.52
+++ src/sendmsg-window.h	27 Feb 2003 09:18:26 -0000
@@ -40,6 +40,7 @@
 #define VIEW_MENU_LENGTH 10
     typedef struct _BalsaSendmsg BalsaSendmsg;
     typedef struct _BalsaSendmsgAddress BalsaSendmsgAddress;
+    typedef struct _BalsaSendmsgReference BalsaSendmsgReference;
 
     struct _BalsaSendmsgAddress {
         BalsaSendmsg *msg;
@@ -59,7 +60,8 @@
 	GtkWidget *text;
 	GtkWidget *spell_checker;
 	GtkWidget *notebook;
-	LibBalsaMessage *orig_message;
+        BalsaSendmsgReference *reply_ref;
+        BalsaSendmsgReference *draft_ref;
 	SendType type;
 	/* language selection related data */
 	gchar *charset;
