From 2505d230498c0f35822e7d10502bb3f899fdf876 Mon Sep 17 00:00:00 2001 From: Meilof Veeningen Date: Mon, 12 Jan 2004 22:22:50 +0000 Subject: support for posting both to mail and to (multiple) folders 2004-01-12 Meilof Veeningen * em-composer-utils.c: support for posting both to mail and to (multiple) folders * em-folder-browser.c: use em_utils_post_to_folder (works with NNTP) * em-folder-selection-button.[ch]: added multiple selection mode * em-folder-selector.[ch]: idem * em-folder-tree.[ch]: added multiple selection mode, no longer show disabled accounts * em-utils.c: various changes to allow posting to (multiple) folders * em-subscribe-editor.c: double-clicking a node in the editor updates it directly * mail-ops.c: for appending messages, set the "X-Mailer" header svn path=/trunk/; revision=24182 --- mail/ChangeLog | 21 +++++ mail/em-composer-utils.c | 120 +++++++++++++++++---------- mail/em-folder-browser.c | 6 +- mail/em-folder-selection-button.c | 117 +++++++++++++++++++++----- mail/em-folder-selection-button.h | 6 ++ mail/em-folder-selector.c | 16 ++++ mail/em-folder-selector.h | 4 + mail/em-folder-tree.c | 140 +++++++++++++++++++++++++++++-- mail/em-folder-tree.h | 6 ++ mail/em-subscribe-editor.c | 27 +++++- mail/em-utils.c | 169 +++++++++++++++++++++++++++++++------- mail/em-utils.h | 5 ++ mail/mail-ops.c | 4 + 13 files changed, 534 insertions(+), 107 deletions(-) (limited to 'mail') diff --git a/mail/ChangeLog b/mail/ChangeLog index 18628947d1..bb6b4e56d2 100644 --- a/mail/ChangeLog +++ b/mail/ChangeLog @@ -1,3 +1,24 @@ +2004-01-12 Meilof Veeningen + + * em-composer-utils.c: support for posting both to mail and to + (multiple) folders + + * em-folder-browser.c: use em_utils_post_to_folder (works with NNTP) + + * em-folder-selection-button.[ch]: added multiple selection mode + + * em-folder-selector.[ch]: idem + + * em-folder-tree.[ch]: added multiple selection mode, no longer show + disabled accounts + + * em-utils.c: various changes to allow posting to (multiple) folders + + * em-subscribe-editor.c: double-clicking a node in the editor updates + it directly + + * mail-ops.c: for appending messages, set the "X-Mailer" header + 2004-01-12 Radek Doulik * em-junk-filter.c (em_junk_sa_check_junk): use diff --git a/mail/em-composer-utils.c b/mail/em-composer-utils.c index bc076a7f77..09ca8a8b4f 100644 --- a/mail/em-composer-utils.c +++ b/mail/em-composer-utils.c @@ -231,7 +231,7 @@ composer_send_queued_cb (CamelFolder *folder, CamelMimeMessage *msg, CamelMessag } static CamelMimeMessage * -composer_get_message (EMsgComposer *composer, gboolean post, gboolean save_html_object_data) +composer_get_message (EMsgComposer *composer, gboolean post, gboolean save_html_object_data, gboolean *no_recipients) { CamelMimeMessage *message = NULL; EABDestination **recipients, **recipients_bcc; @@ -296,10 +296,15 @@ composer_get_message (EMsgComposer *composer, gboolean post, gboolean save_html_ camel_object_unref (cia); /* I'm sensing a lack of love, er, I mean recipients. */ - if (num == 0 && !post) { - e_notice ((GtkWindow *) composer, GTK_MESSAGE_WARNING, - _("You must specify recipients in order to send this message.")); - goto finished; + if (num == 0) { + if (post) { + if (no_recipients) + *no_recipients = TRUE; + } else { + e_notice ((GtkWindow *) composer, GTK_MESSAGE_WARNING, + _("You must specify recipients in order to send this message.")); + goto finished; + } } if (num > 0 && (num == num_bcc || shown == 0)) { @@ -389,55 +394,85 @@ em_utils_composer_send_cb (EMsgComposer *composer, gpointer user_data) CamelMimeMessage *message; CamelMessageInfo *info; struct _send_data *send; - gboolean post = FALSE; - CamelFolder *folder; + gboolean no_recipients = FALSE; + CamelFolder *mail_folder = NULL, *tmpfldr; + GList *post_folders = NULL, *post_ptr; XEvolution *xev; - char *url; - - url = e_msg_composer_hdrs_get_post_to ((EMsgComposerHdrs *) composer->hdrs); - if (url && *url) { - post = TRUE; - - mail_msg_wait (mail_get_folder (url, 0, got_post_folder, &folder, mail_thread_new)); - - if (!folder) { - g_free (url); - return; - } - } else { - folder = outbox_folder; - camel_object_ref (folder); + GList *postlist; + + postlist = e_msg_composer_hdrs_get_post_to ((EMsgComposerHdrs *) composer->hdrs); + while (postlist) { + mail_msg_wait (mail_get_folder (postlist->data, 0, got_post_folder, &tmpfldr, mail_thread_new)); + if (tmpfldr) + post_folders = g_list_append (post_folders, tmpfldr); + postlist = g_list_next (postlist); } - g_free (url); + mail_folder = outbox_folder; + camel_object_ref (mail_folder); + + if (!post_folders && !mail_folder) + return; - message = composer_get_message (composer, post, FALSE); - if (!message) + if (!(message = composer_get_message (composer, post_folders != NULL, FALSE, &no_recipients))) return; - if (post) { + if (no_recipients) { + /* we're doing a post with no recipients */ + camel_object_unref (mail_folder); + mail_folder = NULL; + } + + if (mail_folder) { + /* mail the message */ + info = camel_message_info_new (); + info->flags = CAMEL_MESSAGE_SEEN; + + send = g_malloc (sizeof (*send)); + send->emcs = user_data; + if (send->emcs) + emcs_ref (send->emcs); + send->send = TRUE; + send->composer = composer; + g_object_ref (composer); + gtk_widget_hide (GTK_WIDGET (composer)); + + e_msg_composer_set_enable_autosave (composer, FALSE); + + mail_append_mail (mail_folder, message, info, composer_send_queued_cb, send); + camel_object_unref (mail_folder); + } + + if (post_folders) { /* Remove the X-Evolution* headers if we are in Post-To mode */ xev = mail_tool_remove_xevolution_headers (message); mail_tool_destroy_xevolution (xev); + + /* mail the message */ + info = camel_message_info_new (); + info->flags = CAMEL_MESSAGE_SEEN; + + post_ptr = post_folders; + while (post_ptr) { + send = g_malloc (sizeof (*send)); + send->emcs = user_data; + if (send->emcs) + emcs_ref (send->emcs); + send->send = FALSE; + send->composer = composer; + g_object_ref (composer); + gtk_widget_hide (GTK_WIDGET (composer)); + + e_msg_composer_set_enable_autosave (composer, FALSE); + + mail_append_mail ((CamelFolder *) post_ptr->data, message, info, composer_send_queued_cb, send); + camel_object_unref ((CamelFolder *) post_ptr->data); + + post_ptr = g_list_next (post_ptr); + } } - info = camel_message_info_new (); - info->flags = CAMEL_MESSAGE_SEEN; - - send = g_malloc (sizeof (*send)); - send->emcs = user_data; - if (send->emcs) - emcs_ref (send->emcs); - send->send = !post; - send->composer = composer; - g_object_ref (composer); - gtk_widget_hide (GTK_WIDGET (composer)); - - e_msg_composer_set_enable_autosave (composer, FALSE); - - mail_append_mail (folder, message, info, composer_send_queued_cb, send); camel_object_unref (message); - camel_object_unref (folder); } struct _save_draft_info { @@ -456,6 +491,7 @@ save_draft_done (CamelFolder *folder, CamelMimeMessage *msg, CamelMessageInfo *i if (!ok) goto done; + CORBA_exception_init (&ev); GNOME_GtkHTML_Editor_Engine_runCommand (sdi->composer->editor_engine, "saved", &ev); CORBA_exception_free (&ev); diff --git a/mail/em-folder-browser.c b/mail/em-folder-browser.c index ea89bd15a7..27cca529ad 100644 --- a/mail/em-folder-browser.c +++ b/mail/em-folder-browser.c @@ -618,11 +618,7 @@ static void emfb_mail_post(BonoboUIComponent *uid, void *data, const char *path) { EMFolderView *emfv = data; - char *url; - - url = mail_tools_folder_to_url (emfv->folder); - em_utils_post_to_url (url); - g_free (url); + em_utils_post_to_folder (emfv->folder); } static void diff --git a/mail/em-folder-selection-button.c b/mail/em-folder-selection-button.c index ce5f38680c..c6dc309d6b 100644 --- a/mail/em-folder-selection-button.c +++ b/mail/em-folder-selection-button.c @@ -35,6 +35,7 @@ #include "mail-component.h" #include "em-folder-tree.h" #include "em-folder-selector.h" +#include "em-utils.h" #include "em-folder-selection-button.h" @@ -50,10 +51,13 @@ struct _EMFolderSelectionButtonPrivate { GtkWidget *icon; GtkWidget *label; - char *uri; + char *uri; /* for single-select mode */ + GList *uris; /* for multi-select mode */ char *title; char *caption; + + gboolean multiple_select; }; enum { @@ -120,25 +124,14 @@ static void set_contents (EMFolderSelectionButton *button) { struct _EMFolderSelectionButtonPrivate *priv = button->priv; - const char *folder_name; - CamelURL *url; - - if (priv->uri == NULL - || (url = camel_url_new (priv->uri, NULL)) == NULL) { - set_contents_unselected (button); - return; - } - - folder_name = url->fragment ? url->fragment : url->path + 1; + char *folder_name = em_utils_folder_name_from_uri (priv->uri); - if (folder_name == NULL) { - camel_url_free (url); + if (folder_name) { + gtk_label_set_text (GTK_LABEL (priv->label), folder_name); + g_free (folder_name); + } else { set_contents_unselected (button); - return; } - - gtk_label_set_text (GTK_LABEL (priv->label), folder_name); - camel_url_free (url); } static void @@ -150,6 +143,8 @@ em_folder_selection_button_init (EMFolderSelectionButton *emfsb) priv = g_new0 (struct _EMFolderSelectionButtonPrivate, 1); emfsb->priv = priv; + priv->multiple_select = FALSE; + box = gtk_hbox_new (FALSE, 4); priv->icon = gtk_image_new (); @@ -178,6 +173,10 @@ static void em_folder_selection_button_finalize (GObject *obj) { struct _EMFolderSelectionButtonPrivate *priv = ((EMFolderSelectionButton *) obj)->priv; + + GList *lst = ((EMFolderSelectionButton*) obj)->priv->uris; + g_list_foreach (lst, (GFunc) g_free, NULL); + g_list_free (lst); g_free (priv->title); g_free (priv->caption); @@ -191,10 +190,17 @@ static void emfsb_selector_response (EMFolderSelector *emfs, int response, EMFolderSelectionButton *button) { if (response == GTK_RESPONSE_OK) { - const char *uri = em_folder_selector_get_selected_uri (emfs); - - em_folder_selection_button_set_selection (button, uri); - g_signal_emit (button, signals[SELECTED], 0); + if (button->priv->multiple_select) { + GList *uris = em_folder_selector_get_selected_uris (emfs); + + em_folder_selection_button_set_selection_mult (button, uris); + g_signal_emit (button, signals[SELECTED], 0); + } else { + const char *uri = em_folder_selector_get_selected_uri (emfs); + + em_folder_selection_button_set_selection (button, uri); + g_signal_emit (button, signals[SELECTED], 0); + } } gtk_widget_destroy ((GtkWidget *) emfs); @@ -213,9 +219,13 @@ em_folder_selection_button_clicked (GtkButton *button) model = mail_component_peek_tree_model (mail_component_peek ()); emft = (EMFolderTree *) em_folder_tree_new_with_model (model); + em_folder_tree_set_multiselect (emft, priv->multiple_select); dialog = em_folder_selector_new (emft, EM_FOLDER_SELECTOR_CAN_CREATE, priv->title, priv->caption); - em_folder_selector_set_selected ((EMFolderSelector *) dialog, priv->uri); + if (priv->multiple_select) + em_folder_selector_set_selected_list ((EMFolderSelector *) dialog, priv->uris); + else + em_folder_selector_set_selected ((EMFolderSelector *) dialog, priv->uri); g_signal_connect (dialog, "response", G_CALLBACK (emfsb_selector_response), button); gtk_widget_show (dialog); } @@ -253,3 +263,66 @@ em_folder_selection_button_get_selection (EMFolderSelectionButton *button) return button->priv->uri; } + +void +em_folder_selection_button_set_selection_mult (EMFolderSelectionButton *button, GList *uris) +{ + struct _EMFolderSelectionButtonPrivate *priv = button->priv; + char *caption, *tmp, *tmp2; + + g_return_if_fail (EM_IS_FOLDER_SELECTION_BUTTON (button)); + + if (priv->uris) { + g_list_foreach (priv->uris, (GFunc) g_free, NULL); + g_list_free (priv->uris); + priv->uris = NULL; + } + + priv->uris = uris; + + /* compile the name */ + caption = g_strdup (""); + + while (uris) { + tmp = em_utils_folder_name_from_uri (uris->data); + if (tmp) { + tmp2 = g_strconcat (caption, ", ", tmp, NULL); + g_free (caption); + caption = tmp2; + g_free (tmp); + uris = uris->next; + } else { + /* apparently, we do not know this folder, so we'll just skip it */ + g_free (uris->data); + uris = g_list_next (uris); + priv->uris = g_list_remove (priv->uris, uris->data); + } + } + + if (caption[0]) + gtk_label_set_text (GTK_LABEL (priv->label), caption + 2); + else + set_contents_unselected (button); + + g_free (caption); +} + +GList * +em_folder_selection_button_get_selection_mult (EMFolderSelectionButton *button) +{ + g_return_val_if_fail (EM_IS_FOLDER_SELECTION_BUTTON (button), NULL); + + return button->priv->uris; +} + +void +em_folder_selection_button_set_multiselect (EMFolderSelectionButton *button, gboolean value) +{ + button->priv->multiple_select = value; +} + +gboolean +em_folder_selection_button_get_multiselect (EMFolderSelectionButton *button) +{ + return button->priv->multiple_select; +} diff --git a/mail/em-folder-selection-button.h b/mail/em-folder-selection-button.h index b8f64a4383..194a453efa 100644 --- a/mail/em-folder-selection-button.h +++ b/mail/em-folder-selection-button.h @@ -62,6 +62,12 @@ GtkWidget *em_folder_selection_button_new (const char *title, const char *captio void em_folder_selection_button_set_selection (EMFolderSelectionButton *button, const char *uri); const char *em_folder_selection_button_get_selection (EMFolderSelectionButton *button); +void em_folder_selection_button_set_selection_mult (EMFolderSelectionButton *button, GList *uris); +GList *em_folder_selection_button_get_selection_mult (EMFolderSelectionButton *button); + +void em_folder_selection_button_set_multiselect (EMFolderSelectionButton *button, gboolean value); +gboolean em_folder_selection_button_get_multiselect (EMFolderSelectionButton *button); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/mail/em-folder-selector.c b/mail/em-folder-selector.c index 5e2697ddf8..14169c94cc 100644 --- a/mail/em-folder-selector.c +++ b/mail/em-folder-selector.c @@ -280,6 +280,11 @@ em_folder_selector_set_selected (EMFolderSelector *emfs, const char *uri) em_folder_tree_set_selected (emfs->emft, uri); } +void +em_folder_selector_set_selected_list (EMFolderSelector *emfs, GList *list) +{ + em_folder_tree_set_selected_list (emfs->emft, list); +} const char * em_folder_selector_get_selected_uri (EMFolderSelector *emfs) @@ -329,6 +334,17 @@ em_folder_selector_get_selected_uri (EMFolderSelector *emfs) return uri; } +GList * +em_folder_selector_get_selected_uris (EMFolderSelector *emfs) +{ + return em_folder_tree_get_selected_uris (emfs->emft); +} + +GList * +em_folder_selector_get_selected_paths (EMFolderSelector *emfs) +{ + return em_folder_tree_get_selected_paths (emfs->emft); +} const char * em_folder_selector_get_selected_path (EMFolderSelector *emfs) diff --git a/mail/em-folder-selector.h b/mail/em-folder-selector.h index 9d6a53ed30..0dbad9c7df 100644 --- a/mail/em-folder-selector.h +++ b/mail/em-folder-selector.h @@ -75,10 +75,14 @@ GtkWidget *em_folder_selector_new (struct _EMFolderTree *emft, guint32 flags, co GtkWidget *em_folder_selector_create_new (struct _EMFolderTree *emft, guint32 flags, const char *title, const char *text); void em_folder_selector_set_selected (EMFolderSelector *emfs, const char *uri); +void em_folder_selector_set_selected_list (EMFolderSelector *emfs, GList *list); const char *em_folder_selector_get_selected_uri (EMFolderSelector *emfs); const char *em_folder_selector_get_selected_path (EMFolderSelector *emfs); +GList *em_folder_selector_get_selected_uris (EMFolderSelector *emfs); +GList *em_folder_selector_get_selected_paths (EMFolderSelector *emfs); + #ifdef cplusplus } #endif /* cplusplus */ diff --git a/mail/em-folder-tree.c b/mail/em-folder-tree.c index 45e8b3f48f..bc04551593 100644 --- a/mail/em-folder-tree.c +++ b/mail/em-folder-tree.c @@ -71,6 +71,10 @@ struct _EMFolderTreePrivate { char *selected_uri; char *selected_path; + + gboolean do_multiselect; + /* when doing a multiselect, folders that we didn't find */ + GList *lost_folders; guint save_state_id; @@ -130,6 +134,12 @@ static void emft_tree_row_expanded (GtkTreeView *treeview, GtkTreeIter *root, Gt static gboolean emft_tree_button_press (GtkWidget *treeview, GdkEventButton *event, EMFolderTree *emft); static void emft_tree_selection_changed (GtkTreeSelection *selection, EMFolderTree *emft); +struct _emft_selection_data { + GtkTreeModel *model; + GtkTreeIter *iter; + gboolean set; +}; + static GtkVBoxClass *parent_class = NULL; @@ -289,6 +299,7 @@ em_folder_tree_init (EMFolderTree *emft) struct _EMFolderTreePrivate *priv; priv = g_new0 (struct _EMFolderTreePrivate, 1); + priv->lost_folders = NULL; priv->selected_uri = NULL; priv->selected_path = NULL; priv->treeview = NULL; @@ -300,6 +311,13 @@ static void em_folder_tree_finalize (GObject *obj) { EMFolderTree *emft = (EMFolderTree *) obj; + + /* clear list of lost uris */ + if (emft->priv->lost_folders) { + g_list_foreach (emft->priv->lost_folders, (GFunc) g_free, NULL); + g_list_free (emft->priv->lost_folders); + emft->priv->lost_folders = NULL; + } g_free (emft->priv->selected_uri); g_free (emft->priv->selected_path); @@ -431,7 +449,7 @@ emft_expand_node (const char *key, gpointer value, EMFolderTree *emft) return; id = g_strndup (key, p - key); - if ((account = mail_config_get_account_by_uid (id))) { + if ((account = mail_config_get_account_by_uid (id)) && account->enabled) { CamelException ex; CamelStore *store; @@ -531,6 +549,83 @@ em_folder_tree_enable_drag_and_drop (EMFolderTree *emft) GDK_ACTION_COPY | GDK_ACTION_MOVE); } +void +em_folder_tree_set_multiselect (EMFolderTree *tree, gboolean mode) +{ + GtkTreeSelection *sel = gtk_tree_view_get_selection ((GtkTreeView *) tree->priv->treeview); + + tree->priv->do_multiselect = mode; + gtk_tree_selection_set_mode (sel, mode ? GTK_SELECTION_MULTIPLE : GTK_SELECTION_SINGLE); +} + +static void +get_selected_uris_iterate (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data) +{ + GList **list = (GList **) data; + char *uri; + + gtk_tree_model_get (model, iter, /*COL_STRING_FOLDER_PATH, &path,*/ + COL_STRING_URI, &uri, -1); + *list = g_list_append (*list, g_strdup (uri)); +} + +GList * +em_folder_tree_get_selected_uris (EMFolderTree *emft) +{ + GtkTreeSelection *selection = gtk_tree_view_get_selection (emft->priv->treeview); + GList *lost = emft->priv->lost_folders; + GList *list = NULL; + + /* at first, add lost uris */ + while (lost) { + list = g_list_append (list, g_strdup (lost->data)); + lost = g_list_next (lost); + } + + gtk_tree_selection_selected_foreach (selection, get_selected_uris_iterate, &list); + + return list; +} + +static void +get_selected_uris_path_iterate (GtkTreeModel *model, GtkTreePath *treepath, GtkTreeIter *iter, gpointer data) +{ + GList **list = (GList **) data; + char *path; + + gtk_tree_model_get (model, iter, COL_STRING_FOLDER_PATH, &path, -1); + *list = g_list_append (*list, g_strdup (path)); +} + +GList * +em_folder_tree_get_selected_paths (EMFolderTree *emft) +{ + GtkTreeSelection *selection = gtk_tree_view_get_selection (emft->priv->treeview); + GList *list = NULL; + + gtk_tree_selection_selected_foreach (selection, get_selected_uris_path_iterate, &list); + + return list; +} + +void +em_folder_tree_set_selected_list (EMFolderTree *emft, GList *list) +{ + struct _EMFolderTreePrivate *priv = emft->priv; + + /* clear list of lost uris */ + if (priv->lost_folders) { + g_list_foreach (priv->lost_folders, (GFunc)g_free, NULL); + g_list_free (priv->lost_folders); + priv->lost_folders = NULL; + } + + while (list) { + em_folder_tree_set_selected (emft, list->data); + list = g_list_next (list); + } +} + #if 0 static void @@ -616,8 +711,11 @@ emft_get_folder_info__got (struct _mail_msg *mm) gtk_tree_model_get ((GtkTreeModel *) model, &root, COL_BOOL_LOAD_SUBDIRS, &load, -1); - if (!load) + if (!load) { + if (priv->do_multiselect && m->select_uri) + priv->lost_folders = g_list_append (priv->lost_folders, g_strdup (m->select_uri)); return; + } /* get the first child (which will be a dummy node) */ gtk_tree_model_iter_children ((GtkTreeModel *) model, &iter, &root); @@ -1156,6 +1254,32 @@ emft_popup_delete_folders (CamelStore *store, const char *path, CamelException * camel_store_free_folder_info (store, fi); } +static void +selfunc (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data) +{ + struct _emft_selection_data *dat = (struct _emft_selection_data *) data; + + dat->model = model; + if (!dat->set) + *(dat->iter) = *iter; + dat->set = TRUE; +} + +static gboolean +emft_selection_get_selected (GtkTreeSelection *selection, GtkTreeModel **model, GtkTreeIter *iter) +{ + struct _emft_selection_data dat = { NULL, iter, FALSE }; + + if (gtk_tree_selection_get_mode (selection) == GTK_SELECTION_MULTIPLE) { + gtk_tree_selection_selected_foreach (selection, selfunc, &dat); + if (model) + *model = dat.model; + return dat.set; + } else { + return gtk_tree_selection_get_selected (selection, model, iter); + } +} + static void emft_popup_delete_response (GtkWidget *dialog, guint response, EMFolderTree *emft) { @@ -1172,7 +1296,7 @@ emft_popup_delete_response (GtkWidget *dialog, guint response, EMFolderTree *emf return; selection = gtk_tree_view_get_selection (priv->treeview); - gtk_tree_selection_get_selected (selection, &model, &iter); + emft_selection_get_selected (selection, &model, &iter); gtk_tree_model_get (model, &iter, COL_STRING_FOLDER_PATH, &path, COL_POINTER_CAMEL_STORE, &store, -1); @@ -1195,7 +1319,7 @@ emft_popup_delete_folder (GtkWidget *item, EMFolderTree *emft) char *title, *path; selection = gtk_tree_view_get_selection (priv->treeview); - gtk_tree_selection_get_selected (selection, &model, &iter); + emft_selection_get_selected (selection, &model, &iter); gtk_tree_model_get (model, &iter, COL_STRING_FOLDER_PATH, &path, -1); dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL, @@ -1232,7 +1356,7 @@ emft_popup_rename_folder (GtkWidget *item, EMFolderTree *emft) size_t base_len; selection = gtk_tree_view_get_selection (priv->treeview); - gtk_tree_selection_get_selected (selection, &model, &iter); + emft_selection_get_selected (selection, &model, &iter); gtk_tree_model_get (model, &iter, COL_STRING_FOLDER_PATH, &folder_path, COL_STRING_DISPLAY_NAME, &name, COL_POINTER_CAMEL_STORE, &store, @@ -1509,7 +1633,7 @@ emft_popup_properties (GtkWidget *item, EMFolderTree *emft) char *uri; selection = gtk_tree_view_get_selection (priv->treeview); - gtk_tree_selection_get_selected (selection, &model, &iter); + emft_selection_get_selected (selection, &model, &iter); gtk_tree_model_get (model, &iter, COL_STRING_URI, &uri, -1); mail_get_folder (uri, 0, emft_popup_properties_got_folder, emft, mail_thread_new); @@ -1578,7 +1702,7 @@ emft_tree_selection_changed (GtkTreeSelection *selection, EMFolderTree *emft) GtkTreeIter iter; char *path, *uri; - if (!gtk_tree_selection_get_selected (selection, &model, &iter)) + if (!emft_selection_get_selected (selection, &model, &iter)) return; gtk_tree_model_get (model, &iter, COL_STRING_FOLDER_PATH, &path, @@ -1670,7 +1794,7 @@ em_folder_tree_set_selected (EMFolderTree *emft, const char *uri) row = si->row; top = NULL; } - + /* FIXME: this gets all the subfolders of our first loaded * parent folder - ideally we'd only get what we needed, but * it's probably not worth the effort */ diff --git a/mail/em-folder-tree.h b/mail/em-folder-tree.h index ec4e9301d9..2742b9fe15 100644 --- a/mail/em-folder-tree.h +++ b/mail/em-folder-tree.h @@ -65,6 +65,12 @@ GtkWidget *em_folder_tree_new_with_model (EMFolderTreeModel *model); void em_folder_tree_enable_drag_and_drop (EMFolderTree *emft); +void em_folder_tree_set_multiselect (EMFolderTree *emft, gboolean mode); + +void em_folder_tree_set_selected_list (EMFolderTree *emft, GList *list); +GList *em_folder_tree_get_selected_uris (EMFolderTree *emft); +GList *em_folder_tree_get_selected_paths (EMFolderTree *emft); + void em_folder_tree_set_selected (EMFolderTree *emft, const char *uri); const char *em_folder_tree_get_selected_uri (EMFolderTree *emft); const char *em_folder_tree_get_selected_path (EMFolderTree *emft); diff --git a/mail/em-subscribe-editor.c b/mail/em-subscribe-editor.c index 1fb9066362..a23af0a333 100644 --- a/mail/em-subscribe-editor.c +++ b/mail/em-subscribe-editor.c @@ -127,7 +127,6 @@ struct _EMSubscribeNode { static void sub_editor_busy(EMSubscribeEditor *se, int dir); static int sub_queue_fill_level(EMSubscribe *sub, EMSubscribeNode *node); -static void sub_selection_changed(GtkTreeSelection *selection, EMSubscribe *sub); static void sub_node_free(char *key, EMSubscribeNode *node, EMSubscribe *sub) @@ -195,7 +194,7 @@ sub_folder_subscribe (struct _mail_msg *mm) camel_store_unsubscribe_folder (m->sub->store, m->node->info->full_name, &mm->ex); } -static void +static void sub_folder_subscribed (struct _mail_msg *mm) { struct _zsubscribe_msg *m = (struct _zsubscribe_msg *)mm, *next; @@ -503,6 +502,29 @@ sub_selection_changed(GtkTreeSelection *selection, EMSubscribe *sub) gtk_widget_set_sensitive(sub->editor->unsubscribe_button, dounsub); } +/* double-clicking causes a node item to be evaluated directly */ +static void sub_row_activated(GtkTreeView *tree, GtkTreePath *path, GtkTreeViewColumn *col, EMSubscribe *sub) { + EMSubscribeNode *node; + GtkTreeIter iter; + GtkTreeModel *model = gtk_tree_view_get_model(tree); + + if (gtk_tree_model_get_iter(model, &iter, path) != TRUE) return; + + gtk_tree_model_get(model, &iter, 2, &node, -1); + + /* check whether the item is already processed */ + if (node->path == NULL) + return; + + /* remove it from wherever in the list it is, and place it in front instead */ + e_dlist_remove((EDListNode *)node); + e_dlist_addhead(&sub->pending, (EDListNode *)node); + + if (sub->pending_id == -1 + && (node = (EMSubscribeNode *)e_dlist_remtail(&sub->pending))) + sub_queue_fill_level(sub, node); +} + static void sub_row_expanded(GtkTreeView *tree, GtkTreeIter *iter, GtkTreePath *path, EMSubscribe *sub) { @@ -621,6 +643,7 @@ subscribe_set_store(EMSubscribe *sub, CamelStore *store) gtk_tree_view_set_headers_visible (sub->tree, FALSE); g_signal_connect(sub->tree, "row-expanded", G_CALLBACK(sub_row_expanded), sub); + g_signal_connect(sub->tree, "row-activated", G_CALLBACK(sub_row_activated), sub); g_signal_connect(sub->tree, "destroy", G_CALLBACK(sub_destroy), sub); sub_selection_changed(selection, sub); diff --git a/mail/em-utils.c b/mail/em-utils.c index c942af0036..7a4c94b3b4 100644 --- a/mail/em-utils.c +++ b/mail/em-utils.c @@ -52,7 +52,7 @@ #include "em-composer-utils.h" #include "em-format-quote.h" -static EAccount *guess_account (CamelMimeMessage *message); +static EAccount *guess_account (CamelMimeMessage *message, CamelFolder *folder); static void emu_save_part_done (CamelMimePart *part, char *name, int done, void *data); /** @@ -342,6 +342,44 @@ em_utils_compose_new_message_with_mailto (const char *url) gtk_widget_show ((GtkWidget *) composer); } +/** + * em_utils_post_to_folder: + * @folder: folder + * + * Opens a new composer window as a child window of @parent's toplevel + * window. If @folder is non-NULL, the composer will default to posting + * mail to the folder specified by @folder. + **/ +void +em_utils_post_to_folder (CamelFolder *folder) +{ + EMsgComposer *composer; + EAccount *account; + + composer = e_msg_composer_new_with_type (E_MSG_COMPOSER_POST); + + if (folder != NULL) { + char *url = mail_tools_folder_to_url (folder); + + e_msg_composer_hdrs_set_post_to ((EMsgComposerHdrs *) ((EMsgComposer *) composer)->hdrs, url); + g_free (url); + + url = camel_url_to_string (CAMEL_SERVICE (folder->parent_store)->url, CAMEL_URL_HIDE_ALL); + account = mail_config_get_account_by_source_url (url); + g_free (url); + + if (account) + e_msg_composer_set_headers (composer, account->name, NULL, NULL, NULL, ""); + } + + em_composer_utils_setup_default_callbacks (composer); + + e_msg_composer_unset_changed (composer); + e_msg_composer_drop_editor_undo (composer); + + gtk_widget_show ((GtkWidget *) composer); +} + /** * em_utils_post_to_url: * @url: mailto url @@ -355,7 +393,7 @@ em_utils_post_to_url (const char *url) { EMsgComposer *composer; - composer = e_msg_composer_new_post (); + composer = e_msg_composer_new_with_type (E_MSG_COMPOSER_POST); if (url != NULL) e_msg_composer_hdrs_set_post_to ((EMsgComposerHdrs *) ((EMsgComposer *) composer)->hdrs, url); @@ -647,7 +685,7 @@ redirect_get_composer (CamelMimeMessage *message) while (camel_medium_get_header (CAMEL_MEDIUM (message), "Delivered-To")) camel_medium_remove_header (CAMEL_MEDIUM (message), "Delivered-To"); - account = guess_account (message); + account = guess_account (message, NULL); composer = e_msg_composer_new_redirect (message, account ? account->name : NULL); @@ -795,7 +833,8 @@ em_utils_camel_address_to_destination (CamelInternetAddress *iaddr) static EMsgComposer * reply_get_composer (CamelMimeMessage *message, EAccount *account, - CamelInternetAddress *to, CamelInternetAddress *cc) + CamelInternetAddress *to, CamelInternetAddress *cc, + CamelFolder *folder, const char *postto) { const char *message_id, *references; EABDestination **tov, **ccv; @@ -805,13 +844,19 @@ reply_get_composer (CamelMimeMessage *message, EAccount *account, g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), NULL); g_return_val_if_fail (to == NULL || CAMEL_IS_INTERNET_ADDRESS (to), NULL); g_return_val_if_fail (cc == NULL || CAMEL_IS_INTERNET_ADDRESS (cc), NULL); - - composer = e_msg_composer_new (); - + /* construct the tov/ccv */ tov = em_utils_camel_address_to_destination (to); ccv = em_utils_camel_address_to_destination (cc); - + + if (tov || ccv) { + if (postto) + composer = e_msg_composer_new_with_type (E_MSG_COMPOSER_MAIL_POST); + else + composer = e_msg_composer_new_with_type (E_MSG_COMPOSER_MAIL); + } else + composer = e_msg_composer_new_with_type (E_MSG_COMPOSER_POST); + /* Set the subject of the new message. */ if ((subject = (char *) camel_mime_message_get_subject (message))) { if (strncasecmp (subject, "Re: ", 4) != 0) @@ -821,11 +866,25 @@ reply_get_composer (CamelMimeMessage *message, EAccount *account, } else { subject = g_strdup (""); } - + e_msg_composer_set_headers (composer, account ? account->name : NULL, tov, ccv, NULL, subject); g_free (subject); + /* add post-to, if nessecary */ + if (postto) { + char *store_url = NULL; + + if (folder) { + store_url = camel_url_to_string (CAMEL_SERVICE (folder->parent_store)->url, CAMEL_URL_HIDE_ALL); + if (store_url[strlen (store_url) - 1] == '/') + store_url[strlen (store_url)-1] = '\0'; + } + + e_msg_composer_hdrs_set_post_to_base (E_MSG_COMPOSER_HDRS (composer->hdrs), store_url ? store_url : "", postto); + g_free (store_url); + } + /* Add In-Reply-To and References. */ message_id = camel_medium_get_header (CAMEL_MEDIUM (message), "Message-Id"); references = camel_medium_get_header (CAMEL_MEDIUM (message), "References"); @@ -851,13 +910,26 @@ reply_get_composer (CamelMimeMessage *message, EAccount *account, } static EAccount * -guess_account (CamelMimeMessage *message) +guess_account (CamelMimeMessage *message, CamelFolder *folder) { const CamelInternetAddress *to, *cc; - GHashTable *account_hash; + GHashTable *account_hash = NULL; EAccount *account = NULL; const char *addr; int i; + const char *posthdr, *tmp; + + /* check for newsgroup header */ + posthdr = camel_medium_get_header (CAMEL_MEDIUM (message), "Newsgroups"); + + if (posthdr && folder) { + /* this was posted at a newsgroup! */ + tmp = camel_url_to_string (CAMEL_SERVICE (folder->parent_store)->url, CAMEL_URL_HIDE_ALL); + account = mail_config_get_account_by_source_url (tmp); + g_free (tmp); + if (account) + goto found; + } to = camel_mime_message_get_recipients (message, CAMEL_RECIPIENT_TYPE_TO); cc = camel_mime_message_get_recipients (message, CAMEL_RECIPIENT_TYPE_CC); @@ -885,18 +957,28 @@ guess_account (CamelMimeMessage *message) found: - g_hash_table_destroy (account_hash); + if (account_hash) + g_hash_table_destroy (account_hash); return account; } static void -get_reply_sender (CamelMimeMessage *message, CamelInternetAddress **to) +get_reply_sender (CamelMimeMessage *message, CamelInternetAddress **to, const char **postto) { const CamelInternetAddress *reply_to; - const char *name, *addr; + const char *name, *addr, *posthdr; int i; + /* check whether there is a 'Newsgroups: ' header in there */ + posthdr = camel_medium_get_header (CAMEL_MEDIUM (message), "Newsgroups"); + if (posthdr && postto) { + *postto = posthdr; + while (**postto == ' ') + (*postto)++; + return; + } + reply_to = camel_mime_message_get_reply_to (message); if (!reply_to) reply_to = camel_mime_message_get_from (message); @@ -967,13 +1049,21 @@ concat_unique_addrs (CamelInternetAddress *dest, const CamelInternetAddress *src } static void -get_reply_all (CamelMimeMessage *message, CamelInternetAddress **to, CamelInternetAddress **cc) +get_reply_all (CamelMimeMessage *message, CamelInternetAddress **to, CamelInternetAddress **cc, const char **postto) { const CamelInternetAddress *reply_to, *to_addrs, *cc_addrs; - const char *name, *addr; + const char *name, *addr, *posthdr; GHashTable *rcpt_hash; int i; + /* check whether there is a 'Newsgroups: ' header in there */ + posthdr = camel_medium_get_header (CAMEL_MEDIUM(message), "Newsgroups"); + if (posthdr && postto) { + *postto = posthdr; + while (**postto == ' ') + (*postto)++; + } + rcpt_hash = generate_account_hash (); reply_to = camel_mime_message_get_reply_to (message); @@ -1079,21 +1169,21 @@ em_utils_reply_to_message (CamelMimeMessage *message, int mode) EMsgComposer *composer; EAccount *account; - account = guess_account (message); + account = guess_account (message, NULL); switch (mode) { case REPLY_MODE_SENDER: - get_reply_sender (message, &to); + get_reply_sender (message, &to, NULL); break; case REPLY_MODE_LIST: if (get_reply_list (message, &to)) break; case REPLY_MODE_ALL: - get_reply_all (message, &to, &cc); + get_reply_all (message, &to, &cc, NULL); break; } - composer = reply_get_composer (message, account, to, cc); + composer = reply_get_composer (message, account, to, cc, NULL, NULL); e_msg_composer_add_message_attachments (composer, message, TRUE); if (to != NULL) @@ -1114,19 +1204,20 @@ static void reply_to_message (CamelFolder *folder, const char *uid, CamelMimeMessage *message, void *user_data) { CamelInternetAddress *to = NULL, *cc = NULL; + const char *postto = NULL; EMsgComposer *composer; EAccount *account; guint32 flags; int mode; mode = GPOINTER_TO_INT (user_data); - - account = guess_account (message); + + account = guess_account (message, folder); flags = CAMEL_MESSAGE_ANSWERED | CAMEL_MESSAGE_SEEN; switch (mode) { case REPLY_MODE_SENDER: - get_reply_sender (message, &to); + get_reply_sender (message, &to, &postto); break; case REPLY_MODE_LIST: flags |= CAMEL_MESSAGE_ANSWERED_ALL; @@ -1134,11 +1225,11 @@ reply_to_message (CamelFolder *folder, const char *uid, CamelMimeMessage *messag break; case REPLY_MODE_ALL: flags |= CAMEL_MESSAGE_ANSWERED_ALL; - get_reply_all (message, &to, &cc); + get_reply_all (message, &to, &cc, &postto); break; } - composer = reply_get_composer (message, account, to, cc); + composer = reply_get_composer (message, account, to, cc, folder, postto); e_msg_composer_add_message_attachments (composer, message, TRUE); if (to != NULL) @@ -1187,12 +1278,12 @@ post_reply_to_message (CamelFolder *folder, const char *uid, CamelMimeMessage *m EAccount *account; guint32 flags; - account = guess_account (message); + account = guess_account (message, folder); flags = CAMEL_MESSAGE_ANSWERED | CAMEL_MESSAGE_SEEN; - get_reply_sender (message, &to); + get_reply_sender (message, &to, NULL); - composer = e_msg_composer_new_post (); + composer = e_msg_composer_new_with_type (E_MSG_COMPOSER_MAIL_POST); /* construct the tov/ccv */ tov = em_utils_camel_address_to_destination (to); @@ -2374,3 +2465,25 @@ em_utils_empty_trash (GtkWidget *parent) /* Now empty the local trash folder */ mail_empty_trash (NULL, NULL, NULL); } + +char * +em_utils_folder_name_from_uri (const char *uri) +{ + CamelURL *url; + char *folder_name; + + if (uri == NULL || (url = camel_url_new (uri, NULL)) == NULL) + return NULL; + + folder_name = url->fragment ? url->fragment : url->path + 1; + + if (folder_name == NULL) { + camel_url_free (url); + return NULL; + } + + folder_name = g_strdup (folder_name); + camel_url_free (url); + + return folder_name; +} diff --git a/mail/em-utils.h b/mail/em-utils.h index f0d8e4249a..6b54e48de2 100644 --- a/mail/em-utils.h +++ b/mail/em-utils.h @@ -59,6 +59,7 @@ void em_utils_compose_new_message (void); /* FIXME: mailto? url? should make up its mind what its called. imho use 'uri' */ void em_utils_compose_new_message_with_mailto (const char *url); +void em_utils_post_to_folder (struct _CamelFolder *folder); void em_utils_post_to_url (const char *url); void em_utils_edit_message (struct _CamelMimeMessage *message); @@ -121,6 +122,10 @@ char *em_utils_message_to_html(struct _CamelMimeMessage *msg, const char *credit void em_utils_expunge_folder (struct _GtkWidget *parent, struct _CamelFolder *folder); void em_utils_empty_trash (struct _GtkWidget *parent); +/* returns the folder name portion of an URI */ +char *em_utils_folder_name_from_uri (const char *uri); + + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/mail/mail-ops.c b/mail/mail-ops.c index 32eb68b4f1..380ba24d30 100644 --- a/mail/mail-ops.c +++ b/mail/mail-ops.c @@ -887,6 +887,10 @@ mail_append_mail (CamelFolder *folder, CamelMimeMessage *message, CamelMessageIn g_assert(CAMEL_IS_FOLDER (folder)); g_assert(CAMEL_IS_MIME_MESSAGE (message)); + if (!camel_medium_get_header (CAMEL_MEDIUM (message), "X-Mailer")) + camel_medium_set_header (CAMEL_MEDIUM (message), "X-Mailer", + "Ximian Evolution " VERSION SUB_VERSION " " VERSION_COMMENT); + m = mail_msg_new (&append_mail_op, NULL, sizeof (*m)); m->folder = folder; camel_object_ref(folder); -- cgit v1.2.3