X-Git-Url: http://git.maemo.org/git/?p=modest;a=blobdiff_plain;f=src%2Fmodest-tny-msg-view.c;h=af06c1a656b07649d82e2cc4f8613fdaf009b49e;hp=c23098798c2446062c57119fc42e704d3cfd1e0c;hb=4d20731e682d655fee5b419fc9cdd485df5a63d2;hpb=760ddf92f15a11e080a26c560c2f09beddc5f32c diff --git a/src/modest-tny-msg-view.c b/src/modest-tny-msg-view.c index c230987..af06c1a 100644 --- a/src/modest-tny-msg-view.c +++ b/src/modest-tny-msg-view.c @@ -4,11 +4,15 @@ #include "modest-tny-msg-view.h" #include "modest-tny-stream-gtkhtml.h" +#include "modest-tny-msg-actions.h" + #include #include #include #include #include +#include +#include /* 'private'/'protected' functions */ static void modest_tny_msg_view_class_init (ModestTnyMsgViewClass *klass); @@ -17,15 +21,16 @@ static void modest_tny_msg_view_finalize (GObject *obj); static GSList* get_url_matches (GString *txt); -static gboolean fill_gtkhtml_with_txt (GtkHTML* gtkhtml, const gchar* txt); +static gboolean fill_gtkhtml_with_txt (ModestTnyMsgView *self, GtkHTML* gtkhtml, const gchar* txt, TnyMsgIface *msg); static gboolean on_link_clicked (GtkWidget *widget, const gchar *uri, ModestTnyMsgView *msg_view); static gboolean on_url_requested (GtkWidget *widget, const gchar *uri, GtkHTMLStream *stream, ModestTnyMsgView *msg_view); - - +static gchar *construct_virtual_filename(const gchar *filename, const gint position, const gchar *id, const gboolean active); +static gchar *construct_virtual_filename_from_mime_part(TnyMsgMimePartIface *msg, const gint position); +gint virtual_filename_get_pos(const gchar *filename); /* * we need these regexps to find URLs in plain text e-mails */ @@ -63,6 +68,7 @@ typedef struct _ModestTnyMsgViewPrivate ModestTnyMsgViewPrivate; struct _ModestTnyMsgViewPrivate { GtkWidget *gtkhtml; TnyMsgIface *msg; + ModestConf *conf; }; #define MODEST_TNY_MSG_VIEW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \ MODEST_TYPE_TNY_MSG_VIEW, \ @@ -118,13 +124,15 @@ modest_tny_msg_view_init (ModestTnyMsgView *obj) priv->msg = NULL; priv->gtkhtml = gtk_html_new(); + + priv->conf = NULL; gtk_html_set_editable (GTK_HTML(priv->gtkhtml), FALSE); - gtk_html_allow_selection (GTK_HTML(priv->gtkhtml), TRUE); - gtk_html_set_caret_mode (GTK_HTML(priv->gtkhtml), FALSE); - gtk_html_set_blocking (GTK_HTML(priv->gtkhtml), FALSE); - gtk_html_set_images_blocking (GTK_HTML(priv->gtkhtml), FALSE); - + gtk_html_allow_selection (GTK_HTML(priv->gtkhtml), TRUE); + gtk_html_set_caret_mode (GTK_HTML(priv->gtkhtml), FALSE); + gtk_html_set_blocking (GTK_HTML(priv->gtkhtml), FALSE); + gtk_html_set_images_blocking (GTK_HTML(priv->gtkhtml), FALSE); + g_signal_connect (G_OBJECT(priv->gtkhtml), "link_clicked", G_CALLBACK(on_link_clicked), obj); @@ -140,7 +148,7 @@ modest_tny_msg_view_finalize (GObject *obj) } GtkWidget* -modest_tny_msg_view_new (TnyMsgIface *msg) +modest_tny_msg_view_new (TnyMsgIface *msg, ModestConf *conf) { GObject *obj; ModestTnyMsgView* self; @@ -159,6 +167,8 @@ modest_tny_msg_view_new (TnyMsgIface *msg) if (msg) modest_tny_msg_view_set_message (self, msg); + + priv->conf = conf; return GTK_WIDGET(self); } @@ -169,7 +179,25 @@ static gboolean on_link_clicked (GtkWidget *widget, const gchar *uri, ModestTnyMsgView *msg_view) { + ModestTnyMsgViewPrivate *priv; + + + if (g_str_has_prefix(uri, "attachment:")) { + priv = MODEST_TNY_MSG_VIEW_GET_PRIVATE(msg_view); + /* toggle ...SHOW_ATTACHMENTS_INLINE */ + modest_conf_set_bool(priv->conf, + MODEST_CONF_MSG_VIEW_SHOW_ATTACHMENTS_INLINE, + !modest_conf_get_bool(priv->conf, + MODEST_CONF_MSG_VIEW_SHOW_ATTACHMENTS_INLINE, + NULL), + NULL); + + modest_tny_msg_view_set_message(msg_view, priv->msg); + return TRUE; + } g_message ("link clicked: %s", uri); /* FIXME */ + return FALSE; + } @@ -188,6 +216,7 @@ find_cid_image (TnyMsgIface *msg, const gchar *cid) const gchar *part_cid; part = TNY_MSG_MIME_PART_IFACE(parts->data); part_cid = tny_msg_mime_part_iface_get_content_id (part); + printf("CMP:%s:%s\n", cid, part_cid); if (part_cid && strcmp (cid, part_cid) == 0) return part; /* we found it! */ @@ -199,6 +228,32 @@ find_cid_image (TnyMsgIface *msg, const gchar *cid) } +static TnyMsgMimePartIface * +find_attachment_by_filename (TnyMsgIface *msg, const gchar *fn) +{ + TnyMsgMimePartIface *part = NULL; + GList *parts; + gchar *dummy; + gint pos; + + g_return_val_if_fail (msg, NULL); + g_return_val_if_fail (fn, NULL); + + parts = (GList*) tny_msg_iface_get_parts (msg); + pos = virtual_filename_get_pos(fn); + + g_return_val_if_fail(((pos >= 0) && (pos < g_list_length(parts))), NULL); + + part = g_list_nth_data(parts, pos); + + dummy = construct_virtual_filename_from_mime_part(part, pos); + if (strcmp(dummy, fn) == 0) + return part; + else + return NULL; +} + + static gboolean on_url_requested (GtkWidget *widget, const gchar *uri, GtkHTMLStream *stream, @@ -223,6 +278,17 @@ on_url_requested (GtkWidget *widget, const gchar *uri, tny_msg_mime_part_iface_decode_to_stream (part,tny_stream); gtk_html_stream_close (stream, GTK_HTML_STREAM_OK); } + } else if (g_str_has_prefix (uri, "Attachment:")) { + TnyMsgMimePartIface *part = find_attachment_by_filename (priv->msg, uri); + if (!part) { + g_message ("%s not found", uri); + gtk_html_stream_close (stream, GTK_HTML_STREAM_ERROR); + } else { + TnyStreamIface *tny_stream = + TNY_STREAM_IFACE(modest_tny_stream_gtkhtml_new(stream)); + tny_msg_mime_part_iface_decode_to_stream (part,tny_stream); + gtk_html_stream_close (stream, GTK_HTML_STREAM_OK); + } } return TRUE; } @@ -237,6 +303,150 @@ typedef struct { } url_match_t; + +static gchar * +construct_virtual_filename(const gchar *filename, const gint position, const gchar *id, const gboolean active) +{ + GString *s; + g_return_val_if_fail((position >= 0), "AttachmentInvalid"); + + s = g_string_new(""); + if (active) + g_string_append(s, "Attachment:"); + else + g_string_append(s, "attachment:"); + g_string_append_printf(s, "%d:", position); + if (id) + g_string_append(s, id); + g_string_append_c(s, ':'); + if (filename) + g_string_append(s, filename); + g_string_append_c(s, ':'); + return g_string_free(s, FALSE); +} + + +static gchar * +construct_virtual_filename_from_mime_part(TnyMsgMimePartIface *msg, const gint position) +{ + const gchar *id, *filename; + const gboolean active = TRUE; + + filename = tny_msg_mime_part_iface_get_filename( + TNY_MSG_MIME_PART_IFACE(msg)); + if (!filename) + filename = "[unknown]"; + id = tny_msg_mime_part_iface_get_content_id( + TNY_MSG_MIME_PART_IFACE(msg)); + + return construct_virtual_filename(filename, position, id, active); +} + +const gchar * +get_next_token(const gchar *s, gint *len) +{ + gchar *i1, *i2; + i1 = (char *) s; + i2 = (char *) s; + + while (i2[0]) { + if (i2[0] == ':') + break; + i2++; + } + if (!i2[0]) + return NULL; + *len = i2 - i1; + return ++i2; +} + +/* maybe I should use libregexp */ +gint +virtual_filename_get_pos(const gchar *filename) +{ + const gchar *i1, *i2; + gint len, pos; + GString *dummy; + + i1 = filename; + i2 = filename; + + /* check prefix */ + i2 = get_next_token(i2, &len); + if (strncmp(i1, "Attachment", len) != 0) + return -1; + i1 = i2; + + /* get position */ + i2 = get_next_token(i2, &len); + if (i2 == NULL) + return -1; + dummy = g_string_new_len(i1, len); + pos = atoi(dummy->str); + g_string_free(dummy, FALSE); + return pos; +} + + +static gchar * +attachments_as_html(ModestTnyMsgView *self, TnyMsgIface *msg) +{ + ModestTnyMsgViewPrivate *priv; + gboolean attachments_found = FALSE; + GString *appendix; + const GList *attachment_list, *attachment; + const gchar *content_type, *filename, *id; + gchar *virtual_filename; + gboolean show_attachments_inline; + + if (!msg) + return g_malloc0(1); + + priv = MODEST_TNY_MSG_VIEW_GET_PRIVATE (self); + + /* CLEANUP: starting a new HTML may be unsupported */ + appendix = g_string_new("\n
Attachments:
\n"); + + attachment_list = tny_msg_iface_get_parts(msg); + attachment = attachment_list; + while (attachment) { + filename = ""; + content_type = tny_msg_mime_part_iface_get_content_type( + TNY_MSG_MIME_PART_IFACE(attachment->data)); + g_return_val_if_fail(content_type, NULL); + if ( tny_msg_mime_part_iface_content_type_is( + TNY_MSG_MIME_PART_IFACE(attachment->data), + "image/jpeg") + || tny_msg_mime_part_iface_content_type_is( + TNY_MSG_MIME_PART_IFACE(attachment->data), + "image/gif")) { + filename = tny_msg_mime_part_iface_get_filename( + TNY_MSG_MIME_PART_IFACE(attachment->data)); + if (!filename) + filename = "[unknown]"; + else + attachments_found = TRUE; + id = tny_msg_mime_part_iface_get_content_id( + TNY_MSG_MIME_PART_IFACE(attachment->data)); + show_attachments_inline = modest_conf_get_bool(priv->conf, MODEST_CONF_MSG_VIEW_SHOW_ATTACHMENTS_INLINE, NULL); + virtual_filename = construct_virtual_filename(filename, + g_list_position((GList *)attachment_list, (GList *) attachment), + id, show_attachments_inline); + printf("VF:%s\n", virtual_filename); + if (show_attachments_inline) { + g_string_append_printf(appendix, "\n
%s\n", virtual_filename, filename, filename); + } else { + g_string_append_printf(appendix, "%s: %s
\n", filename, filename, content_type); + } + } + attachment = attachment->next; + } + g_string_append(appendix, ""); + if (!attachments_found) + g_string_assign(appendix, ""); + return g_string_free(appendix, FALSE); +} + static void hyperlinkify_plain_text (GString *txt) { @@ -261,8 +471,10 @@ hyperlinkify_plain_text (GString *txt) g_free (url); g_free (repl); - + + g_free (cursor->data); } + g_slist_free (match_list); } @@ -322,7 +534,7 @@ convert_to_html (const gchar *data) } } } - + g_string_append (html, ""); hyperlinkify_plain_text (html); @@ -410,45 +622,31 @@ get_url_matches (GString *txt) } static gboolean -fill_gtkhtml_with_txt (GtkHTML* gtkhtml, const gchar* txt) +fill_gtkhtml_with_txt (ModestTnyMsgView *self, GtkHTML* gtkhtml, const gchar* txt, TnyMsgIface *msg) { - gchar *html; + GString *html; + gchar *html_attachments; g_return_val_if_fail (gtkhtml, FALSE); g_return_val_if_fail (txt, FALSE); - html = convert_to_html (txt); - gtk_html_load_from_string (gtkhtml, html, strlen(html)); - g_free (html); + html = g_string_new(convert_to_html (txt)); + html_attachments = attachments_as_html(self, msg); + g_string_append(html, html_attachments); + + gtk_html_load_from_string (gtkhtml, html->str, html->len); + g_string_free (html, TRUE); + g_free(html_attachments); return TRUE; } -static TnyMsgMimePartIface * -find_body_part (TnyMsgIface *msg, const gchar *mime_type) -{ - TnyMsgMimePartIface *part = NULL; - GList *parts; - - g_return_val_if_fail (msg, NULL); - g_return_val_if_fail (mime_type, NULL); - - parts = (GList*) tny_msg_iface_get_parts (msg); - while (parts && !part) { - part = TNY_MSG_MIME_PART_IFACE(parts->data); - if (!tny_msg_mime_part_iface_content_type_is (part, mime_type)) - part = NULL; - parts = parts->next; - } - - return part; -} - static gboolean -set_html_message (ModestTnyMsgView *self, TnyMsgMimePartIface *tny_body) +set_html_message (ModestTnyMsgView *self, TnyMsgMimePartIface *tny_body, TnyMsgIface *msg) { + gchar *html_attachments; TnyStreamIface *gtkhtml_stream; ModestTnyMsgViewPrivate *priv; @@ -463,9 +661,13 @@ set_html_message (ModestTnyMsgView *self, TnyMsgMimePartIface *tny_body) tny_stream_iface_reset (gtkhtml_stream); tny_msg_mime_part_iface_decode_to_stream (tny_body, gtkhtml_stream); + html_attachments = attachments_as_html(self, msg); + /* is this clean? */ + gtkhtml_write(gtkhtml_stream, html_attachments, strlen(html_attachments)); tny_stream_iface_reset (gtkhtml_stream); g_object_unref (G_OBJECT(gtkhtml_stream)); + g_free (html_attachments); return TRUE; } @@ -474,7 +676,7 @@ set_html_message (ModestTnyMsgView *self, TnyMsgMimePartIface *tny_body) /* this is a hack --> we use the tny_text_buffer_stream to * get the message text, then write to gtkhtml 'by hand' */ static gboolean -set_text_message (ModestTnyMsgView *self, TnyMsgMimePartIface *tny_body) +set_text_message (ModestTnyMsgView *self, TnyMsgMimePartIface *tny_body, TnyMsgIface *msg) { GtkTextBuffer *buf; GtkTextIter begin, end; @@ -497,8 +699,8 @@ set_text_message (ModestTnyMsgView *self, TnyMsgMimePartIface *tny_body) gtk_text_buffer_get_bounds (buf, &begin, &end); txt = gtk_text_buffer_get_text (buf, &begin, &end, FALSE); - fill_gtkhtml_with_txt (GTK_HTML(priv->gtkhtml), txt); - + fill_gtkhtml_with_txt (self, GTK_HTML(priv->gtkhtml), txt, msg); + g_object_unref (G_OBJECT(txt_stream)); g_object_unref (G_OBJECT(buf)); @@ -506,7 +708,7 @@ set_text_message (ModestTnyMsgView *self, TnyMsgMimePartIface *tny_body) return TRUE; } -GtkTextBuffer * +gchar * modest_tny_msg_view_get_selected_text (ModestTnyMsgView *self) { ModestTnyMsgViewPrivate *priv; @@ -514,28 +716,20 @@ modest_tny_msg_view_get_selected_text (ModestTnyMsgView *self) GtkWidget *html; int len; GtkClipboard *clip; - gchar *text; - GtkTextBuffer *buf; - g_return_if_fail (self); + g_return_val_if_fail (self, NULL); priv = MODEST_TNY_MSG_VIEW_GET_PRIVATE(self); html = priv->gtkhtml; /* I'm sure there is a better way to check for selected text */ sel = gtk_html_get_selection_html(GTK_HTML(html), &len); - if (sel == NULL) + if (!sel) return NULL; + g_free(sel); clip = gtk_widget_get_clipboard(html, GDK_SELECTION_PRIMARY); - text = gtk_clipboard_wait_for_text(clip); - if (text == NULL) - return NULL; - - buf = gtk_text_buffer_new(NULL); - gtk_text_buffer_set_text(buf, text, -1); - g_free(text); - return buf; + return gtk_clipboard_wait_for_text(clip); } void @@ -550,24 +744,24 @@ modest_tny_msg_view_set_message (ModestTnyMsgView *self, TnyMsgIface *msg) priv->msg = msg; - fill_gtkhtml_with_txt (GTK_HTML(priv->gtkhtml), ""); + fill_gtkhtml_with_txt (self, GTK_HTML(priv->gtkhtml), "", msg); if (!msg) return; - body = find_body_part (msg, "text/html"); + body = modest_tny_msg_actions_find_body_part (msg, "text/html"); if (body) { - set_html_message (self, body); + set_html_message (self, body, msg); return; } - body = find_body_part (msg, "text/plain"); + body = modest_tny_msg_actions_find_body_part (msg, "text/plain"); if (body) { - set_text_message (self, body); + set_text_message (self, body, msg); return; } /* hmmmmm */ - fill_gtkhtml_with_txt (GTK_HTML(priv->gtkhtml), - _("Unsupported message type")); + fill_gtkhtml_with_txt (self, GTK_HTML(priv->gtkhtml), + _("Unsupported message type"), msg); }