From fcb4ed5a4f851aabae47aa5c376253246c3f216c Mon Sep 17 00:00:00 2001 From: Not Zed Date: Sat, 17 Mar 2001 04:56:54 +0000 Subject: Move the proxy event outside the lock (otherwise we always deadlock). 2001-03-17 Not Zed * mail-mt.c (mail_msg_free): Move the proxy event outside the lock (otherwise we always deadlock). * mail-local.c (reconfigure_clicked): Clear the message list during update inside the folder thingy. This is a hell mess, need to move the gui stuff to mail-callbacks and make this reconfigure thing a more generic func. * message-list.c (ml_value_to_string): Cleanup the logic to use lookup tables. (sort_uid_to_rows): Removed due to rewrite below. (build_flat_diff): Changes for node/summary/etc changes. Also do changed nodes too. (clear_tree): Free the info reference for nodes in our hashtable. (build_subtree): Ref the info reference in our hash/tree node. (on_click): Dont free message info, since we just got our ref to it. (remove_node_diff): Free messageinfo off node. (build_flat): Ref messageinfo. (message_list_set_folder): Allow a NULL folder to be set - i.e. clear the view. (message_list_set_folder): Emit a no message sleeted signal. (build_tree): Change cursor keeping stuff to work with new info. Turned off BROKEN_ETREE - well maybe it'll work. Check for duplicate messages displayed, etc. 2001-03-16 Not Zed * message-list.h: Added uid_nodemap; mapping of uid's to e-tree nodes. * message-list.c (build_flat): Changed to take a summary argument, and to store node in node map, etc, and store info's in e-tree. (build_subtree): Changed to store node in node map, and to store info's in tree directly. (ml_tree_value_at): Changed to get info directly from tree node, removed allocated return value logic. (ml_tree_value_at): Removed all "fake node" handling, no fake nodes should ever exist. (id_is_uid, id_is_subject, id_uid, id_subject): Removed macro's no longer used. (new_id_from_uid, new_id_from_subject): Removed no longer used. (get_message_uid): (get_message_info): Treat tree node data as messageinfo. (message_list_select): Dont free the messageinfo, as its part of our data, not retrieved from folder. (message_list_drag_data_get): ditto. (subtree_unread): Treat tree node data as messageinfo. (subtree_size): ditto. (subtree_earliest): ditto. (clear_tree): Reset uid_nodemap on clear. (save_node_state): tree nodes == messageinfo's. (add_node_diff): ditto. (remove_node_diff): ditto. (main_folder_changed): use uid_nodemap to lookup changed nodes. (main_message_changed): ditto. svn path=/trunk/; revision=8775 --- mail/ChangeLog | 60 ++++ mail/folder-browser.c | 7 +- mail/mail-callbacks.c | 2 +- mail/mail-local.c | 3 + mail/mail-mt.c | 10 +- mail/message-list.c | 903 +++++++++++++++++--------------------------------- mail/message-list.h | 4 +- 7 files changed, 379 insertions(+), 610 deletions(-) (limited to 'mail') diff --git a/mail/ChangeLog b/mail/ChangeLog index 86117239bb..93b35da7fd 100644 --- a/mail/ChangeLog +++ b/mail/ChangeLog @@ -1,3 +1,63 @@ +2001-03-17 Not Zed + + * mail-mt.c (mail_msg_free): Move the proxy event outside the lock + (otherwise we always deadlock). + + * mail-local.c (reconfigure_clicked): Clear the message list + during update inside the folder thingy. This is a hell mess, need + to move the gui stuff to mail-callbacks and make this reconfigure + thing a more generic func. + + * message-list.c (ml_value_to_string): Cleanup the logic to use + lookup tables. + (sort_uid_to_rows): Removed due to rewrite below. + (build_flat_diff): Changes for node/summary/etc changes. Also do + changed nodes too. + (clear_tree): Free the info reference for nodes in our hashtable. + (build_subtree): Ref the info reference in our hash/tree node. + (on_click): Dont free message info, since we just got our ref to + it. + (remove_node_diff): Free messageinfo off node. + (build_flat): Ref messageinfo. + (message_list_set_folder): Allow a NULL folder to be set - + i.e. clear the view. + (message_list_set_folder): Emit a no message sleeted signal. + (build_tree): Change cursor keeping stuff to work with new info. + + Turned off BROKEN_ETREE - well maybe it'll work. Check for + duplicate messages displayed, etc. + +2001-03-16 Not Zed + + * message-list.h: Added uid_nodemap; mapping of uid's to e-tree + nodes. + + * message-list.c (build_flat): Changed to take a summary argument, + and to store node in node map, etc, and store info's in e-tree. + (build_subtree): Changed to store node in node map, and to store + info's in tree directly. + (ml_tree_value_at): Changed to get info directly from tree node, + removed allocated return value logic. + (ml_tree_value_at): Removed all "fake node" handling, no fake + nodes should ever exist. + (id_is_uid, id_is_subject, id_uid, id_subject): Removed macro's no + longer used. + (new_id_from_uid, new_id_from_subject): Removed no longer used. + (get_message_uid): + (get_message_info): Treat tree node data as messageinfo. + (message_list_select): Dont free the messageinfo, as its part of + our data, not retrieved from folder. + (message_list_drag_data_get): ditto. + (subtree_unread): Treat tree node data as messageinfo. + (subtree_size): ditto. + (subtree_earliest): ditto. + (clear_tree): Reset uid_nodemap on clear. + (save_node_state): tree nodes == messageinfo's. + (add_node_diff): ditto. + (remove_node_diff): ditto. + (main_folder_changed): use uid_nodemap to lookup changed nodes. + (main_message_changed): ditto. + 2001-03-16 Jeffrey Stedfast * mail-crypto.c (pgp_mime_part_sign_prepare_part): New function to diff --git a/mail/folder-browser.c b/mail/folder-browser.c index 8e3474cbd8..e9170b9148 100644 --- a/mail/folder-browser.c +++ b/mail/folder-browser.c @@ -911,8 +911,13 @@ do_message_selected(FolderBrowser *fb) d(printf ("selecting uid %s (delayed)\n", fb->new_uid)); /* keep polling if we are busy */ - if (fb->reconfigure) + if (fb->reconfigure) { + if (fb->new_uid == NULL) { + mail_display_set_message(fb->mail_display, NULL); + return FALSE; + } return TRUE; + } fb->loading_id = 0; diff --git a/mail/mail-callbacks.c b/mail/mail-callbacks.c index 8dc66a58d4..e39dd4c6eb 100644 --- a/mail/mail-callbacks.c +++ b/mail/mail-callbacks.c @@ -1344,7 +1344,7 @@ void configure_folder (BonoboUIComponent *uih, void *user_data, const char *path) { FolderBrowser *fb = FOLDER_BROWSER(user_data); - + mail_local_reconfigure_folder(fb); } diff --git a/mail/mail-local.c b/mail/mail-local.c index 5fd6dab667..574cb981c8 100644 --- a/mail/mail-local.c +++ b/mail/mail-local.c @@ -999,6 +999,9 @@ reconfigure_clicked(GnomeDialog *d, int button, struct _reconfigure_msg *m) int type; char *types[] = { "mbox", "maildir", "mh" }; + /* hack to clear the message list during update */ + message_list_set_folder(m->fb->message_list, NULL); + menu = (GtkMenu *)gtk_option_menu_get_menu(m->optionlist); type = g_list_index(GTK_MENU_SHELL(menu)->children, gtk_menu_get_active(menu)); if (type < 0 || type > 2) diff --git a/mail/mail-mt.c b/mail/mail-mt.c index d450d4d1b1..60fbfaffc0 100644 --- a/mail/mail-mt.c +++ b/mail/mail-mt.c @@ -113,6 +113,7 @@ checkmem(void *p) void mail_msg_free(void *msg) { struct _mail_msg *m = msg; + void *bar = NULL, *label = NULL; #ifdef MALLOC_CHECK checkmem(m); @@ -132,13 +133,13 @@ void mail_msg_free(void *msg) /* this closes the bar, and/or the whole progress dialogue, once we're out of things to do */ if (g_hash_table_size(mail_msg_active) == 0) { if (progress_dialogue != NULL) { - void *data = progress_dialogue; + bar = progress_dialogue; progress_dialogue = NULL; progress_row = 0; - mail_proxy_event(destroy_widgets, NULL, data, NULL); } } else if (m->priv->bar) { - mail_proxy_event(destroy_widgets, NULL, m->priv->bar, m->priv->label); + bar = m->priv->bar; + label = m->priv->label; } if (m->priv->timeout_id > 0) @@ -151,6 +152,9 @@ void mail_msg_free(void *msg) g_free(m->priv->what); g_free(m->priv); g_free(m); + + if (bar || label) + mail_proxy_event(destroy_widgets, NULL, bar, label); } void mail_msg_check_error(void *msg) diff --git a/mail/message-list.c b/mail/message-list.c index c1e180a8bf..1e408f4db9 100644 --- a/mail/message-list.c +++ b/mail/message-list.c @@ -115,12 +115,6 @@ static void hide_load_state(MessageList *ml); /*static void mail_do_regenerate_messagelist (MessageList *list, const char *search, const char *hideexpr, CamelFolderChangeInfo *changes);*/ static void mail_regen_list(MessageList *ml, const char *search, const char *hideexpr, CamelFolderChangeInfo *changes); -/* macros for working with id's (stored in the tree nodes) */ -#define id_is_uid(id) (id[0] == 'u')/* is this a uid id? */ -#define id_is_subject(id) (id[0] == 's') /* is this a subject id? */ -#define id_uid(id) (&id[1]) /* get the uid part of the id */ -#define id_subject(id) (&id[1]) /* get the subject part of the id */ - enum { MESSAGE_SELECTED, LAST_SIGNAL @@ -336,19 +330,16 @@ get_message_uid (MessageList *message_list, int row) { ETreeModel *model = (ETreeModel *)message_list->table_model; ETreePath *node; - const char *uid; + CamelMessageInfo *info; - if (row >= e_table_model_row_count (message_list->table_model)) + if (row >= e_table_model_row_count((ETableModel *)model)) return NULL; node = e_tree_model_node_at_row (model, row); g_return_val_if_fail (node != NULL, NULL); - uid = e_tree_model_node_get_data (model, node); - - if (!id_is_uid(uid)) - return NULL; + info = e_tree_model_node_get_data (model, node); - return id_uid(uid); + return camel_message_info_uid(info); } /* Gets the CamelMessageInfo for the message displayed at the given @@ -357,13 +348,15 @@ get_message_uid (MessageList *message_list, int row) static CamelMessageInfo * get_message_info (MessageList *message_list, int row) { - const char *uid; - - uid = get_message_uid(message_list, row); - if (uid) - return camel_folder_get_message_info(message_list->folder, uid); + ETreeModel *model = (ETreeModel *)message_list->table_model; + ETreePath *node; - return NULL; + if (row >= e_table_model_row_count((ETableModel *)model)) + return NULL; + + node = e_tree_model_node_at_row (model, row); + g_return_val_if_fail (node != NULL, NULL); + return e_tree_model_node_get_data (model, node); } /** @@ -421,10 +414,8 @@ message_list_select (MessageList *message_list, int base_row, if (info && (info->flags & mask) == flags) { e_table_set_cursor_row (et, mrow); gtk_signal_emit(GTK_OBJECT (message_list), message_list_signals [MESSAGE_SELECTED], camel_message_info_uid(info)); - camel_folder_free_message_info(message_list->folder, info); return; } - camel_folder_free_message_info(message_list->folder, info); vrow += direction; } @@ -477,7 +468,6 @@ message_list_drag_data_get (ETable *table, return; } subject = g_strdup (camel_message_info_subject (minfo)); - camel_folder_free_message_info(mlist->folder, minfo); e_filename_make_safe (subject); filename = g_strdup_printf ("%s/%s.eml", tmpdir, subject); g_free (subject); @@ -608,58 +598,41 @@ ml_value_is_empty (ETableModel *etm, int col, const void *value, void *data) } } +static const char *status_map[] = { + N_("Unseen"), + N_("Seen"), + N_("Answered"), + N_("Multiple Unseen Messages"), + N_("Multiple Messages"), +}; + +static const char *score_map[] = { + N_("Lowest"), + N_("Lower"), + N_("Low"), + N_("Normal"), + N_("High"), + N_("Higher"), + N_("Highest"), +}; + static char * ml_value_to_string (ETableModel *etm, int col, const void *value, void *data) { + unsigned int i; + switch (col){ case COL_MESSAGE_STATUS: - switch ((int) value) { - case 0: - return g_strdup (_("Unseen")); - break; - case 1: - return g_strdup (_("Seen")); - break; - case 2: - return g_strdup (_("Answered")); - break; - case 3: - return g_strdup (_("Multiple Unseen Messages")); - break; - case 4: - return g_strdup (_("Multiple Messages")); - break; - default: - return g_strdup (""); - break; - } - break; - + i = (unsigned int)value; + if (i > 4) + return g_strdup(""); + return g_strdup(_(status_map[i])); + case COL_SCORE: - switch ((int) value) { - case -3: - return g_strdup ("Lowest"); - break; - case -2: - return g_strdup ("Lower"); - break; - case -1: - return g_strdup ("Low"); - break; - case 1: - return g_strdup ("High"); - break; - case 2: - return g_strdup ("Higher"); - break; - case 3: - return g_strdup ("Highest"); - break; - default: - return g_strdup ("Normal"); - break; - } - break; + i = (unsigned int)value + 3; + if (i > 6) + i = 3; + return g_strdup(_(score_map[i])); case COL_ATTACHMENT: case COL_FLAGGED: @@ -696,21 +669,15 @@ static int subtree_unread(MessageList *ml, ETreePath *node) { CamelMessageInfo *info; - char *uid; + ETreePath *child; while (node) { - ETreePath *child; - uid = e_tree_model_node_get_data((ETreeModel *)ml->table_model, node); - if (uid == NULL) { - g_warning("I got a NULL uid at node %p", node); - } else if (id_is_uid(uid) - && (info = camel_folder_get_message_info(ml->folder, id_uid(uid)))) { - if (!(info->flags & CAMEL_MESSAGE_SEEN)) { - camel_folder_free_message_info(ml->folder, info); - return TRUE; - } - camel_folder_free_message_info(ml->folder, info); - } + info = e_tree_model_node_get_data((ETreeModel *)ml->table_model, node); + g_assert(info); + + if (!(info->flags & CAMEL_MESSAGE_SEEN)) + return TRUE; + if ((child = e_tree_model_node_get_first_child (E_TREE_MODEL (ml->table_model), node))) if (subtree_unread(ml, child)) return TRUE; @@ -723,19 +690,14 @@ static int subtree_size(MessageList *ml, ETreePath *node) { CamelMessageInfo *info; - char *uid; int size = 0; + ETreePath *child; while (node) { - ETreePath *child; - uid = e_tree_model_node_get_data((ETreeModel *)ml->table_model, node); - if (uid == NULL) { - g_warning("I got a NULL uid at node %p", node); - } else if (id_is_uid(uid) - && (info = camel_folder_get_message_info(ml->folder, id_uid(uid)))) { - size += info->size; - camel_folder_free_message_info(ml->folder, info); - } + info = e_tree_model_node_get_data((ETreeModel *)ml->table_model, node); + g_assert(info); + + size += info->size; if ((child = e_tree_model_node_get_first_child (E_TREE_MODEL (ml->table_model), node))) size += subtree_size(ml, child); @@ -748,24 +710,21 @@ static time_t subtree_earliest(MessageList *ml, ETreePath *node, int sent) { CamelMessageInfo *info; - char *uid; time_t earliest = 0, date; + ETreePath *child; while (node) { - ETreePath *child; - uid = e_tree_model_node_get_data((ETreeModel *)ml->table_model, node); - if (uid == NULL) { - g_warning("I got a NULL uid at node %p", node); - } else if (id_is_uid(uid) - && (info = camel_folder_get_message_info(ml->folder, id_uid(uid)))) { - if (sent) - date = info->date_sent; - else - date = info->date_received; - if (earliest == 0 || date < earliest) - earliest = date; - camel_folder_free_message_info(ml->folder, info); - } + info = e_tree_model_node_get_data((ETreeModel *)ml->table_model, node); + g_assert(info); + + if (sent) + date = info->date_sent; + else + date = info->date_received; + + if (earliest == 0 || date < earliest) + earliest = date; + if ((child = e_tree_model_node_get_first_child (E_TREE_MODEL (ml->table_model), node))) { date = subtree_earliest(ml, child, sent); if (earliest == 0 || (date != 0 && date < earliest)) @@ -782,34 +741,11 @@ static void * ml_tree_value_at (ETreeModel *etm, ETreePath *path, int col, void *model_data) { MessageList *message_list = model_data; - char *uid; - static char *saved; CamelMessageInfo *msg_info; - void *value; - - /* simlated(tm) static dynamic memory (sigh) */ - if (saved) { - g_free(saved); - saved = 0; - } /* retrieve the message information array */ - uid = e_tree_model_node_get_data (etm, path); - if (uid == NULL) { - uid="s ERROR ERROR - UNKNOWN ROW IN TREE"; - goto fake; - } - if (!id_is_uid(uid)) { - g_warning("Invalid node encountered: %s", uid); - goto fake; - } - uid = id_uid(uid); - - msg_info = camel_folder_get_message_info (message_list->folder, uid); - if (msg_info == NULL) { - g_warning("Invalid node encountered: %s", uid); - goto fake; - } + msg_info = e_tree_model_node_get_data (etm, path); + g_assert(msg_info); switch (col){ case COL_MESSAGE_STATUS: { @@ -825,20 +761,16 @@ ml_tree_value_at (ETreeModel *etm, ETreePath *path, int col, void *model_data) } if (msg_info->flags & CAMEL_MESSAGE_ANSWERED) - value = GINT_TO_POINTER (2); + return GINT_TO_POINTER (2); else if (msg_info->flags & CAMEL_MESSAGE_SEEN) - value = GINT_TO_POINTER (1); + return GINT_TO_POINTER (1); else - value = GINT_TO_POINTER (0); + return GINT_TO_POINTER (0); break; } - case COL_FLAGGED: - value = GINT_TO_POINTER ((msg_info->flags & CAMEL_MESSAGE_FLAGGED) != 0); - break; - - case COL_SCORE: - { + return GINT_TO_POINTER ((msg_info->flags & CAMEL_MESSAGE_FLAGGED) != 0); + case COL_SCORE: { const char *tag; int score = 0; @@ -846,45 +778,24 @@ ml_tree_value_at (ETreeModel *etm, ETreePath *path, int col, void *model_data) if (tag) score = atoi (tag); - value = GINT_TO_POINTER (score); - break; + return GINT_TO_POINTER (score); } - case COL_ATTACHMENT: - value = GINT_TO_POINTER ((msg_info->flags & CAMEL_MESSAGE_ATTACHMENTS) != 0); - break; - + return GINT_TO_POINTER ((msg_info->flags & CAMEL_MESSAGE_ATTACHMENTS) != 0); case COL_FROM: - saved = g_strdup (camel_message_info_from(msg_info)); - value = saved; - break; - + return (void *)camel_message_info_from(msg_info); case COL_SUBJECT: - saved = g_strdup (camel_message_info_subject(msg_info)); - value = saved; - break; - + return (void *)camel_message_info_subject(msg_info); case COL_SENT: - value = GINT_TO_POINTER (msg_info->date_sent); - break; - + return GINT_TO_POINTER (msg_info->date_sent); case COL_RECEIVED: - value = GINT_TO_POINTER (msg_info->date_received); - break; - + return GINT_TO_POINTER (msg_info->date_received); case COL_TO: - saved = g_strdup (camel_message_info_to(msg_info)); - value = saved; - break; - + return (void *)camel_message_info_to(msg_info); case COL_SIZE: - value = GINT_TO_POINTER (msg_info->size); - break; - + return GINT_TO_POINTER (msg_info->size); case COL_DELETED: - value = GINT_TO_POINTER ((msg_info->flags & CAMEL_MESSAGE_DELETED) != 0); - break; - + return GINT_TO_POINTER ((msg_info->flags & CAMEL_MESSAGE_DELETED) != 0); case COL_UNREAD: { ETreePath *child; @@ -894,101 +805,21 @@ ml_tree_value_at (ETreeModel *etm, ETreePath *path, int col, void *model_data) return (void *)subtree_unread(message_list, child); } - value = GINT_TO_POINTER (!(msg_info->flags & CAMEL_MESSAGE_SEEN)); - break; + return GINT_TO_POINTER (!(msg_info->flags & CAMEL_MESSAGE_SEEN)); } - case COL_COLOUR: - { + case COL_COLOUR: { const char *colour; - colour = camel_tag_get ((CamelTag **) &msg_info->user_tags, - "colour"); - if (colour) { - saved = g_strdup (colour); - value = saved; - } else if (msg_info->flags & CAMEL_MESSAGE_FLAGGED) + colour = camel_tag_get ((CamelTag **) &msg_info->user_tags, "colour"); + if (colour == NULL && msg_info->flags & CAMEL_MESSAGE_FLAGGED) /* FIXME: extract from the xpm somehow. */ - value = "#A7453E"; - else - value = NULL; - break; + colour = "#A7453E"; + return (void *)colour; } } - camel_folder_free_message_info(message_list->folder, msg_info); - return value; - g_assert_not_reached (); - - fake: - /* This is a fake tree parent */ - switch (col){ - case COL_UNREAD: - /* this value should probably be cached, as it could take a bit - of processing to evaluate all the time */ - return (void *)subtree_unread(message_list, e_tree_model_node_get_first_child(etm, path)); - - case COL_MESSAGE_STATUS: - /* The same applies as for COL_UNREAD just above */ - if (subtree_unread(message_list, e_tree_model_node_get_first_child(etm,path))) - return (void *)3; - else - return (void *)4; - - case COL_FLAGGED: - case COL_SCORE: - case COL_ATTACHMENT: - case COL_DELETED: - case COL_COLOUR: - return (void *) 0; - case COL_SENT: - return (void *)subtree_earliest(message_list, e_tree_model_node_get_first_child(etm, path), TRUE); - - case COL_RECEIVED: - return (void *)subtree_earliest(message_list, e_tree_model_node_get_first_child(etm, path), FALSE); - - case COL_SUBJECT: - saved = g_strdup_printf(_("[ %s ]"), id_subject(uid)); - return saved; - - case COL_FROM: { - ETreePath *child; - - /* the first child should always exist/etc */ - if ( (child = e_tree_model_node_get_first_child(etm, path)) - && (uid = e_tree_model_node_get_data (etm, child)) - && id_is_uid(uid) - && (msg_info = camel_folder_get_message_info (message_list->folder, id_uid(uid))) ) { - /* well, we could scan more children, build up a (more accurate) list, but this should do ok */ - saved = g_strdup_printf(_("%s, et al."), camel_message_info_from(msg_info)); - camel_folder_free_message_info(message_list->folder, msg_info); - } else { - return _(""); - } - return saved; - } - case COL_TO: { - ETreePath *child; - - /* the first child should always exist/etc */ - if ( (child = e_tree_model_node_get_first_child(etm, path)) - && (uid = e_tree_model_node_get_data (etm, child)) - && id_is_uid(uid) - && (msg_info = camel_folder_get_message_info (message_list->folder, id_uid(uid))) ) { - /* well, we could scan more children, build up a (more accurate) list, but this should do ok */ - saved = g_strdup_printf(_("%s, et al."), camel_message_info_to(msg_info)); - camel_folder_free_message_info(message_list->folder, msg_info); - } else { - return _(""); - } - return saved; - } - case COL_SIZE: - return GINT_TO_POINTER (subtree_size(message_list, e_tree_model_node_get_first_child(etm, path))); - } - g_assert_not_reached (); - return NULL; } @@ -1238,14 +1069,14 @@ message_list_init (GtkObject *object) e_scroll_frame_set_policy (E_SCROLL_FRAME (message_list), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); - message_list->uid_rowmap = g_hash_table_new (g_str_hash, g_str_equal); - message_list->uid_pool = e_mempool_new(1024, 512, E_MEMPOOL_ALIGN_BYTE); message_list->hidden = NULL; message_list->hidden_pool = NULL; message_list->hide_before = ML_HIDE_NONE_START; message_list->hide_after = ML_HIDE_NONE_END; message_list->hide_lock = g_mutex_new(); + + message_list->uid_nodemap = g_hash_table_new (g_str_hash, g_str_equal); } static void @@ -1260,9 +1091,6 @@ message_list_destroy (GtkObject *object) } gtk_object_unref (GTK_OBJECT (message_list->table_model)); - - g_hash_table_destroy (message_list->uid_rowmap); - e_mempool_destroy(message_list->uid_pool); if (message_list->idle_id != 0) g_source_remove(message_list->idle_id); @@ -1380,6 +1208,15 @@ message_list_new (void) return GTK_WIDGET (message_list); } +static void +clear_info(char *key, ETreePath *node, MessageList *ml) +{ + CamelMessageInfo *info; + + info = e_tree_model_node_get_data((ETreeModel *)ml->table_model, node); + camel_folder_free_message_info(ml->folder, info); +} + static void clear_tree (MessageList *ml) { @@ -1394,9 +1231,10 @@ clear_tree (MessageList *ml) #endif /* we also reset the uid_rowmap since it is no longer useful/valid anyway */ - g_hash_table_destroy (ml->uid_rowmap); - ml->uid_rowmap = g_hash_table_new(g_str_hash, g_str_equal); - e_mempool_flush(ml->uid_pool, TRUE); + if (ml->folder) + g_hash_table_foreach(ml->uid_nodemap, (GHFunc)clear_info, ml); + g_hash_table_destroy (ml->uid_nodemap); + ml->uid_nodemap = g_hash_table_new(g_str_hash, g_str_equal); if (ml->tree_root) { /* we should be frozen already */ @@ -1420,27 +1258,16 @@ clear_tree (MessageList *ml) static void save_node_state(MessageList *ml, FILE *out, ETreePath *node) { - char *data; CamelMessageInfo *info; while (node) { ETreePath *child = e_tree_model_node_get_first_child (E_TREE_MODEL (ml->table_model), node); - if (child - && !e_tree_model_node_is_expanded((ETreeModel *)ml->table_model, node)) { - data = e_tree_model_node_get_data((ETreeModel *)ml->table_model, node); - if (data) { - if (id_is_uid(data)) { - info = camel_folder_get_message_info(ml->folder, id_uid(data)); - if (info) { - fprintf(out, "%08x%08x\n", info->message_id.id.part.hi, info->message_id.id.part.lo); - camel_folder_free_message_info(ml->folder, info); - } - } else { - fprintf(out, "%s\n", data); - } - } - } if (child) { + if (!e_tree_model_node_is_expanded((ETreeModel *)ml->table_model, node)) { + info = e_tree_model_node_get_data((ETreeModel *)ml->table_model, node); + g_assert(info); + fprintf(out, "%08x%08x\n", info->message_id.id.part.hi, info->message_id.id.part.lo); + } save_node_state(ml, out, child); } node = e_tree_model_node_get_next (E_TREE_MODEL (ml->table_model), node); @@ -1525,7 +1352,7 @@ build_tree (MessageList *ml, CamelFolderThread *thread, CamelFolderChangeInfo *c GHashTable *expanded_nodes; ETreeModel *etm = (ETreeModel *)ml->table_model; ETreePath *top; - char *uid = NULL; + char *saveuid = NULL; #ifdef TIMEIT struct timeval start, end; @@ -1548,49 +1375,44 @@ build_tree (MessageList *ml, CamelFolderThread *thread, CamelFolderChangeInfo *c e_tree_model_node_set_expanded(etm, ml->tree_root, TRUE); } -#define BROKEN_ETREE /* avoid some broken code in etree(?) by not using the incremental update */ + if (ml->cursor_uid) + saveuid = g_strdup(ml->cursor_uid); + +/*#define BROKEN_ETREE*/ /* avoid some broken code in etree(?) by not using the incremental update */ top = e_tree_model_node_get_first_child(etm, ml->tree_root); #ifndef BROKEN_ETREE if (top == NULL || changes == NULL) { #endif - if (ml->cursor_uid) { - uid = g_strdup(ml->cursor_uid); - printf("current uid = %s\n", uid); - } - e_tree_model_freeze(etm); clear_tree (ml); build_subtree(ml, ml->tree_root, thread->tree, &row, expanded_nodes); e_tree_model_thaw(etm); - - if (uid) { - int row; - char *dummy; - - if (g_hash_table_lookup_extended(ml->uid_rowmap, uid, (void **)&dummy, (void **)&row)) { - printf("selecting uid %s row %d\n", uid, row); - e_table_set_cursor_row(ml->table, row); - } else { - printf("cannot find uid %s\n", uid); - g_free(ml->cursor_uid); - ml->cursor_uid = NULL; - gtk_signal_emit((GtkObject *)ml, message_list_signals[MESSAGE_SELECTED], NULL); - } - g_free(uid); - } - #ifndef BROKEN_ETREE } else { static int tree_equal(ETreeModel *etm, ETreePath *ap, CamelFolderThreadNode *bp); build_subtree_diff(ml, ml->tree_root, top, thread->tree, &row, expanded_nodes); top = e_tree_model_node_get_first_child(etm, ml->tree_root); - tree_equal(ml->table_model, top, thread->tree); + tree_equal((ETreeModel *)ml->table_model, top, thread->tree); } #endif + + if (saveuid) { + ETreePath *node = g_hash_table_lookup(ml->uid_nodemap, saveuid); + if (node == NULL) { + g_free(ml->cursor_uid); + ml->cursor_uid = NULL; + gtk_signal_emit((GtkObject *)ml, message_list_signals[MESSAGE_SELECTED], NULL); + } else { + int row = e_tree_model_row_of_node(etm, node); + e_table_set_cursor_row(ml->table, row); + } + g_free(saveuid); + } + free_tree_state(expanded_nodes); #ifdef TIMEIT @@ -1602,32 +1424,6 @@ build_tree (MessageList *ml, CamelFolderThread *thread, CamelFolderChangeInfo *c } -static char * -new_id_from_uid(MessageList *ml, const char *uid) -{ - char *res; - int len; - - len = strlen(uid)+2; - res = e_mempool_alloc(ml->uid_pool, len); - res[0] = 'u'; - strcpy(res+1, uid); - return res; -} - -static char * -new_id_from_subject(MessageList *ml, const char *subject) -{ - char *res; - int len; - - len = strlen(subject)+2; - res = e_mempool_alloc(ml->uid_pool, len); - res[0] = 's'; - strcpy(res+1, subject); - return res; -} - /* this is about 20% faster than build_subtree_diff, entirely because e_tree_model_node_insert(xx, -1 xx) is faster than inserting to the right row :( */ @@ -1637,32 +1433,18 @@ build_subtree (MessageList *ml, ETreePath *parent, CamelFolderThreadNode *c, int { ETreeModel *tree = E_TREE_MODEL (ml->table_model); ETreePath *node; - char *id; - int expanded = FALSE; while (c) { - if (c->message) { - id = new_id_from_uid(ml, camel_message_info_uid(c->message)); - g_hash_table_insert(ml->uid_rowmap, id_uid(id), GINT_TO_POINTER ((*row)++)); - if (c->child) { - if (c->message) { - char key[17]; - sprintf(key, "%08x%08x", c->message->message_id.id.part.hi, c->message->message_id.id.part.lo); - expanded = !g_hash_table_lookup(expanded_nodes, key) != 0; - } else - expanded = TRUE; - } - } else { - id = new_id_from_subject(ml, c->root_subject); - if (c->child) { - expanded = !g_hash_table_lookup(expanded_nodes, id) != 0; - } - } - node = e_tree_model_node_insert(tree, parent, -1, id); + /* phantom nodes no longer allowed */ + g_assert(c->message); + + node = e_tree_model_node_insert(tree, parent, -1, (void *)c->message); + g_hash_table_insert(ml->uid_nodemap, (void *)camel_message_info_uid(c->message), node); + camel_folder_ref_message_info(ml->folder, (CamelMessageInfo *)c->message); if (c->child) { - /* by default, open all trees */ - if (expanded) - e_tree_model_node_set_expanded(tree, node, expanded); + char key[17]; + sprintf(key, "%08x%08x", c->message->message_id.id.part.hi, c->message->message_id.id.part.lo); + e_tree_model_node_set_expanded(tree, node, g_hash_table_lookup(expanded_nodes, key) == 0); build_subtree(ml, node, c->child, row, expanded_nodes); } c = c->next; @@ -1674,17 +1456,13 @@ build_subtree (MessageList *ml, ETreePath *parent, CamelFolderThreadNode *c, int static int node_equal(ETreeModel *etm, ETreePath *ap, CamelFolderThreadNode *bp) { - char *uid; + CamelMessageInfo *info; - uid = e_tree_model_node_get_data(etm, ap); + info = e_tree_model_node_get_data(etm, ap); + + if (bp->message && strcmp(camel_message_info_uid(info), camel_message_info_uid(bp->message))==0) + return 1; - if (id_is_uid(uid)) { - if (bp->message && strcmp(id_uid(uid), camel_message_info_uid(bp->message))==0) - return 1; - } else if (id_is_subject(uid)) { - if (bp->message == NULL && strcmp(id_subject(uid), bp->root_subject) == 0) - return 1; - } return 0; } @@ -1693,20 +1471,14 @@ node_equal(ETreeModel *etm, ETreePath *ap, CamelFolderThreadNode *bp) static int tree_equal(ETreeModel *etm, ETreePath *ap, CamelFolderThreadNode *bp) { - char *uid; + CamelMessageInfo *info; while (ap && bp) { if (!node_equal(etm, ap, bp)) { g_warning("Nodes in tree differ"); - uid = e_tree_model_node_get_data(etm, ap); - if (id_is_uid(uid)) - printf("table uid = %s\n", id_uid(uid)); - else - printf("table subject = %s\n", id_subject(uid)); - if (bp->message) - printf("camel uid = %s\n", camel_message_info_uid(bp->message)); - else - printf("camel subject = %s\n", bp->root_subject); + info = e_tree_model_node_get_data(etm, ap); + printf("table uid = %s\n", camel_message_info_uid(info)); + printf("camel uid = %s\n", camel_message_info_uid(bp->message)); return FALSE; } else { if (!tree_equal(etm, e_tree_model_node_get_first_child(etm, ap), bp->child)) @@ -1719,20 +1491,14 @@ tree_equal(ETreeModel *etm, ETreePath *ap, CamelFolderThreadNode *bp) if (ap || bp) { g_warning("Tree differs, out of nodes in one branch"); if (ap) { - uid = e_tree_model_node_get_data(etm, ap); - if (uid) { - if (id_is_uid(uid)) - printf("table uid = %s\n", id_uid(uid)); - else - printf("table subject = %s\n", id_subject(uid)); - } else - printf("uid is empty?\n"); + info = e_tree_model_node_get_data(etm, ap); + if (info) + printf("table uid = %s\n", camel_message_info_uid(info)); + else + printf("info is empty?\n"); } if (bp) { - if (bp->message) - printf("camel uid = %s\n", camel_message_info_uid(bp->message)); - else - printf("camel subject = %s\n", bp->root_subject); + printf("camel uid = %s\n", camel_message_info_uid(bp->message)); return FALSE; } return FALSE; @@ -1747,36 +1513,20 @@ add_node_diff(MessageList *ml, ETreePath *parent, ETreePath *path, CamelFolderTh { ETreeModel *etm = E_TREE_MODEL (ml->table_model); ETreePath *node; - char *id; - int expanded = FALSE; - - if (c->message) { - id = new_id_from_uid(ml, camel_message_info_uid(c->message)); - /* need to remove the id first, as GHashTable' wont replace the key pointer for us */ - g_hash_table_remove(ml->uid_rowmap, id_uid(id)); - g_hash_table_insert(ml->uid_rowmap, id_uid(id), GINT_TO_POINTER (*row)); - if (c->child) { - if (c->message) { - char key[17]; - sprintf(key, "%08x%08x", c->message->message_id.id.part.hi, c->message->message_id.id.part.lo); - expanded = !g_hash_table_lookup(expanded_nodes, key) != 0; - } else - expanded = TRUE; - } - } else { - id = new_id_from_subject(ml, c->root_subject); - if (c->child) { - expanded = !g_hash_table_lookup(expanded_nodes, id) != 0; - } - } - t(printf("Adding node: %s row %d\n", id, myrow)); - - node = e_tree_model_node_insert(etm, parent, myrow, id); + g_assert(c->message); + + /* we just update the hashtable key, umm, does this leak the info on the message node? */ + g_hash_table_remove(ml->uid_nodemap, camel_message_info_uid(c->message)); + node = e_tree_model_node_insert(etm, parent, myrow, (void *)c->message); + g_hash_table_insert(ml->uid_nodemap, (void *)camel_message_info_uid(c->message), node); + camel_folder_ref_message_info(ml->folder, (CamelMessageInfo *)c->message); (*row)++; + if (c->child) { - e_tree_model_node_set_expanded(etm, node, expanded); - t(printf("Building subtree ...\n")); + char key[17]; + sprintf(key, "%08x%08x", c->message->message_id.id.part.hi, c->message->message_id.id.part.lo); + e_tree_model_node_set_expanded(etm, node, g_hash_table_lookup(expanded_nodes, key) == 0); build_subtree_diff(ml, node, NULL, c->child, row, expanded_nodes); } } @@ -1787,8 +1537,7 @@ remove_node_diff(MessageList *ml, ETreePath *node, int depth) { ETreeModel *etm = E_TREE_MODEL (ml->table_model); ETreePath *cp, *cn; - char *uid, *olduid; - int oldrow; + CamelMessageInfo *info; t(printf("Removing node: %s\n", (char *)e_tree_model_node_get_data(etm, node))); @@ -1801,13 +1550,10 @@ remove_node_diff(MessageList *ml, ETreePath *node, int depth) } /* and the rowid entry - if and only if it is referencing this node */ - uid = e_tree_model_node_get_data(etm, node); - if (id_is_uid(uid) - && g_hash_table_lookup_extended(ml->uid_rowmap, id_uid(uid), (void *)&olduid, (void *)&oldrow) - && olduid == id_uid(uid)) { - t(printf("removing rowid map entry: %s\n", id_uid(uid))); - g_hash_table_remove(ml->uid_rowmap, id_uid(uid)); - } + info = e_tree_model_node_get_data(etm, node); + g_assert(info); + g_hash_table_remove(ml->uid_nodemap, camel_message_info_uid(info)); + camel_folder_free_message_info(ml->folder, info); e_tree_model_node_set_data(etm, node, NULL); /* and only at the toplevel, remove the node (etree should optimise this remove somewhat) */ @@ -1845,10 +1591,10 @@ build_subtree_diff(MessageList *ml, ETreePath *parent, ETreePath *path, CamelFol } else if (node_equal(etm, ap, bp)) { /*t(printf("nodes match, verify\n"));*/ /* matching nodes, verify details/children */ +#if 0 if (bp->message) { char *olduid; int oldrow; - /* if this is a message row, check/update the row id map */ if (g_hash_table_lookup_extended(ml->uid_rowmap, camel_message_info_uid(bp->message), (void *)&olduid, (void *)&oldrow)) { if (oldrow != (*row)) { @@ -1859,6 +1605,7 @@ build_subtree_diff(MessageList *ml, ETreePath *parent, ETreePath *path, CamelFol /*g_assert_not_reached();*/ } } +#endif *row = (*row)+1; myrow++; tmp = e_tree_model_node_get_first_child(etm, ap); @@ -1932,9 +1679,9 @@ static void build_flat_diff(MessageList *ml, CamelFolderChangeInfo *changes); #endif static void -build_flat (MessageList *ml, GPtrArray *uids, CamelFolderChangeInfo *changes) +build_flat (MessageList *ml, GPtrArray *summary, CamelFolderChangeInfo *changes) { - ETreeModel *tree = E_TREE_MODEL (ml->table_model); + ETreeModel *etm = E_TREE_MODEL (ml->table_model); ETreePath *node; char *saveuid = NULL; int i; @@ -1947,43 +1694,42 @@ build_flat (MessageList *ml, GPtrArray *uids, CamelFolderChangeInfo *changes) gettimeofday(&start, NULL); #endif + if (ml->cursor_uid) + saveuid = g_strdup(ml->cursor_uid); + #ifndef BROKEN_ETREE if (changes) { build_flat_diff(ml, changes); } else { #endif - if (ml->cursor_uid) - saveuid = g_strdup(ml->cursor_uid); - - e_tree_model_freeze(tree); + e_tree_model_freeze(etm); clear_tree (ml); - for (i = 0; i < uids->len; i++) { - char *uid = new_id_from_uid(ml, uids->pdata[i]); - node = e_tree_model_node_insert (tree, ml->tree_root, -1, uid); - g_hash_table_insert (ml->uid_rowmap, id_uid(uid), GINT_TO_POINTER (i)); - } - e_tree_model_thaw(tree); + for (i = 0; i < summary->len; i++) { + CamelMessageInfo *info = summary->pdata[i]; - if (saveuid) { - int row; - char *dummy; - - if (g_hash_table_lookup_extended(ml->uid_rowmap, saveuid, (void **)&dummy, (void **)&row)) { - printf("re-selecting %s rwo %d\n", saveuid, row); - e_table_set_cursor_row(ml->table, row); - } else { - printf("can't find uid %s anymore\n", saveuid); - g_free(ml->cursor_uid); - ml->cursor_uid = NULL; - gtk_signal_emit((GtkObject *)ml, message_list_signals[MESSAGE_SELECTED], NULL); - } - - g_free(saveuid); + node = e_tree_model_node_insert(etm, ml->tree_root, -1, info); + g_hash_table_insert(ml->uid_nodemap, (void *)camel_message_info_uid(info), node); + camel_folder_ref_message_info(ml->folder, info); } + e_tree_model_thaw(etm); + #ifndef BROKEN_ETREE } #endif + if (saveuid) { + node = g_hash_table_lookup(ml->uid_nodemap, saveuid); + if (node == NULL) { + g_free(ml->cursor_uid); + ml->cursor_uid = NULL; + gtk_signal_emit((GtkObject *)ml, message_list_signals[MESSAGE_SELECTED], NULL); + } else { + int row = e_tree_model_row_of_node(etm, node); + e_table_set_cursor_row(ml->table, row); + } + g_free(saveuid); + } + #ifdef TIMEIT gettimeofday(&end, NULL); diff = end.tv_sec * 1000 + end.tv_usec/1000; @@ -1995,51 +1741,12 @@ build_flat (MessageList *ml, GPtrArray *uids, CamelFolderChangeInfo *changes) #ifndef BROKEN_ETREE -/* used to sort the rows to match list order */ -struct _uidsort { - int row; - char *uid; -}; - -static int -sort_uid_cmp(const void *ap, const void *bp) -{ - const struct _uidsort *a = (struct _uidsort *)ap; - const struct _uidsort *b = (struct _uidsort *)bp; - - if (a->row < b->row) - return -1; - else if (a->row > b->row) - return 1; - return 0; -} - -static void -sort_uid_to_rows(MessageList *ml, GPtrArray *uids) -{ - struct _uidsort *uidlist; - int i; - - uidlist = g_malloc(sizeof(struct _uidsort) * uids->len); - for (i=0;ilen;i++) { - uidlist[i].row = (int)g_hash_table_lookup(ml->uid_rowmap, uids->pdata[i]); - uidlist[i].uid = uids->pdata[i]; - } - qsort(uidlist, uids->len, sizeof(struct _uidsort), sort_uid_cmp); - for (i=0;ilen;i++) { - uids->pdata[i] = uidlist[i].uid; - } - g_free(uidlist); -} - static void build_flat_diff(MessageList *ml, CamelFolderChangeInfo *changes) { - int row, i; + int i; ETreePath *node; - char *uid; - int oldrow; - char *olduid; + CamelMessageInfo *info; #ifdef TIMEIT struct timeval start, end; @@ -2051,62 +1758,34 @@ build_flat_diff(MessageList *ml, CamelFolderChangeInfo *changes) printf("updating changes to display\n"); /* remove individual nodes? */ - if (changes->uid_removed->len > 0) { - /* first, we need to sort the row id's to match the summary order */ - sort_uid_to_rows(ml, changes->uid_removed); - - /* we remove from the end, so that the rowmap remains valid as we go */ - d(printf("Removing messages from view:\n")); - for (i=changes->uid_removed->len-1;i>=0;i--) { - d(printf(" %s\n", (char *)changes->uid_removed->pdata[i])); - if (g_hash_table_lookup_extended(ml->uid_rowmap, changes->uid_removed->pdata[i], (void *)&olduid, (void *)&row)) { - node = e_tree_model_node_at_row((ETreeModel *)ml->table_model, row); - uid = e_tree_model_node_get_data((ETreeModel *)ml->table_model, node); - if (uid && id_is_uid(uid) && !strcmp(id_uid(uid), changes->uid_removed->pdata[i])) { - g_hash_table_remove(ml->uid_rowmap, olduid); - e_tree_model_node_remove((ETreeModel *)ml->table_model, node); - d(printf(" - removed\n")); - } else { - d(printf(" - is this the right uid, it doesn't match my map?\n")); - } - } + d(printf("Removing messages from view:\n")); + for (i=0;iuid_removed->len;i++) { + node = g_hash_table_lookup(ml->uid_nodemap, changes->uid_removed->pdata[i]); + if (node) { + info = e_tree_model_node_get_data((ETreeModel *)ml->table_model, node); + camel_folder_free_message_info(ml->folder, info); + g_hash_table_remove(ml->uid_nodemap, changes->uid_removed->pdata[i]); + e_tree_model_node_remove((ETreeModel *)ml->table_model, node); } } /* add new nodes? - just append to the end */ - if (changes->uid_added->len > 0) { - node = e_tree_model_node_get_last_child((ETreeModel *)ml->table_model, ml->tree_root); - row = e_tree_model_row_of_node((ETreeModel *)ml->table_model, node) + 1; - d(printf("Adding messages to view:\n")); - for (i=0;iuid_added->len;i++) { + d(printf("Adding messages to view:\n")); + for (i=0;iuid_added->len;i++) { + info = camel_folder_get_message_info(ml->folder, changes->uid_added->pdata[i]); + if (info) { d(printf(" %s\n", (char *)changes->uid_added->pdata[i])); - uid = new_id_from_uid(ml, changes->uid_added->pdata[i]); - node = e_tree_model_node_insert((ETreeModel *)ml->table_model, ml->tree_root, row, uid); - g_hash_table_insert(ml->uid_rowmap, id_uid(uid), GINT_TO_POINTER (row)); - row++; + node = e_tree_model_node_insert((ETreeModel *)ml->table_model, ml->tree_root, -1, info); + g_hash_table_insert(ml->uid_nodemap, (void *)camel_message_info_uid(info), node); } } - /* now, check the rowmap, some rows might've changed (with removes) */ - if (changes->uid_removed->len) { - d(printf("checking uid mappings\n")); - row = 0; - node = e_tree_model_node_get_first_child ((ETreeModel *)ml->table_model, ml->tree_root); - while (node) { - uid = e_tree_model_node_get_data((ETreeModel *)ml->table_model, node); - if (id_is_uid(uid)) { - if (g_hash_table_lookup_extended(ml->uid_rowmap, id_uid(uid), (void *)&olduid, (void *)&oldrow)) { - if (oldrow != row) { - d(printf("row %d moved to new row %d\n", oldrow, row)); - g_hash_table_insert(ml->uid_rowmap, olduid, (void *)row); - } - } else { /* missing? shouldn't happen */ - g_warning("Uid vanished from rowmap?: %s\n", uid); - } - } - row++; - node = e_tree_model_node_get_next((ETreeModel *)ml->table_model, node); - } + /* and update changes too */ + d(printf("Changing messages to view:\n")); + for (i=0;iuid_changed->len;i++) { + ETreePath *node = g_hash_table_lookup(ml->uid_nodemap, changes->uid_changed->pdata[i]); + if (node) + e_tree_model_node_changed((ETreeModel *)ml->table_model, node); } #ifdef TIMEIT @@ -2133,9 +1812,9 @@ main_folder_changed (CamelObject *o, gpointer event_data, gpointer user_data) int i; for (i=0;iuid_changed->len;i++) { - int row = GPOINTER_TO_INT (g_hash_table_lookup (ml->uid_rowmap, changes->uid_changed->pdata[i])); - if (row != -1) - e_table_model_row_changed(ml->table_model, row); + ETreePath *node = g_hash_table_lookup (ml->uid_nodemap, changes->uid_changed->pdata[i]); + if (node) + e_tree_model_node_changed((ETreeModel *)ml->table_model, node); } camel_folder_change_info_free(changes); @@ -2167,12 +1846,11 @@ static void main_message_changed (CamelObject *o, gpointer uid, gpointer user_data) { MessageList *message_list = MESSAGE_LIST (user_data); - int row; + ETreePath *node; - row = GPOINTER_TO_INT (g_hash_table_lookup (message_list->uid_rowmap, - uid)); - if (row != -1) - e_table_model_row_changed (message_list->table_model, row); + node = g_hash_table_lookup (message_list->uid_nodemap, uid); + if (node) + e_tree_model_node_changed ((ETreeModel *)message_list->table_model, node); g_free (uid); } @@ -2193,16 +1871,15 @@ message_list_set_folder (MessageList *message_list, CamelFolder *camel_folder) CamelException ex; g_return_if_fail (message_list != NULL); - g_return_if_fail (camel_folder != NULL); g_return_if_fail (IS_MESSAGE_LIST (message_list)); - g_return_if_fail (CAMEL_IS_FOLDER (camel_folder)); - g_return_if_fail (camel_folder_has_summary_capability (camel_folder)); if (message_list->folder == camel_folder) return; camel_exception_init (&ex); + clear_tree(message_list); + if (message_list->folder) { hide_save_state(message_list); camel_object_unhook_event((CamelObject *)message_list->folder, "folder_changed", @@ -2214,20 +1891,26 @@ message_list_set_folder (MessageList *message_list, CamelFolder *camel_folder) message_list->folder = camel_folder; - /* build the etable suitable for this folder */ - message_list_setup_etable(message_list); - - camel_object_hook_event(CAMEL_OBJECT (camel_folder), "folder_changed", - folder_changed, message_list); - camel_object_hook_event(CAMEL_OBJECT (camel_folder), "message_changed", - message_changed, message_list); - - camel_object_ref (CAMEL_OBJECT (camel_folder)); + if (message_list->cursor_uid) { + g_free(message_list->cursor_uid); + message_list->cursor_uid = NULL; + gtk_signal_emit((GtkObject *)message_list, message_list_signals[MESSAGE_SELECTED], NULL); + } - hide_load_state(message_list); + if (camel_folder) { + /* build the etable suitable for this folder */ + message_list_setup_etable(message_list); + + camel_object_hook_event(CAMEL_OBJECT (camel_folder), "folder_changed", + folder_changed, message_list); + camel_object_hook_event(CAMEL_OBJECT (camel_folder), "message_changed", + message_changed, message_list); + + camel_object_ref (CAMEL_OBJECT (camel_folder)); - clear_tree(message_list); - mail_regen_list(message_list, message_list->search, NULL, NULL); + hide_load_state(message_list); + mail_regen_list(message_list, message_list->search, NULL, NULL); + } } E_MAKE_TYPE (message_list, "MessageList", MessageList, message_list_class_init, message_list_init, PARENT_TYPE); @@ -2281,7 +1964,6 @@ on_click (ETableScrolled *table, gint row, gint col, GdkEvent *event, MessageLis } camel_folder_set_message_flags(list->folder, camel_message_info_uid(info), flag, ~info->flags); - camel_folder_free_message_info(list->folder, info); if (flag == CAMEL_MESSAGE_SEEN && list->seen_id) { gtk_timeout_remove (list->seen_id); @@ -2390,7 +2072,7 @@ void message_list_hide_uids(MessageList *ml, GPtrArray *uids) /* first see if we need to do any work, if so, then do it all at once */ for (i=0;ilen;i++) { - if (g_hash_table_lookup(ml->uid_rowmap, uids->pdata[i])) { + if (g_hash_table_lookup(ml->uid_nodemap, uids->pdata[i])) { MESSAGE_LIST_LOCK(ml, hide_lock); if (ml->hidden == NULL) { ml->hidden = g_hash_table_new(g_str_hash, g_str_equal); @@ -2400,7 +2082,7 @@ void message_list_hide_uids(MessageList *ml, GPtrArray *uids) uid = e_mempool_strdup(ml->hidden_pool, uids->pdata[i]); g_hash_table_insert(ml->hidden, uid, uid); for (;ilen;i++) { - if (g_hash_table_lookup(ml->uid_rowmap, uids->pdata[i])) { + if (g_hash_table_lookup(ml->uid_nodemap, uids->pdata[i])) { uid = e_mempool_strdup(ml->hidden_pool, uids->pdata[i]); g_hash_table_insert(ml->hidden, uid, uid); } @@ -2512,28 +2194,37 @@ struct _regen_list_msg { char *hideexpr; CamelFolderChangeInfo *changes; gboolean dotree; /* we are building a tree */ - - GPtrArray *uids, /* list of uid's to use, if realuids is NULL, this is the actual uid's from search, else a simple ptrarray */ - *realuids; /* actual uid's from search/get_uid's, or NULL */ CamelFolderThread *tree; + + CamelFolder *folder; + GPtrArray *summary; }; +/* + maintain copy of summary + + any new messages added + any removed removed, etc. + + use vfolder to implement searches ??? + + */ static void regen_list_regen(struct _mail_msg *mm) { struct _regen_list_msg *m = (struct _regen_list_msg *)mm; int i; - GPtrArray *uids, *uidnew; + GPtrArray *uids, *uidnew, *showuids; + CamelMessageInfo *info; - if (m->search) { - m->uids = camel_folder_search_by_expression(m->ml->folder, m->search, &mm->ex); - } else { - m->uids = camel_folder_get_uids(m->ml->folder); - } + if (m->search) + uids = camel_folder_search_by_expression(m->folder, m->search, &mm->ex); + else + uids = camel_folder_get_uids(m->folder); if (camel_exception_is_set(&mm->ex)) return; - /* see if we have a new expression to hide on */ + /* perform hiding */ if (m->hideexpr) { uidnew = camel_folder_search_by_expression(m->ml->folder, m->hideexpr, &mm->ex); /* well, lets not abort just because this faileld ... */ @@ -2562,7 +2253,7 @@ static void regen_list_regen(struct _mail_msg *mm) MESSAGE_LIST_LOCK(m->ml, hide_lock); - m->ml->hide_unhidden = m->uids->len; + m->ml->hide_unhidden = uids->len; /* what semantics do we want from hide_before, hide_after? probably <0 means measure from the end of the list */ @@ -2571,7 +2262,6 @@ static void regen_list_regen(struct _mail_msg *mm) if (m->ml->hidden || m->ml->hide_before != ML_HIDE_NONE_START || m->ml->hide_after != ML_HIDE_NONE_END) { int start, end; uidnew = g_ptr_array_new(); - uids = m->uids; /* first, hide matches */ if (m->ml->hidden) { @@ -2603,16 +2293,31 @@ static void regen_list_regen(struct _mail_msg *mm) g_ptr_array_free(uidnew, TRUE); uidnew = uid2; } - m->realuids = uids; - m->uids = uidnew; + showuids = uidnew; } else { - m->realuids = NULL; + uidnew = NULL; + showuids = uids; } MESSAGE_LIST_UNLOCK(m->ml, hide_lock); - if (m->dotree && m->uids) - m->tree = camel_folder_thread_messages_new(m->ml->folder, m->uids); + m->summary = g_ptr_array_new(); + for (i=0;ilen;i++) { + info = camel_folder_get_message_info(m->folder, showuids->pdata[i]); + if (info) + g_ptr_array_add(m->summary, info); + } + + if (uidnew) + g_ptr_array_free(uidnew, TRUE); + + if (m->search) + camel_folder_search_free(m->folder, uids); + else + camel_folder_free_uids(m->folder, uids); + + if (m->dotree) + m->tree = camel_folder_thread_messages_new_summary(m->summary); else m->tree = NULL; } @@ -2621,45 +2326,37 @@ static void regen_list_regened(struct _mail_msg *mm) { struct _regen_list_msg *m = (struct _regen_list_msg *)mm; - if (m->uids == NULL) + if (m->summary == NULL) return; if (m->dotree) build_tree(m->ml, m->tree, m->changes); else - build_flat(m->ml, m->uids, m->changes); + build_flat(m->ml, m->summary, m->changes); } static void regen_list_free(struct _mail_msg *mm) { struct _regen_list_msg *m = (struct _regen_list_msg *)mm; - GPtrArray *uids; - - /* work out if we have aux uid's to free, otherwise free the real ones */ - uids = m->realuids; - if (uids) { - if (m->uids) - g_ptr_array_free(m->uids, TRUE); - } else - uids = m->uids; - - if (uids) { - if (m->search) - camel_folder_search_free(m->ml->folder, uids); - else - camel_folder_free_uids(m->ml->folder, uids); + int i; + + if (m->summary) { + for (i=0;isummary->len;i++) + camel_folder_free_message_info(m->folder, m->summary->pdata[i]); + g_ptr_array_free(m->summary, TRUE); } - /* update what we have as our search string */ + if (m->tree) + camel_folder_thread_messages_destroy(m->tree); + if (m->ml->search && m->ml->search != m->search) g_free(m->ml->search); m->ml->search = m->search; - if (m->tree) - camel_folder_thread_messages_destroy(m->tree); - g_free(m->hideexpr); + camel_object_unref((CamelObject *)m->folder); + if (m->changes) camel_folder_change_info_free(m->changes); @@ -2700,6 +2397,8 @@ mail_regen_list(MessageList *ml, const char *search, const char *hideexpr, Camel m->changes = changes; m->dotree = ml->threaded; gtk_object_ref((GtkObject *)ml); + m->folder = ml->folder; + camel_object_ref((CamelObject *)m->folder); e_thread_put(mail_thread_new, (EMsg *)m); } diff --git a/mail/message-list.h b/mail/message-list.h index dbbb3421be..cd26c2cfef 100644 --- a/mail/message-list.h +++ b/mail/message-list.h @@ -55,9 +55,7 @@ struct _MessageList { /* The folder */ CamelFolder *folder; - /* UID to model row hash table. Keys owned by the mempool. */ - GHashTable *uid_rowmap; - struct _EMemPool *uid_pool; + GHashTable *uid_nodemap; /* uid (from info) -> tree node mapping */ /* UID's to hide. Keys in the mempool */ /* IMPORTANT: You MUST have obtained the hide lock, to operate on this data */ -- cgit v1.2.3