diff options
-rw-r--r-- | mail/ChangeLog | 17 | ||||
-rw-r--r-- | mail/em-format-html-display.c | 326 | ||||
-rw-r--r-- | mail/em-format-html.c | 6 | ||||
-rw-r--r-- | mail/em-popup.c | 154 | ||||
-rw-r--r-- | mail/em-popup.h | 3 | ||||
-rw-r--r-- | mail/em-utils.c | 71 | ||||
-rw-r--r-- | mail/em-utils.h | 1 |
7 files changed, 542 insertions, 36 deletions
diff --git a/mail/ChangeLog b/mail/ChangeLog index 50c3e2dfb9..24ae4b7313 100644 --- a/mail/ChangeLog +++ b/mail/ChangeLog @@ -1,3 +1,20 @@ +2005-07-25 Srinivasa Ragavan <sragavan@novell.com> + + * em-format-html-display.c: (efhd_init) (efhd_finalise) () + (efhd_attachment_image) (efhd_attachment_button) (efhd_format_attachment) + Added code to create a attachment bar. + + * em-format-html.c: (efh_format_message) Added code to add bar + at the beginning of the message. + + * em-popup.[ch]: (em_popup_target_new_attachments) (emp_part_popup_set_background) + (emp_standard_menu_factory) Added code to handle the popup menu inside the attachment + bar. + + * em-utils.[ch]: (em_utils_edit_filters) (emu_get_save_filesel) + (em_utils_save_part) (em_utils_save_messages) Added code to handle save selected and + save all options of the attachment bar. + 2005-07-21 Not Zed <NotZed@Ximian.com> * em-folder-browser.c: reverted dobey's busted view->hide* menu diff --git a/mail/em-format-html-display.c b/mail/em-format-html-display.c index 25dc7622a6..a1da4532a8 100644 --- a/mail/em-format-html-display.c +++ b/mail/em-format-html-display.c @@ -45,6 +45,7 @@ #include <gtk/gtkmenuitem.h> #include <gtk/gtkmain.h> #include <gtk/gtkdnd.h> +#include <gtk/gtktoolbutton.h> #include <glade/glade.h> @@ -87,6 +88,8 @@ #include "em-icon-stream.h" #include "em-utils.h" #include "em-popup.h" +#include "e-attachment.h" +#include "e-attachment-bar.h" #define d(x) @@ -101,6 +104,18 @@ struct _EMFormatHTMLDisplayPrivate { GtkWidget *search_case_check; char *search_text; int search_wrap; /* are we doing a wrap search */ + + /* for Attachment bar */ + GtkWidget *attachment_bar; + GtkWidget *attachment_box; + GtkWidget *label; + GtkWidget *arrow; + GtkWidget *forward; + GtkWidget *down; + GtkWidget *save; + gboolean show_bar; + gboolean bar_added; + GHashTable *files; }; static int efhd_html_button_press_event (GtkWidget *widget, GdkEventButton *event, EMFormatHTMLDisplay *efh); @@ -109,6 +124,8 @@ static void efhd_html_on_url (GtkHTML *html, const char *url, EMFormatHTMLDispla static void efhd_attachment_frame(EMFormat *emf, CamelStream *stream, EMFormatPURI *puri); static gboolean efhd_attachment_image(EMFormatHTML *efh, GtkHTMLEmbedded *eb, EMFormatHTMLPObject *pobject); +static void efhd_message_add_bar(EMFormat *emf, CamelStream *stream, CamelMimePart *part, const EMFormatHandler *info); +static void efhd_attachment_bar_refresh (EMFormatHTMLDisplay *efhd); struct _attach_puri { EMFormatPURI puri; @@ -128,6 +145,10 @@ struct _attach_puri { int fit_width; int fit_height; GtkImage *image; + + /* Signed / Encrypted */ + camel_cipher_validity_sign_t sign; + camel_cipher_validity_encrypt_t encrypt; }; @@ -254,6 +275,10 @@ efhd_init(GObject *o) /* we want to convert url's etc */ efh->text_html_flags |= CAMEL_MIME_FILTER_TOHTML_CONVERT_URLS | CAMEL_MIME_FILTER_TOHTML_CONVERT_ADDRESSES; #undef efh + + efhd->priv->show_bar = FALSE; + efhd->priv->bar_added = FALSE; + efhd->priv->files = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); } static void @@ -263,6 +288,9 @@ efhd_finalise(GObject *o) /* check pending stuff */ + if (efhd->priv->files) + g_hash_table_destroy(efhd->priv->files); + g_free(efhd->priv->search_text); g_free(efhd->priv); @@ -959,6 +987,7 @@ static EMFormatHandler type_builtin_table[] = { { "image/pjpeg", (EMFormatFunc)efhd_image }, { "x-evolution/message/prefix", (EMFormatFunc)efhd_message_prefix }, + { "x-evolution/message/post-header", (EMFormatFunc)efhd_message_add_bar }, }; static void @@ -1007,6 +1036,21 @@ static const EMFormatHandler *efhd_find_handler(EMFormat *emf, const char *mime_ static void efhd_format_clone(EMFormat *emf, CamelFolder *folder, const char *uid, CamelMimeMessage *msg, EMFormat *src) { + EMFormatHTMLDisplay *efhd = (EMFormatHTMLDisplay *) emf; + + if (emf != src) { + if (src) + efhd->priv->show_bar = ((EMFormatHTMLDisplay *)src)->priv->show_bar; + else + efhd->priv->show_bar = FALSE; + } + + efhd->priv->attachment_bar = NULL; + efhd->priv->bar_added = FALSE; + if (efhd->priv->files) + g_hash_table_destroy(efhd->priv->files); + efhd->priv->files = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + ((EMFormatClass *)efhd_parent)->format_clone(emf, folder, uid, msg, src); } @@ -1370,9 +1414,12 @@ efhd_attachment_image(EMFormatHTML *efh, GtkHTMLEmbedded *eb, EMFormatHTMLPObjec static gboolean efhd_attachment_button(EMFormatHTML *efh, GtkHTMLEmbedded *eb, EMFormatHTMLPObject *pobject) { + EMFormatHTMLDisplay *efhd = (EMFormatHTMLDisplay *)efh; + EAttachment *new; struct _attach_puri *info; GtkWidget *hbox, *w, *button, *mainbox; - char *simple_type; + char *simple_type, *tmp, *new_file = NULL; + const char *file; GtkTargetEntry drag_types[] = { { NULL, 0, 0 }, { "text/uri-list", 0, 1 }, @@ -1386,6 +1433,47 @@ efhd_attachment_button(EMFormatHTML *efh, GtkHTMLEmbedded *eb, EMFormatHTMLPObje g_assert(info != NULL); g_assert(info->forward == NULL); + file = camel_mime_part_get_filename(info->puri.part); + + new = e_attachment_new_from_mime_part (info->puri.part); + + if (!file) { + file = "attachment.dat"; + camel_mime_part_set_filename(new->body, file); + } + + tmp = g_hash_table_lookup (efhd->priv->files, file); + if (tmp) { + guint count = GPOINTER_TO_UINT(tmp); + char *ext; + char *tmp_file = g_strdup (file); + + if ((ext = strrchr(tmp_file, '.'))) { + ext[0] = 0; + new_file = g_strdup_printf("%s(%d).%s", tmp_file, count++, ext+1); + } else { + new_file = g_strdup_printf("%s(%d)", tmp_file, count++); + } + + g_free (tmp_file); + g_hash_table_insert (efhd->priv->files, g_strdup(file), GUINT_TO_POINTER(count)); + camel_mime_part_set_filename(new->body, new_file); + + g_free(new_file); + } else { + g_hash_table_insert (efhd->priv->files, g_strdup(file), GUINT_TO_POINTER(1)); + } + + /* Store the status of encryption / signature on the attachment for emblem display + * FIXME: May not work well always + */ + new->sign = info->sign; + new->encrypt = info->encrypt; + + /* Add the attachment to the bar.*/ + e_attachment_bar_add_attachment (E_ATTACHMENT_BAR(efhd->priv->attachment_bar), new); + efhd_attachment_bar_refresh (efhd); + mainbox = gtk_hbox_new(FALSE, 0); button = gtk_button_new(); @@ -1644,6 +1732,237 @@ type_ok: } static void +attachment_bar_arrow_clicked(GtkWidget *w, EMFormatHTMLDisplay *efhd) +{ + + efhd->priv->show_bar = !efhd->priv->show_bar; + + if (efhd->priv->show_bar) { + gtk_widget_show(efhd->priv->attachment_box); + gtk_widget_show(efhd->priv->down); + gtk_widget_hide(efhd->priv->forward); + } else { + gtk_widget_hide(efhd->priv->attachment_box); + gtk_widget_show(efhd->priv->forward); + gtk_widget_hide(efhd->priv->down); + } +} + +static void +attachments_save_all_clicked(GtkWidget *w, EMFormatHTMLDisplay *efhd) +{ + GSList *attachment_parts; + + attachment_parts = e_attachment_bar_get_parts(E_ATTACHMENT_BAR(efhd->priv->attachment_bar)); + em_utils_save_parts(w, _("Select folder to save all attachments..."), attachment_parts); +} + +static void +efhd_bar_popup_position(GtkMenu *menu, int *x, int *y, gboolean *push_in, gpointer user_data) +{ + EAttachmentBar *bar = user_data; + GnomeIconList *icon_list = user_data; + GList *selection; + GnomeCanvasPixbuf *image; + + gdk_window_get_origin (((GtkWidget*) bar)->window, x, y); + + selection = gnome_icon_list_get_selection (icon_list); + if (selection == NULL) + return; + + image = gnome_icon_list_get_icon_pixbuf_item (icon_list, (gint)selection->data); + if (image == NULL) + return; + + /* Put menu to the center of icon. */ + *x += (int)(image->item.x1 + image->item.x2) / 2; + *y += (int)(image->item.y1 + image->item.y2) / 2; +} + +static void +efhd_bar_save_selected(EPopup *ep, EPopupItem *item, EMFormatHTMLDisplay *efhd) +{ + GSList *attachment_parts, *tmp; + GSList *parts = NULL; + + attachment_parts = e_attachment_bar_get_selected(E_ATTACHMENT_BAR(efhd->priv->attachment_bar)); + + for (tmp = attachment_parts; tmp; tmp=tmp->next) + parts = g_slist_prepend(parts, ((EAttachment *)tmp->data)->body); + + parts = g_slist_reverse(parts); + em_utils_save_parts(efhd->priv->attachment_bar, _("Select folder to save selected attachments..."), parts); + + g_slist_foreach(attachment_parts, (GFunc)g_object_unref, NULL); + g_slist_free (attachment_parts); +} + +static EPopupItem efhd_bar_menu_items[] = { + { E_POPUP_BAR, "05.display", }, + { E_POPUP_ITEM, "05.display.01", N_("Save Selected..."), efhd_bar_save_selected, NULL, NULL, EM_POPUP_ATTACHMENTS_MULTIPLE}, +}; + +static gboolean +efhd_bar_button_press_event(EAttachmentBar *bar, GdkEventButton *event, EMFormat *emf) +{ + GtkMenu *menu; + GSList *list=NULL; + EPopupTarget *target; + EMPopup *emp; + GSList *menus = NULL; + int i; + + if (event && event->button != 3) + return FALSE; + + /** @HookPoint-EMPopup: Attachment Bar Context Menu + * @Id: org.gnome.evolution.mail.attachments.popup + * @Class: org.gnome.evolution.mail.popup:1.0 + * @Target: EMPopupTargetPart + * + * This is the drop-down menu shown when a user clicks on the attachment bar + * when attachments are selected. + */ + emp = em_popup_new("org.gnome.evolution.mail.attachments.popup"); + + /* Add something like save-selected, foward selected attachments in a mail etc....*/ + list = e_attachment_bar_get_selected(bar); + + /* Lets not propagate any more the r-click which is intended to us*/ + if ( g_slist_length (list) == 0) + return TRUE; + + target = (EPopupTarget *)em_popup_target_new_attachments(emp, list); + for (i=0; i<2; i++) + menus = g_slist_prepend(menus, &efhd_bar_menu_items[i]); + e_popup_add_items((EPopup *)emp, menus, NULL, efhd_menu_items_free, emf); + + ((EMPopupTargetPart *)target)->target.widget = (GtkWidget *)bar; + menu = e_popup_create_menu_once((EPopup *)emp, (EPopupTarget *)target, 0); + if (event) + gtk_menu_popup(menu, NULL, NULL, NULL, NULL, event->button, event->time); + else + gtk_menu_popup(menu, NULL, NULL, (GtkMenuPositionFunc)efhd_bar_popup_position, bar, 0, gtk_get_current_event_time()); + + return TRUE; +} + +static gboolean +efhd_bar_popup_menu_event (EAttachmentBar *bar, EMFormat *emf) +{ + return efhd_bar_button_press_event(bar, NULL, emf); +} + +static void +efhd_attachment_bar_refresh (EMFormatHTMLDisplay *efhd) +{ + int nattachments; + + if (!efhd->priv->attachment_bar) + return; + + nattachments = e_attachment_bar_get_num_attachments (E_ATTACHMENT_BAR(efhd->priv->attachment_bar)); + if (nattachments) { + char *txt; + + /* Cant i put in the number of attachments here ?*/ + txt = g_strdup_printf(ngettext("%d Attachment", "%d Attachments", nattachments), nattachments); + gtk_label_set_text ((GtkLabel *)efhd->priv->label, txt); + g_free (txt); + + /* Enable the expander button and the save all button.*/ + gtk_widget_set_sensitive (efhd->priv->arrow, TRUE); + gtk_widget_set_sensitive (efhd->priv->save, TRUE); + } +} + +static gboolean +efhd_add_bar(EMFormatHTML *efh, GtkHTMLEmbedded *eb, EMFormatHTMLPObject *pobject) +{ + EMFormatHTMLDisplay *efhd = (EMFormatHTMLDisplay *)efh; + struct _EMFormatHTMLDisplayPrivate *priv = efhd->priv; + GtkWidget *hbox1, *hbox2, *hbox3, *vbox, *txt, *image; + int width, height; + + priv->attachment_bar = e_attachment_bar_new(NULL); + ((EAttachmentBar *)priv->attachment_bar)->expand = TRUE; + + priv->forward = gtk_arrow_new(GTK_ARROW_RIGHT, GTK_SHADOW_NONE); + priv->down = gtk_arrow_new(GTK_ARROW_DOWN, GTK_SHADOW_NONE); + hbox3 = gtk_hbox_new (FALSE, 0); + gtk_box_pack_start ((GtkBox *)hbox3, priv->forward, FALSE, FALSE, 0); + gtk_box_pack_start ((GtkBox *)hbox3, priv->down, FALSE, FALSE, 0); + priv->arrow = (GtkWidget *)gtk_tool_button_new(hbox3, NULL); + + priv->label = gtk_label_new(_("No Attachment")); + priv->save = gtk_button_new(); + image = gtk_image_new_from_stock ("gtk-save", GTK_ICON_SIZE_BUTTON); + txt = gtk_label_new(_("Save All")); + hbox1 = gtk_hbox_new(FALSE, 0); + gtk_box_pack_start((GtkBox *)hbox1, image, FALSE, FALSE, 2); + gtk_box_pack_start((GtkBox *)hbox1, txt, FALSE, FALSE, 0); + + gtk_container_add((GtkContainer *)priv->save, hbox1); + + gtk_widget_set_sensitive(priv->arrow, FALSE); + gtk_widget_set_sensitive(priv->save, FALSE); + + hbox2 = gtk_hbox_new (FALSE, 0); + gtk_box_pack_start ((GtkBox *)hbox2, priv->arrow, FALSE, FALSE, 0); + gtk_box_pack_start ((GtkBox *)hbox2, priv->label, FALSE, FALSE, 2); + gtk_box_pack_start ((GtkBox *)hbox2, priv->save, FALSE, FALSE, 2); + + priv->attachment_box = gtk_hbox_new (FALSE, 0); + gtk_box_pack_start ((GtkBox *)priv->attachment_box, priv->attachment_bar, TRUE, TRUE, 0); + + gtk_widget_get_size_request(priv->attachment_bar, &width, &height); + + /* FIXME: What if the text is more?. Should we reduce the text with appending ...? + * or resize the bar? How to figure out that, it needs more space? */ + gtk_widget_set_size_request (priv->attachment_bar, + ((GtkWidget *)efh->html)->parent->allocation.width - /* FIXME */36, + 84 /* FIXME: Default show only one row, Dont hardcode size*/); + + vbox = gtk_vbox_new (FALSE, 0); + gtk_box_pack_start ((GtkBox *)vbox, hbox2, FALSE, FALSE, 2); + gtk_box_pack_start ((GtkBox *)vbox, priv->attachment_box, TRUE, TRUE, 2); + + gtk_container_add ((GtkContainer *)eb, vbox); + gtk_widget_show_all ((GtkWidget *)eb); + + if (priv->show_bar) { + gtk_widget_show(priv->down); + gtk_widget_hide(priv->forward); + } else { + gtk_widget_show(priv->forward); + gtk_widget_hide(priv->down); + gtk_widget_hide(priv->attachment_box); + } + + g_signal_connect (priv->arrow, "clicked", G_CALLBACK(attachment_bar_arrow_clicked), efh); + g_signal_connect (priv->attachment_bar, "button_press_event", G_CALLBACK(efhd_bar_button_press_event), efhd); + g_signal_connect (priv->attachment_bar, "popup-menu", G_CALLBACK(efhd_bar_popup_menu_event), efhd); + g_signal_connect (priv->save, "clicked", G_CALLBACK(attachments_save_all_clicked), efh); + + return TRUE; +} + +static void +efhd_message_add_bar(EMFormat *emf, CamelStream *stream, CamelMimePart *part, const EMFormatHandler *info) +{ + EMFormatHTMLDisplay *efhd = (EMFormatHTMLDisplay *) emf; + const char *classid = "attachment-bar"; + + if (efhd->priv->bar_added) + return; + + efhd->priv->bar_added = TRUE; + em_format_html_add_pobject((EMFormatHTML *)emf, sizeof(EMFormatHTMLPObject), classid, part, efhd_add_bar); + camel_stream_printf(stream, "<td><object classid=\"%s\"></object></td>", classid); +} + +static void efhd_format_attachment(EMFormat *emf, CamelStream *stream, CamelMimePart *part, const char *mime_type, const EMFormatHandler *handle) { char *classid, *text, *html; @@ -1656,6 +1975,11 @@ efhd_format_attachment(EMFormat *emf, CamelStream *stream, CamelMimePart *part, info->shown = em_format_is_inline(emf, info->puri.part_id, info->puri.part, handle); info->snoop_mime_type = emf->snoop_mime_type; + if (emf->valid) { + info->sign = emf->valid->sign.status; + info->encrypt = emf->valid->encrypt.status; + } + camel_stream_write_string(stream, EM_FORMAT_HTML_VPAD "<table cellspacing=0 cellpadding=0><tr><td>" diff --git a/mail/em-format-html.c b/mail/em-format-html.c index 95190101ce..5e9b2626a9 100644 --- a/mail/em-format-html.c +++ b/mail/em-format-html.c @@ -1830,6 +1830,8 @@ efh_format_headers(EMFormatHTML *efh, CamelStream *stream, CamelMedium *part) static void efh_format_message(EMFormat *emf, CamelStream *stream, CamelMimePart *part, const EMFormatHandler *info) { + const EMFormatHandler *handle; + /* TODO: make this validity stuff a method */ EMFormatHTML *efh = (EMFormatHTML *) emf; CamelCipherValidity *save = emf->valid, *save_parent = emf->valid_parent; @@ -1842,6 +1844,10 @@ static void efh_format_message(EMFormat *emf, CamelStream *stream, CamelMimePart if (!efh->hide_headers) efh_format_headers(efh, stream, (CamelMedium *)part); + + handle = em_format_find_handler(emf, "x-evolution/message/post-header"); + if (handle) + handle->handler(emf, stream, part, handle); camel_stream_printf(stream, EM_FORMAT_HTML_VPAD); em_format_part(emf, stream, part); diff --git a/mail/em-popup.c b/mail/em-popup.c index c419e8a1d4..965365957e 100644 --- a/mail/em-popup.c +++ b/mail/em-popup.c @@ -64,6 +64,7 @@ #include <gconf/gconf-client.h> #include <e-util/e-util.h> +#include "e-attachment.h" static void emp_standard_menu_factory(EPopup *emp, void *data); @@ -365,8 +366,17 @@ em_popup_target_new_attachments(EMPopup *emp, GSList *attachments) t->attachments = attachments; if (len > 0) mask &= ~ EM_POPUP_ATTACHMENTS_MANY; - if (len == 1) + if (len == 1 && ((EAttachment *)attachments->data)->is_available_local) { + + if (camel_content_type_is(((CamelDataWrapper *) ((EAttachment *) attachments->data)->body)->mime_type, "image", "*")) + mask &= ~ EM_POPUP_ATTACHMENTS_IMAGE; + if (CAMEL_IS_MIME_MESSAGE(camel_medium_get_content_object((CamelMedium *) ((EAttachment *) attachments->data)->body))) + mask &= ~EM_POPUP_ATTACHMENTS_MESSAGE; + mask &= ~ EM_POPUP_ATTACHMENTS_ONE; + } + if (len > 1) + mask &= ~ EM_POPUP_ATTACHMENTS_MULTIPLE; t->target.mask = mask; return t; @@ -377,26 +387,39 @@ em_popup_target_new_attachments(EMPopup *emp, GSList *attachments) static void emp_part_popup_saveas(EPopup *ep, EPopupItem *item, void *data) { - EMPopupTargetPart *t = (EMPopupTargetPart *)ep->target; + EPopupTarget *t = ep->target; + CamelMimePart *part = NULL; - em_utils_save_part(ep->target->widget, _("Save As..."), t->part); + /* If it is of type EM_POPUP_TARGET_ATTACHMENTS, we can assume the length is one. */ + if (t->type == EM_POPUP_TARGET_ATTACHMENTS) + part = ((EAttachment *) ((EMPopupTargetAttachments *) t)->attachments->data)->body; + else + part = ((EMPopupTargetPart *) t)->part; + + em_utils_save_part(ep->target->widget, _("Save As..."), part); } static void emp_part_popup_set_background(EPopup *ep, EPopupItem *item, void *data) { - EMPopupTargetPart *t = (EMPopupTargetPart *)ep->target; + EPopupTarget *t = ep->target; GConfClient *gconf; char *str, *filename, *path, *extension; unsigned int i=1; + CamelMimePart *part = NULL; + + if (t->type == EM_POPUP_TARGET_ATTACHMENTS) + part = ((EAttachment *) ((EMPopupTargetAttachments *) t)->attachments->data)->body; + else + part = ((EMPopupTargetPart *) t)->part; - filename = g_strdup(camel_mime_part_get_filename(t->part)); + filename = g_strdup(camel_mime_part_get_filename(part)); /* if filename is blank, create a default filename based on MIME type */ if (!filename || !filename[0]) { CamelContentType *ct; - ct = camel_mime_part_get_content_type(t->part); + ct = camel_mime_part_get_content_type(part); g_free (filename); filename = g_strdup_printf (_("untitled_image.%s"), ct->subtype); } @@ -420,7 +443,7 @@ emp_part_popup_set_background(EPopup *ep, EPopupItem *item, void *data) g_free(filename); - if (em_utils_save_part_to_file(ep->target->widget, path, t->part)) { + if (em_utils_save_part_to_file(ep->target->widget, path, part)) { gconf = gconf_client_get_default(); /* if the filename hasn't changed, blank the filename before @@ -452,41 +475,65 @@ emp_part_popup_set_background(EPopup *ep, EPopupItem *item, void *data) static void emp_part_popup_reply_sender(EPopup *ep, EPopupItem *item, void *data) { - EMPopupTargetPart *t = (EMPopupTargetPart *)ep->target; + EPopupTarget *t = ep->target; CamelMimeMessage *message; + CamelMimePart *part; + + if (t->type == EM_POPUP_TARGET_ATTACHMENTS) + part = ((EAttachment *) ((EMPopupTargetAttachments *) t)->attachments->data)->body; + else + part = ((EMPopupTargetPart *) t)->part; - message = (CamelMimeMessage *)camel_medium_get_content_object((CamelMedium *)t->part); + message = (CamelMimeMessage *)camel_medium_get_content_object((CamelMedium *)part); em_utils_reply_to_message(NULL, NULL, message, REPLY_MODE_SENDER, NULL); } static void emp_part_popup_reply_list (EPopup *ep, EPopupItem *item, void *data) { - EMPopupTargetPart *t = (EMPopupTargetPart *)ep->target; + EPopupTarget *t = ep->target; CamelMimeMessage *message; - - message = (CamelMimeMessage *)camel_medium_get_content_object((CamelMedium *)t->part); + CamelMimePart *part; + + if (t->type == EM_POPUP_TARGET_ATTACHMENTS) + part = ((EAttachment *) ((EMPopupTargetAttachments *) t)->attachments->data)->body; + else + part = ((EMPopupTargetPart *) t)->part; + + message = (CamelMimeMessage *)camel_medium_get_content_object((CamelMedium *)part); em_utils_reply_to_message(NULL, NULL, message, REPLY_MODE_LIST, NULL); } static void emp_part_popup_reply_all (EPopup *ep, EPopupItem *item, void *data) { - EMPopupTargetPart *t = (EMPopupTargetPart *)ep->target; + EPopupTarget *t = ep->target; CamelMimeMessage *message; + CamelMimePart *part; + + if (t->type == EM_POPUP_TARGET_ATTACHMENTS) + part = ((EAttachment *) ((EMPopupTargetAttachments *) t)->attachments->data)->body; + else + part = ((EMPopupTargetPart *) t)->part; - message = (CamelMimeMessage *)camel_medium_get_content_object((CamelMedium *)t->part); + message = (CamelMimeMessage *)camel_medium_get_content_object((CamelMedium *)part); em_utils_reply_to_message(NULL, NULL, message, REPLY_MODE_ALL, NULL); } static void emp_part_popup_forward (EPopup *ep, EPopupItem *item, void *data) { - EMPopupTargetPart *t = (EMPopupTargetPart *)ep->target; + EPopupTarget *t = ep->target; CamelMimeMessage *message; + CamelMimePart *part; + + if (t->type == EM_POPUP_TARGET_ATTACHMENTS) + part = ((EAttachment *) ((EMPopupTargetAttachments *) t)->attachments->data)->body; + else + part = ((EMPopupTargetPart *) t)->part; /* TODO: have a emfv specific override so we can get the parent folder uri */ - message = (CamelMimeMessage *)camel_medium_get_content_object((CamelMedium *) t->part); + message = (CamelMimeMessage *)camel_medium_get_content_object((CamelMedium *) part); em_utils_forward_message(message, NULL); } @@ -501,6 +548,17 @@ static EMPopupItem emp_standard_object_popups[] = { { E_POPUP_ITEM, "20.part.00", N_("_Forward"), emp_part_popup_forward, NULL, "stock_mail-forward", EM_POPUP_PART_MESSAGE }, }; +static EMPopupItem emp_attachment_object_popups[] = { + { E_POPUP_ITEM, "00.attach.00", N_("_Save As..."), emp_part_popup_saveas, NULL, "stock_save-as", 0 }, + { E_POPUP_ITEM, "00.attach.10", N_("Set as _Background"), emp_part_popup_set_background, NULL, NULL, EM_POPUP_ATTACHMENTS_IMAGE }, + { E_POPUP_BAR, "05.attach", NULL, NULL, NULL, NULL, EM_POPUP_ATTACHMENTS_MESSAGE }, + { E_POPUP_ITEM, "05.attach.00", N_("_Reply to sender"), emp_part_popup_reply_sender, NULL, "stock_mail-reply" , EM_POPUP_ATTACHMENTS_MESSAGE }, + { E_POPUP_ITEM, "05.attach.01", N_("Reply to _List"), emp_part_popup_reply_list, NULL, NULL, EM_POPUP_ATTACHMENTS_MESSAGE}, + { E_POPUP_ITEM, "05.attach.03", N_("Reply to _All"), emp_part_popup_reply_all, NULL, "stock_mail-reply-to-all", EM_POPUP_ATTACHMENTS_MESSAGE}, + { E_POPUP_BAR, "05.attach.10", NULL, NULL, NULL, NULL, EM_POPUP_ATTACHMENTS_MESSAGE }, + { E_POPUP_ITEM, "05.attach.15", N_("_Forward"), emp_part_popup_forward, NULL, "stock_mail-forward", EM_POPUP_ATTACHMENTS_MESSAGE }, +}; + static const EPopupItem emp_standard_part_apps_bar = { E_POPUP_BAR, "99.object" }; /* ********************************************************************** */ @@ -563,9 +621,15 @@ static void emp_apps_open_in(EPopup *ep, EPopupItem *item, void *data) { char *path; - EMPopupTargetPart *target = (EMPopupTargetPart *)ep->target; + EPopupTarget *target = ep->target; + CamelMimePart *part; - path = em_utils_temp_save_part(target->target.widget, target->part); + if (target->type == EM_POPUP_TARGET_ATTACHMENTS) + part = ((EAttachment *) ((EMPopupTargetAttachments *) target)->attachments->data)->body; + else + part = ((EMPopupTargetPart *) target)->part; + + path = em_utils_temp_save_part(target->widget, part); if (path) { GnomeVFSMimeApplication *app = item->user_data; char *uri; @@ -610,6 +674,9 @@ emp_standard_menu_factory(EPopup *emp, void *data) int i, len; EPopupItem *items; GSList *menus = NULL; + GList *apps = NULL; + char *mime_type = NULL; + const char *filename = NULL; switch (emp->target->type) { #if 0 @@ -627,14 +694,42 @@ emp_standard_menu_factory(EPopup *emp, void *data) break; } case EM_POPUP_TARGET_PART: { EMPopupTargetPart *t = (EMPopupTargetPart *)emp->target; - GList *apps = gnome_vfs_mime_get_all_applications(t->mime_type); + mime_type = g_strdup(t->mime_type); + filename = camel_mime_part_get_filename(t->part); - /* FIXME: use the snoop_part stuff from em-format.c */ - if (apps == NULL && strcmp(t->mime_type, "application/octet-stream") == 0) { - const char *filename, *name_type; - - filename = camel_mime_part_get_filename(t->part); + items = emp_standard_object_popups; + len = LEN(emp_standard_object_popups); + break; } + case EM_POPUP_TARGET_ATTACHMENTS: { + EMPopupTargetAttachments *t = (EMPopupTargetAttachments *)emp->target; + GSList *list = t->attachments; + EAttachment *attachment; + + if (g_slist_length(list) != 1 || !((EAttachment *)list->data)->is_available_local) { + items = NULL; + len = 0; + break; + } + /* Only one attachment selected */ + attachment = list->data; + mime_type = camel_data_wrapper_get_mime_type((CamelDataWrapper *)attachment->body); + filename = camel_mime_part_get_filename(attachment->body); + + items = emp_attachment_object_popups; + len = LEN(emp_attachment_object_popups); + break; } + default: + items = NULL; + len = 0; + } + + if (mime_type) { + apps = gnome_vfs_mime_get_all_applications(mime_type); + + if (apps == NULL && strcmp(mime_type, "application/octet-stream") == 0) { + const char *name_type; + if (filename) { /* GNOME-VFS will misidentify TNEF attachments as MPEG */ if (!strcmp (filename, "winmail.dat")) @@ -645,6 +740,7 @@ emp_standard_menu_factory(EPopup *emp, void *data) apps = gnome_vfs_mime_get_all_applications(name_type); } } + g_free (mime_type); if (apps) { GString *label = g_string_new(""); @@ -676,13 +772,6 @@ emp_standard_menu_factory(EPopup *emp, void *data) g_string_free(label, TRUE); g_list_free(apps); } - - items = emp_standard_object_popups; - len = LEN(emp_standard_object_popups); - break; } - default: - items = NULL; - len = 0; } for (i=0;i<len;i++) { @@ -769,6 +858,9 @@ static const EPopupHookTargetMask emph_folder_masks[] = { static const EPopupHookTargetMask emph_attachments_masks[] = { { "one", EM_POPUP_ATTACHMENTS_ONE }, { "many", EM_POPUP_ATTACHMENTS_MANY }, + { "multiple", EM_POPUP_ATTACHMENTS_MULTIPLE }, + { "image", EM_POPUP_ATTACHMENTS_IMAGE }, + { "message", EM_POPUP_ATTACHMENTS_MESSAGE }, { 0 } }; diff --git a/mail/em-popup.h b/mail/em-popup.h index dc032f6783..6ae0623099 100644 --- a/mail/em-popup.h +++ b/mail/em-popup.h @@ -161,6 +161,9 @@ enum _em_popup_target_folder_t { enum _em_popup_target_attachments_t { EM_POPUP_ATTACHMENTS_ONE = 1<<0, /* only 1 selected */ EM_POPUP_ATTACHMENTS_MANY = 1<<1, /* one or more selected */ + EM_POPUP_ATTACHMENTS_MULTIPLE = 1<<2, /* More than 1 selected */ + EM_POPUP_ATTACHMENTS_IMAGE = 1<<3, /* Image selected */ + EM_POPUP_ATTACHMENTS_MESSAGE = 1<<4 /* Message selected */ }; typedef struct _EMPopupTargetSelect EMPopupTargetSelect; diff --git a/mail/em-utils.c b/mail/em-utils.c index 38b89078ec..5bd70e5be3 100644 --- a/mail/em-utils.c +++ b/mail/em-utils.c @@ -300,7 +300,7 @@ em_utils_edit_filters (GtkWidget *parent) /* Saving messages... */ static GtkWidget * -emu_get_save_filesel (GtkWidget *parent, const char *title, const char *name) +emu_get_save_filesel (GtkWidget *parent, const char *title, const char *name, GtkFileChooserAction action) { GtkWidget *filesel; const char *dir; @@ -310,7 +310,7 @@ emu_get_save_filesel (GtkWidget *parent, const char *title, const char *name) #ifdef USE_GTKFILECHOOSER filesel = gtk_file_chooser_dialog_new (title, NULL, - GTK_FILE_CHOOSER_ACTION_SAVE, + action, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_SAVE, GTK_RESPONSE_OK, NULL); @@ -439,12 +439,75 @@ em_utils_save_part(GtkWidget *parent, const char *prompt, CamelMimePart *part) } } - filesel = emu_get_save_filesel(parent, prompt, name); + filesel = emu_get_save_filesel(parent, prompt, name, GTK_FILE_CHOOSER_ACTION_SAVE); camel_object_ref(part); g_signal_connect (filesel, "response", G_CALLBACK (emu_save_part_response), part); gtk_widget_show (filesel); } +static void +emu_save_parts_response (GtkWidget *filesel, int response, GSList *parts) +{ + char *path = NULL; + GSList *selected; + if (response == GTK_RESPONSE_OK) { +#ifdef USE_GTKFILECHOOSER + path = gtk_file_chooser_get_current_folder (GTK_FILE_CHOOSER (filesel)); +#else + path = gtk_file_selection_get_filename (GTK_FILE_SELECTION (filesel)); +#endif + + emu_update_save_path(path); + + for ( selected = parts; selected != NULL; selected = selected->next) { + const char *file_name; + char *safe_name = NULL; + char *file_path; + CamelMimePart *part = selected->data; + + file_name = camel_mime_part_get_filename(part); + if (file_name == NULL) { + if (CAMEL_IS_MIME_MESSAGE(part)) { + file_name = camel_mime_message_get_subject((CamelMimeMessage *)part); + if (file_name == NULL) + file_name = _("message"); + } else { + file_name = _("attachment"); + } + } else { + safe_name = g_strdup(file_name); + e_filename_make_safe(safe_name); + file_name = safe_name; + } + + file_path = g_build_filename (path, file_name, NULL); + if (!g_file_test(file_path, (G_FILE_TEST_EXISTS))) + mail_save_part(part, file_path, NULL, NULL); + else + g_warning ("Could not save %s. File already exists", file_path); + + g_free (file_path); + g_free (safe_name); + } + + g_free (path); + } + + g_slist_free (parts); + gtk_widget_destroy((GtkWidget *)filesel); +} + +void +em_utils_save_parts (GtkWidget *parent, const char *prompt, GSList * parts) +{ + GtkWidget *filesel; + + filesel = emu_get_save_filesel (parent, prompt, NULL, GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER); + g_signal_connect (filesel, "response", G_CALLBACK (emu_save_parts_response), parts); + gtk_widget_show (filesel); +} + + /** * em_utils_save_part_to_file: * @parent: parent window @@ -542,7 +605,7 @@ em_utils_save_messages (GtkWidget *parent, CamelFolder *folder, GPtrArray *uids) g_return_if_fail (CAMEL_IS_FOLDER (folder)); g_return_if_fail (uids != NULL); - filesel = emu_get_save_filesel(parent, _("Save Message..."), NULL); + filesel = emu_get_save_filesel(parent, _("Save Message..."), NULL, GTK_FILE_CHOOSER_ACTION_SAVE); camel_object_ref(folder); data = g_malloc(sizeof(struct _save_messages_data)); diff --git a/mail/em-utils.h b/mail/em-utils.h index 4aa0d67389..0b27628dcb 100644 --- a/mail/em-utils.h +++ b/mail/em-utils.h @@ -77,6 +77,7 @@ void em_utils_selection_set_urilist(struct _GtkSelectionData *data, struct _Came void em_utils_selection_get_urilist(struct _GtkSelectionData *data, struct _CamelFolder *folder); char *em_utils_temp_save_part(struct _GtkWidget *parent, struct _CamelMimePart *part); +void em_utils_save_parts (struct _GtkWidget *parent, const char *prompt, GSList * parts); gboolean em_utils_folder_is_drafts(struct _CamelFolder *folder, const char *uri); gboolean em_utils_folder_is_sent(struct _CamelFolder *folder, const char *uri); |