prototype balsa-index optimalizations



Hi,

Attached is a prototype how the fetching and displaying of messages could  
be done. The idea is to let the balsa-index class tell the mailbox which  
headers are needed to display and thread. If the mailbox supports  
threading that is offloaded too. For IMAP further optimalizations can be  
done, for example the message structure could be retrieved and only the  
displayed parts fetched.

This is a prototype patch, so take a look and tell me what you think.

Bart
--
When a guy says "the last thing I'd wanna do is hurt you" it just means
he's gotta do other things first.
Fingerprint = CD4D 5601 287D F075 6F96  6157 99F9 E56A 4B08 6D06
--- balsa-new-mailbox/libbalsa/imap/imap-commands.c	2003-09-03 14:29:38.000000000 +0200
+++ balsa-index-optimalization/libbalsa/imap/imap-commands.c	2003-09-04 21:27:45.000000000 +0200
@@ -344,3 +344,18 @@
   return rc;
 }
 
+/*
+ * THREAD Command
+ * see draft-ietf-imapext-thread-12.txt
+ */
+ImapResult
+imap_mbox_thread(ImapMboxHandle *h, const char *how)
+{
+  gchar * cmd = g_strdup_printf("THREAD %s UTF-8 ALL", how);
+  ImapResult rc = 
+    imap_cmd_exec(h, cmd) == IMR_OK 
+    ? IMAP_SUCCESS : IMAP_PROTOCOL_ERROR;  
+  g_free(cmd);
+  return rc;
+}
+
--- balsa-new-mailbox/libbalsa/imap/imap-commands.h	2003-09-03 14:29:38.000000000 +0200
+++ balsa-index-optimalization/libbalsa/imap/imap-commands.h	2003-09-04 20:36:47.000000000 +0200
@@ -30,4 +30,5 @@
 
 /* Experimental/Expansion */
 ImapResult imap_mbox_scan(ImapMboxHandle *r, const char*what, const char*str);
+ImapResult imap_mbox_thread(ImapMboxHandle *h, const char *how);
 #endif /* __IMAP_COMMANDS_H__ */
--- balsa-new-mailbox/libbalsa/imap/imap-handle.c	2003-09-03 14:29:38.000000000 +0200
+++ balsa-index-optimalization/libbalsa/imap/imap-handle.c	2003-09-04 23:56:58.000000000 +0200
@@ -387,6 +387,12 @@
   return handle->exists;
 }
 
+GNode *imap_mbox_handle_get_thread_root(ImapMboxHandle* handle)
+{
+  g_return_val_if_fail(handle, NULL);
+  return handle->thread_root;
+}
+
 void
 imap_mbox_handle_connect_notify(ImapMboxHandle* handle,
                                 ImapMboxNotifyCb cb, void *data)
@@ -435,15 +441,22 @@
 static void
 imap_envelope_free_data(ImapEnvelope* env)
 {
-  if(env->subject)     g_free(env->subject);
-  if(env->from)        g_free(env->from);
-  if(env->sender)      g_free(env->sender);
-  if(env->replyto)     g_free(env->replyto);
-  if(env->to)          g_free(env->to);
-  if(env->cc)          g_free(env->cc);
-  if(env->bcc)         g_free(env->bcc);
-  if(env->in_reply_to) g_free(env->in_reply_to);
-  if(env->message_id)  g_free(env->message_id);
+  g_free(env->subject);
+  g_free(env->from);
+  g_free(env->sender);
+  g_free(env->replyto);
+
+  g_list_foreach(env->to_list, (GFunc)g_free, NULL);
+  g_list_free(env->to_list);
+
+  g_list_foreach(env->cc_list, (GFunc)g_free, NULL);
+  g_list_free(env->cc_list);
+
+  g_list_foreach(env->bcc_list, (GFunc)g_free, NULL);
+  g_list_free(env->bcc_list);
+
+  g_free(env->in_reply_to);
+  g_free(env->message_id);
 }
 void
 imap_envelope_free(ImapEnvelope *env)
@@ -465,6 +478,7 @@
   g_return_if_fail(msg);
   if(msg->envelope) imap_envelope_free(msg->envelope);
   g_free(msg->body);
+  g_free(msg->fetched_header_fields);
   g_free(msg);
 }
 
@@ -723,7 +737,8 @@
   /* ordered identically as ImapCapability constants */
   static const char* capabilities[] = {
     "IMAP4", "IMAP4rev1", "STATUS", "ACL", "NAMESPACE", "AUTH=CRAM-MD5", 
-    "AUTH=GSSAPI", "AUTH=ANONYMOUS", "STARTTLS", "LOGINDISABLED"
+    "AUTH=GSSAPI", "AUTH=ANONYMOUS", "STARTTLS", "LOGINDISABLED",
+    "THREAD=ORDEREDSUBJECT", "THREAD=REFERENCES"
   };
   unsigned x;
   int c;
@@ -1019,9 +1034,7 @@
   return IMR_OK;
 }
 
-/* imap_get_address: returns null if no beginning of address is found
-   (eg., when end of list is found instead).
-*/
+#if 0
 static char*
 imap_get_address(struct siobuf* sio)
 {
@@ -1079,6 +1092,50 @@
   }
   return res;
 }
+#else
+/* imap_get_address: returns null if no beginning of address is found
+   (eg., when end of list is found instead).
+*/
+static ImapAddress*
+imap_get_address(struct siobuf* sio)
+{
+  ImapAddress *address;
+  int c;
+
+  if(sio_getc(sio) != '(') return NULL;
+  
+  address = g_new0(ImapAddress, 1);
+
+  address->addr_name = imap_get_nstring(sio);
+  if( (c=sio_getc(sio)) != ' '); /* error but do nothing */
+  address->addr_adl = imap_get_nstring(sio);
+  if( (c=sio_getc(sio)) != ' '); /* error but do nothing */
+  address->addr_mailbox = imap_get_nstring(sio);
+  if( (c=sio_getc(sio)) != ' '); /* error but do nothing */
+  address->addr_host = imap_get_nstring(sio);
+  if( (c=sio_getc(sio)) != ')'); /* error but do nothing */
+
+  return address;
+}
+static GList*
+imap_get_addr_list(struct siobuf *sio)
+{
+  GList *list=NULL;
+  ImapAddress *addr;
+
+  int c=sio_getc(sio);
+  if( c == '(') {
+    while( (addr=imap_get_address(sio)) != NULL) {
+      list = g_list_prepend(list, addr);
+    }
+    /* assert(c==')'); */
+  } else { /* nil; FIXME: error checking */
+    sio_getc(sio); /* i */
+    sio_getc(sio); /* l */
+  }
+  return g_list_reverse(list);
+}
+#endif
 
 static ImapResponse
 ir_msg_att_envelope(ImapMboxHandle *h, unsigned seqno)
@@ -1086,6 +1143,7 @@
   int c;
   char *date;
   ImapMessage *msg = h->msg_cache[seqno-1];
+  GList *address_list;
 
   if( (c=sio_getc(h->sio)) != '(') return IMR_PROTOCOL;
   if(!msg->envelope)
@@ -1096,24 +1154,46 @@
   if(date) g_free(date);
   msg->envelope->date = 0;
   if( (c=sio_getc(h->sio)) != ' ') return IMR_PROTOCOL;
+
   msg->envelope->subject = imap_get_nstring(h->sio);
   if( (c=sio_getc(h->sio)) != ' ') return IMR_PROTOCOL;
-  msg->envelope->from = imap_get_addr_list(h->sio);
+
+  address_list = imap_get_addr_list(h->sio);
+  msg->envelope->from = address_list->data;
+  address_list = g_list_delete_link(address_list, address_list);
+  g_list_foreach(address_list, (GFunc)g_free, NULL);
+  g_list_free(address_list);
   if( (c=sio_getc(h->sio)) != ' ') return IMR_PROTOCOL;
-  msg->envelope->sender = imap_get_addr_list(h->sio);
+
+  address_list = imap_get_addr_list(h->sio);
+  msg->envelope->sender = address_list->data;
+  address_list = g_list_delete_link(address_list, address_list);
+  g_list_foreach(address_list, (GFunc)g_free, NULL);
+  g_list_free(address_list);
   if( (c=sio_getc(h->sio)) != ' ') return IMR_PROTOCOL;
-  msg->envelope->replyto = imap_get_addr_list(h->sio);
+
+  address_list = imap_get_addr_list(h->sio);
+  msg->envelope->replyto = address_list->data;
+  address_list = g_list_delete_link(address_list, address_list);
+  g_list_foreach(address_list, (GFunc)g_free, NULL);
+  g_list_free(address_list);
   if( (c=sio_getc(h->sio)) != ' ') return IMR_PROTOCOL;
-  msg->envelope->to = imap_get_addr_list(h->sio);
+
+  msg->envelope->to_list = imap_get_addr_list(h->sio);
   if( (c=sio_getc(h->sio)) != ' ') return IMR_PROTOCOL;
-  msg->envelope->cc = imap_get_addr_list(h->sio);
+
+  msg->envelope->cc_list = imap_get_addr_list(h->sio);
   if( (c=sio_getc(h->sio)) != ' ') return IMR_PROTOCOL;
-  msg->envelope->bcc = imap_get_addr_list(h->sio);
+
+  msg->envelope->bcc_list = imap_get_addr_list(h->sio);
   if( (c=sio_getc(h->sio)) != ' ') return IMR_PROTOCOL;
+
   msg->envelope->in_reply_to = imap_get_nstring(h->sio);
   if( (c=sio_getc(h->sio)) != ' ') { printf("c=%c\n",c); return IMR_PROTOCOL;}
+
   msg->envelope->message_id = imap_get_nstring(h->sio);
   if( (c=sio_getc(h->sio)) != ')') { printf("c=%d\n",c);return IMR_PROTOCOL;}
+
   return IMR_OK;
 }
 
@@ -1156,11 +1236,30 @@
 	  printf("%c", c);
 		  ;
   }
-	  printf("%c<\n", c);
+  printf("%c<\n", c);
+  g_free(msg->body);
   msg->body = imap_get_nstring(h->sio);
   return IMR_OK;
 }
 static ImapResponse
+ir_msg_att_body_header_fields(ImapMboxHandle *h, unsigned seqno)
+{
+  int c;
+  unsigned i;
+  ImapMessage *msg = h->msg_cache[seqno-1];
+
+  if(sio_getc(h->sio) != '(') return IMR_PROTOCOL;
+
+  while (imap_get_astring(h->sio, &c) && c != ')')
+      /* nothing (yet?) */;
+  if(c != ')') return IMR_PROTOCOL;
+  if(sio_getc(h->sio) != ']') return IMR_PROTOCOL;
+  if(sio_getc(h->sio) != ' ') return IMR_PROTOCOL;
+  g_free(msg->fetched_header_fields);
+  msg->fetched_header_fields = imap_get_nstring(h->sio);
+  return IMR_OK;
+}
+static ImapResponse
 ir_msg_att_uid(ImapMboxHandle *h, unsigned seqno)
 {
   char buf[12];
@@ -1186,8 +1285,9 @@
     { "RFC822.HEADER", ir_msg_att_rfc822_header }, 
     { "RFC822.TEXT",   ir_msg_att_rfc822_text }, 
     { "RFC822.SIZE",   ir_msg_att_rfc822_size }, 
-    { "BODY[",         ir_msg_att_body }, 
     { "BODY",          ir_msg_att_body }, 
+    { "BODY[",         ir_msg_att_body }, 
+    { "BODY[HEADER.FIELDS",         ir_msg_att_body_header_fields }, 
     { "UID",           ir_msg_att_uid }
   };
   char atom[LONG_STRING];
@@ -1228,6 +1328,96 @@
   return ir_fetch_seq(h, seqno);
 }
 
+/*
+   Example:    S: * THREAD (2)(3 6 (4 23)(44 7 96))
+
+      The first thread consists only of message 2.  The second thread
+      consists of the messages 3 (parent) and 6 (child), after which it
+      splits into two subthreads; the first of which contains messages 4
+      (child of 6, sibling of 44) and 23 (child of 4), and the second of
+      which contains messages 44 (child of 6, sibling of 4), 7 (child of
+      44), and 96 (child of 7).  Since some later messages are parents
+      of earlier messages, the messages were probably moved from some
+      other mailbox at different times.
+
+      -- 2
+
+      -- 3
+         \-- 6
+             |-- 4
+             |   \-- 23
+             |
+             \-- 44
+                  \-- 7
+                      \-- 96
+*/
+static ImapResponse
+ir_thread_sub(ImapMboxHandle *h, GNode *parent, int last)
+{
+  char buf[12];
+  unsigned seqno;
+  int c;
+  GNode *item;
+  ImapResponse rc = IMR_OK;
+
+  c = imap_get_atom(h->sio, buf, sizeof(buf));
+  seqno = atoi(buf);
+#if 0
+  if (last == ' ')
+#endif
+  {
+      if(seqno == 0 && c == '(') {
+	  while (c == '(') {
+	      rc = ir_thread_sub(h, parent, c);
+	      if (rc!=IMR_OK) {
+		  return rc;
+	      }
+	      c=sio_getc(h->sio);
+	  }
+	  return rc;
+      }
+  }
+  if(seqno == 0) return IMAP_PROTOCOL_ERROR;
+  printf("%d ", seqno);
+  item = g_node_append_data(parent, GUINT_TO_POINTER(seqno));
+  if (c == ' ') {
+      printf(">");
+      rc = ir_thread_sub(h, item, c);
+      printf("<");
+  }
+
+  return rc;
+}
+static ImapResponse
+ir_thread(ImapMboxHandle *h)
+{
+  GNode *root;
+  int c;
+  ImapResponse rc = IMR_OK;
+  
+  c=sio_getc(h->sio);
+  g_node_destroy(h->thread_root);
+  h->thread_root = NULL;
+  root = g_node_new(NULL);
+  while (c == '(') {
+      rc=ir_thread_sub(h, root, c);
+      if (rc!=IMR_OK) {
+	  return rc;
+      }
+      printf("\n");
+      c=sio_getc(h->sio);
+  }
+  if( c != 0x0d) {printf("CR:%d\n",c); rc = IMR_PROTOCOL;}
+  if( (c=sio_getc(h->sio)) != 0x0a) {printf("LF:%d\n",c); rc = IMR_PROTOCOL;}
+
+  if (rc != IMR_OK)
+      g_node_destroy(root);
+  else
+      h->thread_root = root;
+
+  return rc;
+}
+
 /* response dispatch code */
 static const struct {
   const gchar *response;
@@ -1245,7 +1435,8 @@
   { "STATUS",     6, ir_status },
   { "SEARCH",     6, ir_search },
   { "FLAGS",      5, ir_flags },
-  { "FETCH",      5, ir_fetch }
+  { "FETCH",      5, ir_fetch },
+  { "THREAD",     6, ir_thread },
 };
 static const struct {
   const gchar *response;
--- balsa-new-mailbox/libbalsa/imap/imap-handle.h	2003-09-03 14:29:38.000000000 +0200
+++ balsa-index-optimalization/libbalsa/imap/imap-handle.h	2003-09-04 21:14:16.000000000 +0200
@@ -44,6 +44,8 @@
   IMCAP_AUTH_ANON, 	        /*           AUTH=ANONYMOUS */
   IMCAP_STARTTLS,		/* RFC 2595: STARTTLS */
   IMCAP_LOGINDISABLED,		/*           LOGINDISABLED */
+  IMCAP_THREAD_ORDEREDSUBJECT,
+  IMCAP_THREAD_REFERENCES,
   IMCAP_MAX
 } ImapCapability;
 
@@ -95,6 +97,7 @@
 /* int below is a boolean */
 int      imap_mbox_handle_can_do(ImapMboxHandle* handle, ImapCapability cap);
 unsigned imap_mbox_handle_get_exists(ImapMboxHandle* handle);
+GNode *imap_mbox_handle_get_thread_root(ImapMboxHandle* handle);
 
 void imap_mbox_handle_connect_notify(ImapMboxHandle* handle,
                                      ImapMboxNotifyCb cb,
--- balsa-new-mailbox/libbalsa/imap/imap.h	2003-09-03 14:29:38.000000000 +0200
+++ balsa-index-optimalization/libbalsa/imap/imap.h	2003-09-04 21:09:51.000000000 +0200
@@ -47,15 +47,22 @@
 typedef guint32 ImapUID;
 typedef time_t ImapDate;
 
+typedef struct ImapAddress_ {
+    char *addr_name;
+    char *addr_adl;
+    char *addr_mailbox;
+    char *addr_host;
+} ImapAddress;
+
 typedef struct ImapEnvelope_ {
   ImapDate date;
   gchar *subject; /* mime encoded, 7-bit subject as fetched from server */
-  gchar *from;
-  gchar *sender;
-  gchar *replyto;
-  gchar *to;
-  gchar *cc;
-  gchar *bcc;
+  ImapAddress *from;
+  ImapAddress *sender;
+  ImapAddress *replyto;
+  GList *to_list;
+  GList *cc_list;
+  GList *bcc_list;
   gchar *in_reply_to;
   gchar *message_id;
 } ImapEnvelope;
@@ -69,6 +76,7 @@
      section have yet to be implemented. Currently, they will be ignored 
   */
   gchar *body;
+  gchar *fetched_header_fields;
 } ImapMessage;
 
 typedef struct _ImapMboxHandle      ImapMboxHandle;
--- balsa-new-mailbox/libbalsa/imap/imap_private.h	2003-09-03 14:29:38.000000000 +0200
+++ balsa-index-optimalization/libbalsa/imap/imap_private.h	2003-09-04 21:11:25.000000000 +0200
@@ -38,6 +38,7 @@
 
   ImapInfoCb alert_cb;
   void *alert_arg;
+  GNode *thread_root;
 };
 
 extern const char* msg_flags[];
--- balsa-new-mailbox/libbalsa/libbalsa-marshal.list	2003-09-03 14:29:47.000000000 +0200
+++ balsa-index-optimalization/libbalsa/libbalsa-marshal.list	2003-09-04 20:15:50.000000000 +0200
@@ -1,4 +1,5 @@
 # keep this list sorted.
+BOOLEAN:OBJECT,POINTER
 BOOLEAN:POINTER
 BOOLEAN:POINTER,INT,POINTER
 BOOLEAN:VOID
--- balsa-new-mailbox/libbalsa/mailbox.c	2003-09-03 14:19:29.000000000 +0200
+++ balsa-index-optimalization/libbalsa/mailbox.c	2003-09-04 20:22:23.000000000 +0200
@@ -98,6 +98,8 @@
     LOAD_MESSAGE,
     ADD_MESSAGE,
     CHANGE_MESSAGE_FLAGS,
+    FETCH_HEADERS,
+    UPDATE_MODEL_AND_THREAD,
     LAST_SIGNAL
 };
 
@@ -346,6 +348,24 @@
                      NULL, NULL,
                      libbalsa_VOID__INT_INT_INT, G_TYPE_NONE, 3,
 		     G_TYPE_INT, G_TYPE_INT, G_TYPE_INT);
+    libbalsa_mailbox_signals[FETCH_HEADERS] =
+	g_signal_new("fetch-headers",
+                     G_TYPE_FROM_CLASS(object_class),
+                     G_SIGNAL_RUN_LAST | G_SIGNAL_NO_HOOKS,
+                     G_STRUCT_OFFSET(LibBalsaMailboxClass,
+                                     fetch_headers),
+                     NULL, NULL,
+                     libbalsa_VOID__POINTER_INT, G_TYPE_NONE, 2,
+		     G_TYPE_POINTER, G_TYPE_INT);
+    libbalsa_mailbox_signals[UPDATE_MODEL_AND_THREAD] =
+	g_signal_new("update-model-and-thread",
+                     G_TYPE_FROM_CLASS(object_class),
+                     G_SIGNAL_RUN_LAST | G_SIGNAL_NO_HOOKS,
+                     G_STRUCT_OFFSET(LibBalsaMailboxClass,
+                                     update_model_and_thread),
+                     NULL, NULL,
+                     libbalsa_BOOLEAN__OBJECT_POINTER, G_TYPE_BOOLEAN, 2,
+		     G_TYPE_OBJECT, G_TYPE_POINTER);
 
     object_class->dispose = libbalsa_mailbox_dispose;
     object_class->finalize = libbalsa_mailbox_finalize;
@@ -1272,6 +1292,33 @@
 		  msgno, set, clear);
 }
 
+void libbalsa_mailbox_fetch_headers(LibBalsaMailbox *mailbox, GList *messages,
+				    LibBalsaMailboxFetchHeaders headers)
+{
+    g_return_if_fail(mailbox != NULL);
+    g_return_if_fail(LIBBALSA_IS_MAILBOX(mailbox));
+    g_return_if_fail(messages != NULL);
+
+    g_signal_emit(G_OBJECT(mailbox),
+		  libbalsa_mailbox_signals[FETCH_HEADERS], 0,
+		  messages, headers);
+}
+
+gboolean libbalsa_mailbox_update_model_and_thread(LibBalsaMailbox *mailbox,
+					      GtkTreeModel *model,
+					      GList *messages)
+{
+    gboolean retval = FALSE;
+    g_return_val_if_fail(mailbox != NULL, FALSE);
+    g_return_val_if_fail(LIBBALSA_IS_MAILBOX(mailbox), FALSE);
+    g_return_val_if_fail(messages != NULL, FALSE);
+
+    g_signal_emit(G_OBJECT(mailbox),
+		  libbalsa_mailbox_signals[UPDATE_MODEL_AND_THREAD], 0,
+		  model, messages, &retval);
+    return retval;
+}
+
 /*
  * Mailbox views
  */
--- balsa-new-mailbox/libbalsa/mailbox.h	2003-09-03 14:19:29.000000000 +0200
+++ balsa-index-optimalization/libbalsa/mailbox.h	2003-09-04 20:17:07.000000000 +0200
@@ -100,6 +100,13 @@
     LB_MAILBOX_SHOW_TO
 } LibBalsaMailboxShow;
 
+typedef enum {
+    LIBBALSA_MAILBOX_FETCH_HEADERS_FLAGS	= 1<<0,
+    LIBBALSA_MAILBOX_FETCH_HEADERS_ENVELOPE	= 1<<1,
+    LIBBALSA_MAILBOX_FETCH_HEADERS_SIZE		= 1<<2,
+    LIBBALSA_MAILBOX_FETCH_HEADERS_LINES	= 1<<3,
+    LIBBALSA_MAILBOX_FETCH_HEADERS_REFERENCES	= 1<<4
+} LibBalsaMailboxFetchHeaders;
 /*
  * structures
  */
@@ -192,6 +199,12 @@
 					   LibBalsaMessageFlag set,
 					   LibBalsaMessageFlag clear);
     gboolean (*close_backend)(LibBalsaMailbox * mailbox);
+
+    void (*fetch_headers)(LibBalsaMailbox *mailbox, GList *messages,
+				   LibBalsaMailboxFetchHeaders);
+    gboolean (*update_model_and_thread)(LibBalsaMailbox *mailbox,
+					GtkTreeModel *model,
+					GList *messages);
 };
 
 GType libbalsa_mailbox_get_type(void);
@@ -272,6 +285,11 @@
 					   LibBalsaMessageFlag set,
 					   LibBalsaMessageFlag clear);
 
+void libbalsa_mailbox_fetch_headers(LibBalsaMailbox *mailbox, GList *messages,
+				    LibBalsaMailboxFetchHeaders);
+gboolean libbalsa_mailbox_update_model_and_thread(LibBalsaMailbox *mailbox,
+						  GtkTreeModel *model,
+						  GList *messages);
 /*
  * misc mailbox releated functions
  */
--- balsa-new-mailbox/libbalsa/mailbox_imap.c	2003-09-03 14:29:47.000000000 +0200
+++ balsa-index-optimalization/libbalsa/mailbox_imap.c	2003-09-05 01:02:42.000000000 +0200
@@ -54,12 +54,12 @@
 struct message_info {
     GMimeMessage *mime_message;
     ImapMessage *msg;
-    char *key;
     ImapUID uid;
-    const char *subdir;
-    char *filename;
     LibBalsaMessageFlag flags;
     LibBalsaMessageFlag orig_flags;
+    LibBalsaMessage *message;
+    GtkTreeRowReference *ref;
+
 };
 #define CLIENT_CONTEXT(mailbox) ((struct imap_info*)(mailbox)->mailbox_data)
 #include "libbalsa_private.h"
@@ -128,6 +128,12 @@
 						guint msgno,
 						LibBalsaMessageFlag set,
 						LibBalsaMessageFlag clear);
+static void libbalsa_mailbox_imap_fetch_headers(LibBalsaMailbox *mailbox,
+						GList *messages,
+						LibBalsaMailboxFetchHeaders headers);
+static gboolean libbalsa_mailbox_imap_update_model_and_thread(LibBalsaMailbox *mailbox,
+							      GtkTreeModel *model,
+							      GList *messages);
 
 static void server_settings_changed(LibBalsaServer * server,
 				    LibBalsaMailbox * mailbox);
@@ -222,6 +228,8 @@
     libbalsa_mailbox_class->load_message = libbalsa_mailbox_imap_load_message;
     libbalsa_mailbox_class->add_message = libbalsa_mailbox_imap_add_message;
     libbalsa_mailbox_class->change_message_flags = libbalsa_mailbox_imap_change_message_flags;
+    libbalsa_mailbox_class->fetch_headers = libbalsa_mailbox_imap_fetch_headers;
+    libbalsa_mailbox_class->update_model_and_thread = libbalsa_mailbox_imap_update_model_and_thread;
 
 }
 
@@ -1493,15 +1501,12 @@
 
     mailbox->messages++;
 
-    if (libbalsa_mailbox_imap_get_message(mailbox, msgno) == NULL)
-	return NULL;
+    message = libbalsa_message_new();
+    msg_info->message = message;
 
-    if (msg_info->mime_message->subject &&
-	!strcmp(msg_info->mime_message->subject,
-		"DON'T DELETE THIS MESSAGE -- FOLDER INTERNAL DATA"))
+#if 0
+    if (libbalsa_mailbox_imap_get_message(mailbox, msgno) == NULL)
 	return NULL;
-
-    message = libbalsa_message_new();
     message->mime_msg = msg_info->mime_message;
 
 #ifdef MESSAGE_COPY_CONTENT
@@ -1517,20 +1522,10 @@
 	    msg_info->lines=atoi(header);
 #endif
 
-    msg = imap_mbox_handle_get_msg(CLIENT_CONTEXT(mailbox)->handle, msgno+1);
-    if (!IMSG_FLAG_SEEN(msg->flags))
-        message->flags |= LIBBALSA_MESSAGE_FLAG_NEW;
-    if (IMSG_FLAG_DELETED(msg->flags))
-        message->flags |= LIBBALSA_MESSAGE_FLAG_DELETED;
-    if (IMSG_FLAG_FLAGGED(msg->flags))
-        message->flags |= LIBBALSA_MESSAGE_FLAG_FLAGGED;
-    if (IMSG_FLAG_ANSWERED(msg->flags))
-        message->flags |= LIBBALSA_MESSAGE_FLAG_REPLIED;
-    if (IMSG_FLAG_RECENT(msg->flags))
-	message->flags |= LIBBALSA_MESSAGE_FLAG_RECENT;
 #if FIXME
     message->flags = msg_info->flags = msg_info->orig_flags;
 #endif
+#endif
 
     message->msgno = msgno;
     return message;
@@ -1618,3 +1613,212 @@
     if (clear & LIBBALSA_MESSAGE_FLAG_RECENT)
 	imap_mbox_store_flag(handle, seq, IMSGF_RECENT, 0);
 }
+
+static LibBalsaAddress *
+libbalsa_address_new_from_imap_address(ImapAddress *addr)
+{
+    LibBalsaAddress *address;
+
+    if (!addr || (addr->addr_name==NULL && addr->addr_mailbox==NULL))
+	return NULL;
+
+    address = libbalsa_address_new();
+
+    /* it will be owned by the caller */
+
+    address->full_name = g_strdup(addr->addr_name);
+    if (addr->addr_mailbox)
+	address->address_list = g_list_append(address->address_list,
+				      g_strdup_printf("%s@%s", 
+						      addr->addr_mailbox,
+						      addr->addr_host));
+
+    return address;
+}
+static GList*
+libbalsa_address_new_list_from_imap_address_list(GList *list)
+{
+    LibBalsaAddress* addr;
+    GList* lst = NULL;
+
+    for (; list; list = list->next) {
+	addr = libbalsa_address_new_from_imap_address(list->data);
+	if (addr)
+	    g_list_prepend(lst, addr);
+    }
+    return g_list_reverse(lst);
+}
+
+static
+void libbalsa_mailbox_imap_fetch_headers(LibBalsaMailbox *mailbox,
+					 GList *messages,
+					 LibBalsaMailboxFetchHeaders headers)
+{
+    ImapMboxHandle *handle = CLIENT_CONTEXT(mailbox)->handle;
+    gchar *hdrs[10];
+    int header_count=0;
+    GString *seqs;
+    GList *list;
+
+#if 0
+    if (headers & LIBBALSA_MAILBOX_FETCH_HEADERS_FLAGS)
+    {
+	/* always fetched with imap_mbox_handle_fetch_env */
+	/* FLAGS */
+    }
+    if (headers & LIBBALSA_MAILBOX_FETCH_HEADERS_ENVELOPE)
+    {
+	/* ENVELOPE */
+    }
+    if (headers & LIBBALSA_MAILBOX_FETCH_HEADERS_SIZE)
+    {
+	/* RFC822.SIZE */
+    }
+    if (headers & LIBBALSA_MAILBOX_FETCH_HEADERS_LINES)
+    {
+	/* not available on server */
+    }
+    if (headers & LIBBALSA_MAILBOX_FETCH_HEADERS_REFERENCES)
+    {
+	/*
+	   ENVELOPE +
+	hdrs[header_count++] = "References";
+	*/
+    }
+    hdrs[header_count]=NULL;
+#endif
+    seqs = g_string_new(NULL);
+	
+    g_string_append_printf(seqs, "%d",
+			   LIBBALSA_MESSAGE(messages->data)->msgno+1);
+    list = messages->next;
+    for (; list; list = list->next) {
+	LibBalsaMessage *message = LIBBALSA_MESSAGE(list->data);
+	g_string_append_printf(seqs, ",%d", message->msgno+1);
+    }
+
+    imap_mbox_handle_fetch_env(handle, seqs->str);
+
+    g_string_free(seqs, TRUE);
+
+    for (list = messages; list; list = list->next) {
+	LibBalsaMessage *message = LIBBALSA_MESSAGE(list->data);
+	ImapMessage *msg = imap_mbox_handle_get_msg(handle, message->msgno+1);
+	gchar *header;
+	if (!msg) {
+	    printf("fetch_headers failed for %d\n", message->msgno+1);
+	    continue;
+	}
+	if (headers & LIBBALSA_MAILBOX_FETCH_HEADERS_FLAGS)
+	{
+	    message->flags=0;
+	    if (!IMSG_FLAG_SEEN(msg->flags))
+		message->flags |= LIBBALSA_MESSAGE_FLAG_NEW;
+	    if (IMSG_FLAG_DELETED(msg->flags))
+		message->flags |= LIBBALSA_MESSAGE_FLAG_DELETED;
+	    if (IMSG_FLAG_FLAGGED(msg->flags))
+		message->flags |= LIBBALSA_MESSAGE_FLAG_FLAGGED;
+	    if (IMSG_FLAG_ANSWERED(msg->flags))
+		message->flags |= LIBBALSA_MESSAGE_FLAG_REPLIED;
+	    if (IMSG_FLAG_RECENT(msg->flags))
+		message->flags |= LIBBALSA_MESSAGE_FLAG_RECENT;
+	}
+	if (headers & LIBBALSA_MAILBOX_FETCH_HEADERS_ENVELOPE)
+	{
+	    message->headers->from =
+		libbalsa_address_new_from_imap_address(msg->envelope->from);
+	    message->headers->to_list =
+		libbalsa_address_new_list_from_imap_address_list(msg->envelope->to_list);
+	    message->subj = g_strdup(msg->envelope->subject);
+	}
+	if (headers & LIBBALSA_MAILBOX_FETCH_HEADERS_SIZE)
+	{
+	}
+	if (headers & LIBBALSA_MAILBOX_FETCH_HEADERS_LINES)
+	{
+	}
+	if (headers & LIBBALSA_MAILBOX_FETCH_HEADERS_REFERENCES)
+	{
+	}
+    }
+}
+
+struct ThreadingInfo {
+    LibBalsaMailbox *mailbox;
+    GtkTreeModel *model;
+};
+
+static gboolean
+construct(GNode * node, struct ThreadingInfo *ti)
+{
+    if (node->data) {
+	struct message_info *msg_info;
+	LibBalsaMessage *message;
+	GtkTreeIter iter;
+	GtkTreePath *path;
+
+	/* find LibBalsaMessage from node->data */
+	msg_info = message_info_from_msgno(ti->mailbox,
+					   GPOINTER_TO_UINT(node->data)-1);
+	message = msg_info->message;
+	g_return_val_if_fail(message != NULL, FALSE);
+	
+	if (node->parent && node->parent->data) {
+	    /* find parent iter from node->parent->data */
+	    struct message_info *msg_info;
+	    GtkTreeIter parent_iter;
+
+	    msg_info = message_info_from_msgno(ti->mailbox,
+				       GPOINTER_TO_UINT(node->parent->data)-1);
+	    path = gtk_tree_row_reference_get_path(msg_info->ref);
+	    gtk_tree_model_get_iter(ti->model, &parent_iter, path);
+	    gtk_tree_path_free(path);
+
+	    gtk_tree_store_append(GTK_TREE_STORE(ti->model), &iter,
+				  &parent_iter);
+	} else {
+	    gtk_tree_store_append(GTK_TREE_STORE(ti->model), &iter, NULL);
+	}
+
+	path = gtk_tree_model_get_path(ti->model, &iter);
+	msg_info->ref = gtk_tree_row_reference_new(ti->model, path);
+	gtk_tree_path_free(path);
+	bndx_model_set_message(ti->model, &iter, message);
+    }
+
+    return FALSE;
+}
+
+static
+gboolean libbalsa_mailbox_imap_update_model_and_thread(LibBalsaMailbox *mailbox,
+						   GtkTreeModel *model,
+						   GList *messages)
+{
+    ImapMboxHandle *handle = CLIENT_CONTEXT(mailbox)->handle;
+    gboolean use_imap_thread = FALSE;
+
+    if (mailbox->view->threading_type == LB_MAILBOX_THREADING_SIMPLE
+	&& imap_mbox_handle_can_do(handle, IMCAP_THREAD_ORDEREDSUBJECT)) {
+	imap_mbox_thread(handle, "ORDEREDSUBJECT");
+	use_imap_thread=TRUE;
+    }
+    if (mailbox->view->threading_type == LB_MAILBOX_THREADING_JWZ
+	&& imap_mbox_handle_can_do(handle, IMCAP_THREAD_REFERENCES)) {
+	imap_mbox_thread(handle, "REFERENCES");
+	use_imap_thread=TRUE;
+    }
+    if (use_imap_thread) {
+	GNode *root;
+	struct ThreadingInfo ti;
+
+	ti.mailbox = mailbox;
+	ti.model = model;
+
+	root = imap_mbox_handle_get_thread_root(handle);
+	g_node_traverse(root, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
+			(GNodeTraverseFunc) construct, &ti);
+	return TRUE;
+    }
+
+    return FALSE;
+}
--- balsa-new-mailbox/libbalsa/message.c	2003-09-03 14:29:47.000000000 +0200
+++ balsa-index-optimalization/libbalsa/message.c	2003-09-04 16:06:31.000000000 +0200
@@ -1147,9 +1147,11 @@
     int offset;
   
     g_return_if_fail(message != NULL);
-    g_return_if_fail(message->mime_msg != NULL);
     g_return_if_fail(message->headers != NULL);
 
+    if (message->mime_msg == NULL)
+	return;
+
     libbalsa_message_headers_from_gmime(message->headers, message->mime_msg);
 
     g_mime_message_get_date(message->mime_msg, &message->headers->date, &offset);
--- balsa-new-mailbox/src/balsa-index.c	2003-09-03 14:29:48.000000000 +0200
+++ balsa-index-optimalization/src/balsa-index.c	2003-09-05 01:02:24.000000000 +0200
@@ -107,7 +107,33 @@
 static void bndx_select_message(BalsaIndex * index,
                                 LibBalsaMessage * message);
 static void bndx_changed_find_row(BalsaIndex * index);
-static void bndx_add_message(BalsaIndex * index, LibBalsaMessage * message);
+static void bndx_index_column_set_attrs (GtkTreeViewColumn *tree_column,
+					 GtkCellRenderer *cell,
+					 GtkTreeModel *tree_model,
+					 GtkTreeIter *iter,
+					 gpointer data);
+static void bndx_from_column_set_attrs (GtkTreeViewColumn *tree_column,
+					GtkCellRenderer *cell,
+					GtkTreeModel *tree_model,
+					GtkTreeIter *iter,
+					gpointer data);
+static void bndx_subject_column_set_attrs (GtkTreeViewColumn *tree_column,
+					   GtkCellRenderer *cell,
+					   GtkTreeModel *tree_model,
+					   GtkTreeIter *iter,
+					   gpointer data);
+static void bndx_date_column_set_attrs (GtkTreeViewColumn *tree_column,
+					GtkCellRenderer *cell,
+					GtkTreeModel *tree_model,
+					GtkTreeIter *iter,
+					gpointer data);
+static void bndx_size_column_set_attrs (GtkTreeViewColumn *tree_column,
+					GtkCellRenderer *cell,
+					GtkTreeModel *tree_model,
+					GtkTreeIter *iter,
+					gpointer data);
+void bndx_model_set_message(GtkTreeModel *model, GtkTreeIter *iter,
+			     LibBalsaMessage *message);
 static void bndx_messages_remove(BalsaIndex * index, GList * messages);
 static gboolean bndx_refresh_size_func(GtkTreeModel * model,
                                        GtkTreePath * path,
@@ -327,9 +353,9 @@
     renderer = gtk_cell_renderer_text_new();
     g_object_set(renderer, "xalign", 1.0, NULL);
     gtk_tree_view_column_pack_start(column, renderer, FALSE);
-    gtk_tree_view_column_set_attributes(column, renderer,
-                                        "text", BNDX_INDEX_COLUMN,
-                                        NULL);
+    gtk_tree_view_column_set_cell_data_func(column, renderer,
+					    bndx_index_column_set_attrs,
+					    NULL, NULL);
     gtk_tree_view_column_set_sort_column_id(column,
                                             BNDX_TREE_COLUMN_NO);
     g_signal_connect(G_OBJECT(column), "clicked",
@@ -356,12 +382,12 @@
     
     /* From/To column */
     renderer = gtk_cell_renderer_text_new();
-    column = 
-        gtk_tree_view_column_new_with_attributes(_("From"), renderer,
-                                                 "text", BNDX_FROM_COLUMN,
-						 "weight",
-						 BNDX_WEIGHT_COLUMN,
-                                                 NULL);
+    column = gtk_tree_view_column_new();
+    gtk_tree_view_column_set_title(column, _("From"));
+    gtk_tree_view_column_pack_start(column, renderer, TRUE);
+    gtk_tree_view_column_set_cell_data_func(column, renderer,
+					    bndx_from_column_set_attrs,
+					    NULL, NULL);
     gtk_tree_view_column_set_alignment(column, 0.5);
     gtk_tree_view_column_set_resizable(column, TRUE);
     gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
@@ -373,15 +399,12 @@
 
     /* Subject column--contains tree expanders */
     renderer = gtk_cell_renderer_text_new();
-    column = 
-        gtk_tree_view_column_new_with_attributes(_("Subject"), renderer,
-                                                 "text",
-                                                 BNDX_SUBJECT_COLUMN,
-                                                 "foreground-gdk",
-                                                 BNDX_COLOR_COLUMN,
-                                                 "weight",
-                                                 BNDX_WEIGHT_COLUMN,
-                                                 NULL);
+    column = gtk_tree_view_column_new();
+    gtk_tree_view_column_set_title(column, _("Subject"));
+    gtk_tree_view_column_pack_start(column, renderer, TRUE);
+    gtk_tree_view_column_set_cell_data_func(column, renderer,
+					    bndx_subject_column_set_attrs,
+					    NULL, NULL);
     gtk_tree_view_column_set_alignment(column, 0.5);
     gtk_tree_view_column_set_resizable(column, TRUE);
     gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
@@ -394,11 +417,12 @@
 
     /* Date column */
     renderer = gtk_cell_renderer_text_new();
-    column = 
-        gtk_tree_view_column_new_with_attributes(_("Date"), renderer,
-                                                 "text", BNDX_DATE_COLUMN,
-						 "weight",BNDX_WEIGHT_COLUMN,
-                                                 NULL);
+    column = gtk_tree_view_column_new();
+    gtk_tree_view_column_set_title(column, _("Date"));
+    gtk_tree_view_column_pack_start(column, renderer, TRUE);
+    gtk_tree_view_column_set_cell_data_func(column, renderer,
+					    bndx_date_column_set_attrs,
+					    NULL, NULL);
     gtk_tree_view_column_set_alignment(column, 0.5);
     gtk_tree_view_column_set_resizable(column, TRUE);
     gtk_tree_view_column_set_sort_column_id(column,
@@ -414,10 +438,9 @@
     renderer = gtk_cell_renderer_text_new();
     g_object_set(renderer, "xalign", 1.0, NULL);
     gtk_tree_view_column_pack_start(column, renderer, FALSE);
-    gtk_tree_view_column_set_attributes(column, renderer,
-                                        "text", BNDX_SIZE_COLUMN,
-					"weight",BNDX_WEIGHT_COLUMN,
-                                        NULL);
+    gtk_tree_view_column_set_cell_data_func(column, renderer,
+					    bndx_size_column_set_attrs,
+					    NULL, NULL);
     gtk_tree_view_column_set_sort_column_id(column,
                                             BNDX_TREE_COLUMN_SIZE);
     g_signal_connect(G_OBJECT(column), "clicked",
@@ -1243,6 +1266,7 @@
      * balsa_icon_get_bitmap(BALSA_PIXMAP_INFO_READ)); 
      */
 
+    if (message->mime_msg) {
     if (libbalsa_message_has_attachment(message))
         attach_pixbuf =
             gtk_widget_render_icon(GTK_WIDGET(index->window),
@@ -1282,14 +1306,11 @@
                                    BALSA_PIXMAP_INFO_ENCR,
                                    GTK_ICON_SIZE_MENU, NULL);
 #endif
+    }
 
     gtk_tree_store_set(GTK_TREE_STORE(model), iter,
                        BNDX_STATUS_COLUMN, status_pixbuf,
                        BNDX_ATTACH_COLUMN, attach_pixbuf,
-		       BNDX_WEIGHT_COLUMN,
-		       LIBBALSA_MESSAGE_HAS_FLAG(message,
-						 LIBBALSA_MESSAGE_FLAG_NEW) ?
-		       PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL,
                        -1);
 	
 }
@@ -1477,6 +1498,8 @@
     g_idle_add((GSourceFunc)mailbox_messages_changed_status_idle, arg);
 }
 
+static void
+mailbox_load_and_thread(LibBalsaMailbox *mailbox, BalsaIndex *index, GList *messages);
 /* mailbox_messages_added_cb : callback for sync with backend; the signal
    is emitted by the mailbox when new messages has been retrieved (either
    after opening the mailbox, or after "check new messages").
@@ -1487,13 +1510,7 @@
 {
     GList *list;
 
-    for (list = messages; list; list = g_list_next(list)) {
-        LibBalsaMessage *msg = (LibBalsaMessage *) list->data;
-	if (msg->mailbox)
-	    bndx_add_message(bindex, msg);
-    }
-    balsa_index_threading(bindex, 
-			  bindex->mailbox_node->mailbox->view->threading_type);
+    mailbox_load_and_thread(bindex->mailbox_node->mailbox, bindex, messages);
     for (list = messages; list; list = g_list_next(list)) {
         LibBalsaMessage *msg = (LibBalsaMessage *) list->data;
         GtkTreeIter iter;
@@ -2168,16 +2185,9 @@
 bndx_refresh_size_func(GtkTreeModel * model, GtkTreePath * path,
                        GtkTreeIter * iter, gpointer data)
 {
-    gchar *txt_new;
-    LibBalsaMessage *message = NULL;
-
-    gtk_tree_model_get(model, iter, BNDX_MESSAGE_COLUMN, &message, -1);
-    txt_new =
-        libbalsa_message_size_to_gchar(message, GPOINTER_TO_INT(data));
     gtk_tree_store_set(GTK_TREE_STORE(model), iter,
-                       BNDX_SIZE_COLUMN, txt_new,
-                       -1);
-    g_free(txt_new);
+		       BNDX_SIZE_COLUMN, NULL,
+		       -1);
 
     return FALSE;
 }
@@ -2203,15 +2213,9 @@
 bndx_refresh_date_func(GtkTreeModel * model, GtkTreePath * path,
                        GtkTreeIter * iter, gpointer data)
 {
-    gchar *txt_new;
-    LibBalsaMessage *message = NULL;
-
-    gtk_tree_model_get(model, iter, BNDX_MESSAGE_COLUMN, &message, -1);
-    txt_new = libbalsa_message_date_to_gchar(message, (gchar*) data);
     gtk_tree_store_set(GTK_TREE_STORE(model), iter,
-                       BNDX_DATE_COLUMN, txt_new,
+                       BNDX_DATE_COLUMN, NULL,
                        -1);
-    g_free(txt_new);
 
     return FALSE;
 }
@@ -2436,10 +2440,10 @@
 }
 
 static void
-bndx_add_message(BalsaIndex * index, LibBalsaMessage * message)
+bndx_row_column_set_attrs(BalsaIndex * index, GtkTreeIter *iter,
+			  LibBalsaMessage * message)
 {
     GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(index));
-    GtkTreeIter iter;
     gchar *num, *from, *subject, *date, *size;
     const gchar *name_str = NULL;
     GList *list;
@@ -2447,18 +2451,15 @@
     LibBalsaMailbox* mailbox;
     gboolean append_dots;
 
-    g_return_if_fail(index != NULL);
-    g_return_if_fail(message != NULL);
-
-    if (balsa_app.hide_deleted && LIBBALSA_MESSAGE_IS_DELETED(message))
-        return;
+    num = g_strdup_printf("%ld", LIBBALSA_MESSAGE_GET_NO(message) + 1);
 
     mailbox = index->mailbox_node->mailbox;
-    
-    if (mailbox == NULL)
-	return;
 
-    num = g_strdup_printf("%ld", LIBBALSA_MESSAGE_GET_NO(message) + 1);
+    printf ("Updating %s\n", num);
+    list = g_list_append(NULL, message);
+    libbalsa_mailbox_fetch_headers(mailbox, list,
+				   LIBBALSA_MAILBOX_FETCH_HEADERS_ENVELOPE);
+    g_list_free(list);
 
     append_dots = FALSE;
     if (mailbox->view->show == LB_MAILBOX_SHOW_TO) {
@@ -2484,10 +2485,13 @@
     libbalsa_utf8_sanitize(&subject, balsa_app.convert_unknown_8bit, balsa_app.convert_unknown_8bit_codeset, NULL);
 
     date = libbalsa_message_date_to_gchar(message, balsa_app.date_string);
+
+    if (message->mime_msg) {
     size = libbalsa_message_size_to_gchar(message, balsa_app.line_length);
+    } else
+	size=g_strdup("");
 
-    gtk_tree_store_insert_before(GTK_TREE_STORE(model), &iter, NULL, NULL);
-    gtk_tree_store_set(GTK_TREE_STORE(model), &iter,
+    gtk_tree_store_set(GTK_TREE_STORE(model), iter,
                        BNDX_MESSAGE_COLUMN, message,
                        BNDX_INDEX_COLUMN, num,
                        BNDX_FROM_COLUMN, from,
@@ -2495,7 +2499,10 @@
                        BNDX_DATE_COLUMN, date,
                        BNDX_SIZE_COLUMN, size,
                        BNDX_COLOR_COLUMN, NULL,
-                       BNDX_WEIGHT_COLUMN, PANGO_WEIGHT_NORMAL,
+                       BNDX_WEIGHT_COLUMN,
+		       LIBBALSA_MESSAGE_HAS_FLAG(message, 
+						 LIBBALSA_MESSAGE_FLAG_NEW) ? 
+		       PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL,
                        -1);
     g_free(num);
     g_free(from);
@@ -2503,7 +2510,245 @@
     g_free(date);
     g_free(size);
 
-    bndx_set_col_images(index, &iter, message);
+    bndx_set_col_images(index, iter, message);
+}
+
+static void
+bndx_index_column_set_attrs (GtkTreeViewColumn *tree_column,
+			    GtkCellRenderer *cell,
+			    GtkTreeModel *tree_model,
+			    GtkTreeIter *iter,
+			    gpointer data)
+{
+    gchar *text;
+
+    gtk_tree_model_get (tree_model, iter,
+		  BNDX_INDEX_COLUMN, &text,
+		  -1);
+
+    if (!text) {
+	GdkRectangle rect;
+	GtkTreePath* path;
+	BalsaIndex * index = BALSA_INDEX(tree_column->tree_view);
+
+	/* FIXME: There has to be a better way to test display */
+	path = gtk_tree_model_get_path(tree_model, iter);
+	gtk_tree_view_get_cell_area(GTK_TREE_VIEW(index),
+				    path, tree_column, &rect);
+	gtk_tree_path_free(path);
+	if (rect.width<0 || rect.y<-rect.height) {
+	    text="0";
+	} else {
+	    gchar *txt_new;
+	    LibBalsaMessage *message = NULL;
+
+	    gtk_tree_model_get(tree_model, iter,
+			       BNDX_MESSAGE_COLUMN, &message,
+			       -1);
+	    bndx_row_column_set_attrs(index, iter, message);
+	    gtk_tree_model_get (tree_model, iter,
+				BNDX_INDEX_COLUMN, &text,
+				-1);
+	}
+    }
+
+    g_object_set (cell, "text", text, NULL);
+}
+
+static void
+bndx_from_column_set_attrs (GtkTreeViewColumn *tree_column,
+			    GtkCellRenderer *cell,
+			    GtkTreeModel *tree_model,
+			    GtkTreeIter *iter,
+			    gpointer data)
+{
+    gchar *text;
+    PangoWeight weight;
+
+    gtk_tree_model_get (tree_model, iter,
+		  BNDX_FROM_COLUMN, &text,
+		  BNDX_WEIGHT_COLUMN, &weight,
+		  -1);
+
+    if (!text) {
+	GdkRectangle rect;
+	GtkTreePath* path;
+	BalsaIndex * index = BALSA_INDEX(tree_column->tree_view);
+
+	/* FIXME: There has to be a better way to test display */
+	path = gtk_tree_model_get_path(tree_model, iter);
+	gtk_tree_view_get_cell_area(GTK_TREE_VIEW(index),
+				    path, tree_column, &rect);
+	gtk_tree_path_free(path);
+	if (rect.width<0 || rect.y<-rect.height) {
+	    text="0";
+	} else {
+	    gchar *txt_new;
+	    LibBalsaMessage *message = NULL;
+	    gboolean append_dots;
+	    LibBalsaMailbox* mailbox;
+	    GList *list;
+	    LibBalsaAddress *addy = NULL;
+	    const gchar *name_str = NULL;
+
+	    gtk_tree_model_get(tree_model, iter,
+			       BNDX_MESSAGE_COLUMN, &message,
+			       -1);
+	    bndx_row_column_set_attrs(index, iter, message);
+	    gtk_tree_model_get (tree_model, iter,
+				BNDX_FROM_COLUMN, &text,
+				-1);
+	}
+    }
+
+    g_object_set (cell, "text", text, "weight",weight, NULL);
+}
+
+static void
+bndx_subject_column_set_attrs (GtkTreeViewColumn *tree_column,
+			    GtkCellRenderer *cell,
+			    GtkTreeModel *tree_model,
+			    GtkTreeIter *iter,
+			    gpointer data)
+{
+    gchar *text;
+    PangoWeight weight;
+    GdkColor color;
+
+    gtk_tree_model_get (tree_model, iter,
+		  BNDX_SUBJECT_COLUMN, &text,
+		  BNDX_COLOR_COLUMN, &color,
+		  BNDX_WEIGHT_COLUMN, &weight,
+		  -1);
+
+    if (!text) {
+	GdkRectangle rect;
+	GtkTreePath* path;
+	BalsaIndex * index = BALSA_INDEX(tree_column->tree_view);
+
+	/* FIXME: There has to be a better way to test display */
+	path = gtk_tree_model_get_path(tree_model, iter);
+	gtk_tree_view_get_cell_area(GTK_TREE_VIEW(index),
+				    path, tree_column, &rect);
+	gtk_tree_path_free(path);
+	if (rect.width<0 || rect.y<-rect.height) {
+	    text="0";
+	} else {
+	    gchar *txt_new;
+	    LibBalsaMessage *message = NULL;
+
+	    gtk_tree_model_get(tree_model, iter,
+			       BNDX_MESSAGE_COLUMN, &message,
+			       -1);
+	    bndx_row_column_set_attrs(index, iter, message);
+	    gtk_tree_model_get (tree_model, iter,
+				BNDX_SUBJECT_COLUMN, &text,
+				-1);
+	}
+    }
+
+    g_object_set (cell,
+		  "text", text,
+		  "foreground-gdk", color,
+		  "weight", weight,
+		  NULL);
+}
+
+static void
+bndx_date_column_set_attrs (GtkTreeViewColumn *tree_column,
+			    GtkCellRenderer *cell,
+			    GtkTreeModel *tree_model,
+			    GtkTreeIter *iter,
+			    gpointer data)
+{
+    gchar *text;
+    PangoWeight weight;
+
+    gtk_tree_model_get (tree_model, iter,
+		  BNDX_DATE_COLUMN, &text,
+		  BNDX_WEIGHT_COLUMN, &weight,
+		  -1);
+
+    if (!text) {
+	GdkRectangle rect;
+	GtkTreePath* path;
+	BalsaIndex * index = BALSA_INDEX(tree_column->tree_view);
+
+	/* FIXME: There has to be a better way to test display */
+	path = gtk_tree_model_get_path(tree_model, iter);
+	gtk_tree_view_get_cell_area(GTK_TREE_VIEW(index),
+				    path, tree_column, &rect);
+	gtk_tree_path_free(path);
+	if (rect.width<0 || rect.y<-rect.height) {
+	    text="0";
+	} else {
+	    gchar *txt_new;
+	    LibBalsaMessage *message = NULL;
+
+	    gtk_tree_model_get(tree_model, iter,
+			       BNDX_MESSAGE_COLUMN, &message,
+			       -1);
+	    bndx_row_column_set_attrs(index, iter, message);
+	    gtk_tree_model_get (tree_model, iter,
+				BNDX_DATE_COLUMN, &text,
+				-1);
+	}
+    }
+
+    g_object_set (cell, "text", text, "weight", weight, NULL);
+}
+
+static void
+bndx_size_column_set_attrs (GtkTreeViewColumn *tree_column,
+			    GtkCellRenderer *cell,
+			    GtkTreeModel *tree_model,
+			    GtkTreeIter *iter,
+			    gpointer data)
+{
+    gchar *text;
+    PangoWeight weight;
+
+    gtk_tree_model_get (tree_model, iter,
+		  BNDX_SIZE_COLUMN, &text,
+		  BNDX_WEIGHT_COLUMN, &weight,
+		  -1);
+
+    if (!text) {
+	GdkRectangle rect;
+	GtkTreePath* path;
+	BalsaIndex * index = BALSA_INDEX(tree_column->tree_view);
+
+	/* FIXME: There has to be a better way to test display */
+	path = gtk_tree_model_get_path(tree_model, iter);
+	gtk_tree_view_get_cell_area(GTK_TREE_VIEW(index),
+				    path, tree_column, &rect);
+	gtk_tree_path_free(path);
+	if (rect.width<0 || rect.y<-rect.height) {
+	    text="0";
+	} else {
+	    gchar *txt_new;
+	    LibBalsaMessage *message = NULL;
+
+	    gtk_tree_model_get(tree_model, iter,
+			       BNDX_MESSAGE_COLUMN, &message,
+			       -1);
+	    bndx_row_column_set_attrs(index, iter, message);
+	    gtk_tree_model_get (tree_model, iter,
+				BNDX_SIZE_COLUMN, &text,
+				-1);
+	}
+    }
+
+    g_object_set (cell, "text", text, "weight", weight, NULL);
+}
+
+void
+bndx_model_set_message(GtkTreeModel *model, GtkTreeIter *iter, LibBalsaMessage *message)
+{
+    gtk_tree_store_set(GTK_TREE_STORE(model), iter,
+                       BNDX_MESSAGE_COLUMN, message,
+                       -1);
+
 }
 
 static void
@@ -2599,9 +2844,11 @@
     }
     g_signal_handler_unblock(selection, index->selection_changed_id);
 
+#if FIXME
     /* rethread and select the next message */
     balsa_index_threading(index,
                           index->mailbox_node->mailbox->view->threading_type);
+#endif
     if (next_message)
         bndx_select_message(index, next_message);
     g_get_current_time (&index->last_use);
@@ -2689,19 +2936,53 @@
     bndx_scroll_to_row(index, path);
 }
 
+static void
+mailbox_load_and_thread(LibBalsaMailbox *mailbox, BalsaIndex *index, GList *messages)
+{
+    GList *list;
+	GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(index));
+	g_return_if_fail(index != NULL);
+
+    list = messages;
+    if (!list)
+	list = mailbox->message_list;
+    if (!libbalsa_mailbox_update_model_and_thread(mailbox, model, list)) {
+	for (; list; list = list->next) {
+	    GtkTreeIter iter;
+	    LibBalsaMessage *message = LIBBALSA_MESSAGE(list->data);
+
+	    g_return_if_fail(message != NULL);
+
+	    if (balsa_app.hide_deleted && LIBBALSA_MESSAGE_IS_DELETED(message))
+		continue;
+
+	    gtk_tree_store_insert_before(GTK_TREE_STORE(model), &iter,
+					 NULL, NULL);
+	    bndx_model_set_message(model, &iter, message);
+	}
+	list = messages;
+	if (!list)
+	    list = mailbox->message_list;
+	libbalsa_mailbox_fetch_headers(mailbox, list,
+				       LIBBALSA_MAILBOX_FETCH_HEADERS_ENVELOPE);
+	balsa_index_threading(index, mailbox->view->threading_type);
+    }
+}
+			
 /* Set the tree store, load the messages, and thread. */
 static void
 bndx_load_and_thread(BalsaIndex * index, int thtype)
 {
     LibBalsaMailbox *mailbox;
-    GList *list;
 
     g_hash_table_foreach_remove(index->ref_table, (GHRFunc) gtk_true, NULL);
     bndx_set_tree_store(index);
     mailbox = index->mailbox_node->mailbox;
-    for (list = mailbox->message_list; list; list = list->next)
-        bndx_add_message(index, list->data);
-    bndx_set_threading_type(index, thtype);
+    mailbox->view->threading_type = thtype;
+    mailbox_load_and_thread(mailbox, index, NULL);
+
+    /* expand tree if specified in config */
+    balsa_index_update_tree(index, balsa_app.expand_tree);
     bndx_set_sort_order(index, mailbox->view->sort_field,
                         mailbox->view->sort_type);
 }

PGP signature



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