2008-06-04 [colin] 3.4.0cvs82
[claws.git] / src / messageview.c
index 78d0a5a263345d24c7d8c60853a016bf6b905b18..c9cf88c1a56a5edfb9c8c1cfd0491a8b2a0754e8 100644 (file)
@@ -42,6 +42,7 @@
 #include "menu.h"
 #include "about.h"
 #include "filesel.h"
+#include "foldersel.h"
 #include "sourcewindow.h"
 #include "addressbook.h"
 #include "alertpanel.h"
 #include "inc.h"
 #include "log.h"
 #include "combobox.h"
+#include "printing.h"
+#include "quoted-printable.h"
+#include "version.h"
+#include "statusbar.h"
 
 static GList *messageview_list = NULL;
 
@@ -75,10 +80,11 @@ static gint messageview_delete_cb   (GtkWidget              *widget,
                                         MessageView            *messageview);
 static void messageview_size_allocate_cb(GtkWidget     *widget,
                                         GtkAllocation  *allocation);
+#ifndef MAEMO
 static gboolean key_pressed            (GtkWidget      *widget,
                                         GdkEventKey    *event,
                                         MessageView    *messageview);
-
+#endif
 static void return_receipt_show                (NoticeView     *noticeview, 
                                         MsgInfo        *msginfo);      
 static void return_receipt_send_clicked (NoticeView    *noticeview, 
@@ -94,6 +100,11 @@ static void partial_recv_unmark_clicked (NoticeView *noticeview,
 static void save_as_cb                 (gpointer        data,
                                         guint           action,
                                         GtkWidget      *widget);
+#if GTK_CHECK_VERSION(2,10,0) && !defined(USE_GNOMEPRINT)
+static void page_setup_cb              (gpointer        data,
+                                        guint           action,
+                                        GtkWidget      *widget);
+#endif
 static void print_cb                   (gpointer        data,
                                         guint           action,
                                         GtkWidget      *widget);
@@ -110,6 +121,49 @@ static void search_cb                      (gpointer        data,
                                         guint           action,
                                         GtkWidget      *widget);
 
+static void prev_cb                    (gpointer        data,
+                                        guint           action,
+                                        GtkWidget      *widget);
+static void next_cb                    (gpointer        data,
+                                        guint           action,
+                                        GtkWidget      *widget);
+static void prev_unread_cb             (gpointer        data,
+                                        guint           action,
+                                        GtkWidget      *widget);
+static void next_unread_cb             (gpointer        data,
+                                        guint           action,
+                                        GtkWidget      *widget);
+static void prev_new_cb                        (gpointer        data,
+                                        guint           action,
+                                        GtkWidget      *widget);
+static void next_new_cb                        (gpointer        data,
+                                        guint           action,
+                                        GtkWidget      *widget);
+static void prev_marked_cb             (gpointer        data,
+                                        guint           action,
+                                        GtkWidget      *widget);
+static void next_marked_cb             (gpointer        data,
+                                        guint           action,
+                                        GtkWidget      *widget);
+static void prev_labeled_cb            (gpointer        data,
+                                        guint           action,
+                                        GtkWidget      *widget);
+static void next_labeled_cb            (gpointer        data,
+                                        guint           action,
+                                        GtkWidget      *widget);
+static void last_read_cb               (gpointer        data,
+                                        guint           action,
+                                        GtkWidget      *widget);
+static void parent_cb                  (gpointer        data,
+                                        guint           action,
+                                        GtkWidget      *widget);
+static void goto_unread_folder_cb      (gpointer        data,
+                                        guint           action,
+                                        GtkWidget      *widget);
+static void goto_folder_cb             (gpointer        data,
+                                        guint           action,
+                                        GtkWidget      *widget);
+
 static void set_charset_cb             (gpointer        data,
                                         guint           action,
                                         GtkWidget      *widget);
@@ -163,6 +217,9 @@ static GtkItemFactoryEntry msgview_entries[] =
 {
        {N_("/_File"),                  NULL, NULL, 0, "<Branch>"},
        {N_("/_File/_Save as..."),      "<control>S", save_as_cb, 0, NULL},
+#if GTK_CHECK_VERSION(2,10,0) && !defined(USE_GNOMEPRINT)
+       {N_("/_File/Page setup..."),    NULL, page_setup_cb, 0, NULL},
+#endif
        {N_("/_File/_Print..."),        "<control>P", print_cb, 0, NULL},
        {N_("/_File/---"),              NULL, NULL, 0, "<Separator>"},
        {N_("/_File/_Close"),           "<control>W", close_cb, 0, NULL},
@@ -175,6 +232,36 @@ static GtkItemFactoryEntry msgview_entries[] =
                                        "<control>F", search_cb, 0, NULL},
 
        {N_("/_View"),                  NULL, NULL, 0, "<Branch>"},
+       {N_("/_View/_Go to"),                   NULL, NULL, 0, "<Branch>"},
+       {N_("/_View/_Go to/_Previous message"), "P", prev_cb, 0, NULL},
+       {N_("/_View/_Go to/_Next message"),     "N", next_cb, 0, NULL},
+       {N_("/_View/_Go to/---"),               NULL, NULL, 0, "<Separator>"},
+       {N_("/_View/_Go to/P_revious unread message"),
+                                               "<shift>P", prev_unread_cb, 0, NULL},
+       {N_("/_View/_Go to/N_ext unread message"),
+                                               "<shift>N", next_unread_cb, 0, NULL},
+       {N_("/_View/_Go to/---"),               NULL, NULL, 0, "<Separator>"},
+       {N_("/_View/_Go to/Previous ne_w message"),     NULL, prev_new_cb, 0, NULL},
+       {N_("/_View/_Go to/Ne_xt new message"), NULL, next_new_cb, 0, NULL},
+       {N_("/_View/_Go to/---"),               NULL, NULL, 0, "<Separator>"},
+       {N_("/_View/_Go to/Previous _marked message"),
+                                               NULL, prev_marked_cb, 0, NULL},
+       {N_("/_View/_Go to/Next m_arked message"),
+                                               NULL, next_marked_cb, 0, NULL},
+       {N_("/_View/_Go to/---"),               NULL, NULL, 0, "<Separator>"},
+       {N_("/_View/_Go to/Previous _labeled message"),
+                                               NULL, prev_labeled_cb, 0, NULL},
+       {N_("/_View/_Go to/Next la_beled message"),
+                                               NULL, next_labeled_cb, 0, NULL},
+       {N_("/_View/_Go to/---"),               NULL, NULL, 0, "<Separator>"},
+       {N_("/_View/_Go to/Last read message"),
+                                               NULL, last_read_cb, 0, NULL},
+       {N_("/_View/_Go to/Parent message"),
+                                               "<control>Up", parent_cb, 0, NULL},
+       {N_("/_View/_Go to/---"),               NULL, NULL, 0, "<Separator>"},
+       {N_("/_View/_Go to/Next unread _folder"),       "<shift>G", goto_unread_folder_cb, 0, NULL},
+       {N_("/_View/_Go to/_Other folder..."),  "G", goto_folder_cb, 0, NULL},
+       {N_("/_View/---"),                      NULL, NULL, 0, "<Separator>"},
 
 #define ENC_SEPARATOR \
        {N_("/_View/Character _encoding/---"),  NULL, NULL, 0, "<Separator>"}
@@ -185,7 +272,7 @@ static GtkItemFactoryEntry msgview_entries[] =
        {N_("/_View/Character _encoding/_Auto detect"),
                                        NULL, set_charset_cb, C_AUTO, "<RadioItem>"},
        ENC_SEPARATOR,
-       {N_("/_View/Character _encoding/7bit ascii (US-ASC_II)"),
+       {N_("/_View/Character _encoding/7bit ASCII (US-ASC_II)"),
         ENC_ACTION(C_US_ASCII)},
 
        {N_("/_View/Character _encoding/Unicode (_UTF-8)"),
@@ -379,6 +466,8 @@ MessageView *messageview_create(MainWindow *mainwin)
        messageview->statusbar     = NULL;
        messageview->statusbar_cid = 0;
 
+       messageview->show_full_text= FALSE;
+
        messageview->msginfo_update_callback_id =
                hooks_register_hook(MSGINFO_UPDATE_HOOKLIST, messageview_update_msg, (gpointer) messageview);
 
@@ -401,12 +490,14 @@ void messageview_update_actions_menu(MessageView *msgview)
        action_update_msgview_menu(ifactory, "/Tools/Actions", msgview);
 }
 
-void messageview_add_toolbar(MessageView *msgview, GtkWidget *window) 
+static void messageview_add_toolbar(MessageView *msgview, GtkWidget *window) 
 {
        GtkWidget *handlebox;
        GtkWidget *vbox;
        GtkWidget *menubar;
+#ifndef GENERIC_UMPC
        GtkWidget *statusbar = NULL;
+#endif
        guint n_menu_entries;
 
        vbox = gtk_vbox_new(FALSE, 0);
@@ -434,12 +525,17 @@ void messageview_add_toolbar(MessageView *msgview, GtkWidget *window)
 #else
        msgview->toolbar = toolbar_create(TOOLBAR_MSGVIEW, handlebox,
                                          (gpointer)msgview);
+#ifndef GENERIC_UMPC
        statusbar = gtk_statusbar_new();
        gtk_widget_show(statusbar);
        gtk_box_pack_end(GTK_BOX(vbox), statusbar, FALSE, FALSE, 0);
        msgview->statusbar = statusbar;
        msgview->statusbar_cid = gtk_statusbar_get_context_id
                (GTK_STATUSBAR(statusbar), "Message View");
+#else
+       msgview->statusbar = NULL;
+       msgview->statusbar_cid = 0;
+#endif
 #endif
 
 
@@ -559,7 +655,11 @@ static gint disposition_notification_send(MsgInfo *msginfo)
         gchar *addrp;
        gchar *foo = NULL;
        gboolean queued_removed = FALSE;
-       
+       gchar *boundary = NULL;
+       gchar *date = NULL;
+       gchar *orig_to = NULL;
+       gchar *enc_sub = NULL;
+
        if (!msginfo->extradata)
                return -1;
        if (!msginfo->extradata->returnreceiptto && 
@@ -588,7 +688,7 @@ static gint disposition_notification_send(MsgInfo *msginfo)
        if (ok != 0) {
                AlertValue val;
                gchar *message;
-               message = g_strdup_printf(
+               message = g_markup_printf_escaped(
                  _("The notification address to which the return receipt is\n"
                    "to be sent does not correspond to the return path:\n"
                    "Notification address: %s\n"
@@ -656,24 +756,29 @@ static gint disposition_notification_send(MsgInfo *msginfo)
        addrp = addr;
        
        /* write queue headers */
-       fprintf(fp, "AF:\n");
-       fprintf(fp, "NF:0\n");
-       fprintf(fp, "PS:10\n");
-       fprintf(fp, "SRH:1\n");
-       fprintf(fp, "SFN:\n");
-       fprintf(fp, "DSR:\n");
-       fprintf(fp, "MID:\n");
-       fprintf(fp, "CFG:\n");
-       fprintf(fp, "PT:0\n");
-       fprintf(fp, "S:%s\n", account->address);
-       fprintf(fp, "RQ:\n");
-       if (account->smtp_server)
-               fprintf(fp, "SSV:%s\n", account->smtp_server);
-       else
-               fprintf(fp, "SSV:\n");
-       fprintf(fp, "SSH:\n");
-       fprintf(fp, "R:<%s>\n", addrp);
-       
+       if (fprintf(fp, "AF:\n"
+                   "NF:0\n"
+                   "PS:10\n"
+                   "SRH:1\n"
+                   "SFN:\n"
+                   "DSR:\n"
+                   "MID:\n"
+                   "CFG:\n"
+                   "PT:0\n"
+                   "S:%s\n"
+                   "RQ:\n"
+                   "SSV:%s\n"
+                   "SSH:\n"
+                   "R:<%s>\n", 
+                   account->address,
+                   account->smtp_server?account->smtp_server:"",
+                   addrp) < 0) {
+               g_free(addrp);
+               fclose(fp);
+               claws_unlink(tmp);
+               return -1;
+       }
+
        g_free(addrp);
        
        /* check whether we need to save the message */
@@ -682,39 +787,160 @@ static gint disposition_notification_send(MsgInfo *msginfo)
                outbox = NULL;
        if (outbox) {
                path = folder_item_get_identifier(outbox);
-               fprintf(fp, "SCF:%s\n", path);
+               if (fprintf(fp, "SCF:%s\n", path) < 0) {
+                       g_free(path);
+                       fclose(fp);
+                       claws_unlink(tmp);
+                       return -1;
+               }
                g_free(path);
        }               
 
-       fprintf(fp, "X-Claws-End-Special-Headers: 1\n");
-       
+       if (fprintf(fp, "X-Claws-End-Special-Headers: 1\n") < 0) {
+               fclose(fp);
+               claws_unlink(tmp);
+               return -1;
+       }
+
        /* Date */
        get_rfc822_date(buf, sizeof(buf));
-       fprintf(fp, "Date: %s\n", buf);
+       if (fprintf(fp, "Date: %s\n", buf) < 0) {
+               fclose(fp);
+               claws_unlink(tmp);
+               return -1;
+       }
 
        /* From */
        if (account->name && *account->name) {
                notification_convert_header
                        (buf, sizeof(buf), account->name,
                         strlen("From: "));
-               fprintf(fp, "From: %s <%s>\n", buf, account->address);
+               if (fprintf(fp, "From: %s <%s>\n", buf, account->address) < 0) {
+                       fclose(fp);
+                       claws_unlink(tmp);
+                       return -1;
+               }
        } else
-               fprintf(fp, "From: %s\n", account->address);
+               if (fprintf(fp, "From: %s\n", account->address) < 0) {
+                       fclose(fp);
+                       claws_unlink(tmp);
+                       return -1;
+               }
+
 
-       fprintf(fp, "To: %s\n", to);
+       if (fprintf(fp, "To: %s\n", to) < 0) {
+               fclose(fp);
+               claws_unlink(tmp);
+               return -1;
+       }
 
        /* Subject */
        notification_convert_header(buf, sizeof(buf), msginfo->subject,
                                    strlen("Subject: "));
-       fprintf(fp, "Subject: Disposition notification: %s\n", buf);
+       if (fprintf(fp, "Subject: Disposition notification: %s\n", buf) < 0) {
+               fclose(fp);
+               claws_unlink(tmp);
+               return -1;
+       }
 
        /* Message ID */
-       generate_msgid(buf, sizeof(buf));
-       fprintf(fp, "Message-ID: <%s>\n", buf);
+       if (account->set_domain && account->domain) {
+               g_snprintf(buf, sizeof(buf), "%s", account->domain); 
+       } else if (!strncmp(get_domain_name(), "localhost", strlen("localhost"))) {
+               g_snprintf(buf, sizeof(buf), "%s", 
+                       strchr(account->address, '@') ?
+                               strchr(account->address, '@')+1 :
+                               account->address);
+       } else {
+               g_snprintf(buf, sizeof(buf), "%s", "");
+       }
+       
+       if (account->gen_msgid) {
+               generate_msgid(buf, sizeof(buf));
+
+               if (fprintf(fp, "Message-ID: <%s>\n", buf) < 0) {
+                       fclose(fp);
+                       claws_unlink(tmp);
+                       return -1;
+               }
+       }
+
+       boundary = generate_mime_boundary("DN");
+       get_rfc822_date(buf, sizeof(buf));
+       date = g_strdup(buf);
+       if (msginfo->to) {
+               orig_to = g_strdup(msginfo->to);
+               extract_address(orig_to);
+       }
+       if (msginfo->subject && *(msginfo->subject)) {
+               enc_sub = g_malloc0(strlen(msginfo->subject)*8);
+               qp_encode_line(enc_sub, (const guchar *)msginfo->subject);
+               g_strstrip(enc_sub);
+       }
+       if (fprintf(fp, "MIME-Version: 1.0\n"
+                       "Content-Type: multipart/report; report-type=disposition-notification;\n"
+                       "  boundary=\"%s\"\n"
+                       "\n"
+                       "--%s\n"
+                       "Content-Type: text/plain; charset=UTF-8\n"
+                       "Content-Transfer-Encoding: quoted-printable\n"
+                       "\n"
+                       "The message sent on: %s\n"
+                       "To: %s\n"
+                       "With subject: \"%s\"\n"
+                       "has been displayed at %s.\n"
+                       "\n"
+                       "There is no guarantee that the message has been read or understood.\n"
+                       "\n"
+                       "--%s\n"
+                       "Content-Type: message/disposition-notification\n"
+                       "\n"
+                       "Reporting-UA: %s\n"
+                       "Original-Recipient: rfc822;%s\n"
+                       "Final-Recipient: rfc822;%s\n"
+                       "Original-Message-ID: <%s>\n"
+                       "Disposition: manual-action/MDN-sent-manually; displayed\n"
+                       "\n"
+                       "--%s\n"
+                       "Content-Type: application/octet-stream\n"
+                       "Reporting-UA: %s\n"
+                       "Original-Recipient: rfc822;%s\n"
+                       "Final-Recipient: rfc822;%s\n"
+                       "Original-Message-ID: <%s>\n"
+                       "Disposition: manual-action/MDN-sent-manually; displayed\n"
+                       "\n"
+                       "--%s--\n", 
+                       boundary, 
+                       boundary,
+                       msginfo->date, 
+                       orig_to?orig_to:"No To:",
+                       enc_sub?enc_sub:"No subject",
+                       date,
+                       boundary,
+                       PROG_VERSION,
+                       orig_to?orig_to:"No To:",
+                       account->address,
+                       msginfo->msgid?msginfo->msgid:"NO MESSAGE ID",
+                       boundary,
+                       PROG_VERSION,
+                       orig_to?orig_to:"No To:",
+                       account->address,
+                       msginfo->msgid?msginfo->msgid:"NO MESSAGE ID",
+                       boundary) < 0) {
+               fclose(fp);
+               claws_unlink(tmp);
+               g_free(boundary);
+               return -1;
+       }
+
+       g_free(enc_sub);
+       g_free(orig_to);
+       g_free(date);
+       g_free(boundary);
 
        if (fclose(fp) == EOF) {
                FILE_OP_ERROR(tmp, "fclose");
-               g_unlink(tmp);
+               claws_unlink(tmp);
                return -1;
        }
 
@@ -723,13 +949,13 @@ static gint disposition_notification_send(MsgInfo *msginfo)
        if (!queue) queue = folder_get_default_queue();
        if (!queue) {
                g_warning("can't find queue folder\n");
-               g_unlink(tmp);
+               claws_unlink(tmp);
                return -1;
        }
        folder_item_scan(queue);
        if ((num = folder_item_add_msg(queue, tmp, NULL, TRUE)) < 0) {
                g_warning("can't queue the message\n");
-               g_unlink(tmp);
+               claws_unlink(tmp);
                return -1;
        }
                
@@ -781,6 +1007,9 @@ gint messageview_show(MessageView *messageview, MsgInfo *msginfo,
        gchar *subject = NULL;
        g_return_val_if_fail(msginfo != NULL, -1);
 
+       if (msginfo != messageview->msginfo)
+               messageview->show_full_text = FALSE;
+
        if (messageview->mimeview->textview &&
            messageview->mimeview->textview->loading) {
                messageview->mimeview->textview->stop_loading = TRUE;
@@ -802,11 +1031,36 @@ gint messageview_show(MessageView *messageview, MsgInfo *msginfo,
                                messageview->toolbar->learn_spam_btn, 
                                procmsg_spam_can_learn());
        }
+       
+       noticeview_hide(messageview->noticeview);
+       mimeview_clear(messageview->mimeview);
        messageview->updating = TRUE;
-       mimeinfo = procmime_scan_message(msginfo);
+
+       if (msginfo->size > 1024*1024)
+               statuswindow_print_all(_("Fetching message (%s)..."),
+                       to_human_readable(msginfo->size));
+       
+       file = procmsg_get_message_file_path(msginfo);
+
+       if (msginfo->size > 1024*1024)
+               statuswindow_pop_all();
+
+       if (!file) {
+               g_warning("can't get message file path.\n");
+               textview_show_error(messageview->mimeview->textview);
+               return -1;
+       }
+       
+       if (!folder_has_parent_of_type(msginfo->folder, F_QUEUE) &&
+           !folder_has_parent_of_type(msginfo->folder, F_DRAFT))
+               mimeinfo = procmime_scan_file(file);
+       else
+               mimeinfo = procmime_scan_queue_file(file);
+
        messageview->updating = FALSE;
        
        if (messageview->deferred_destroy) {
+               g_free(file);
                messageview_destroy(messageview);
                return 0;
        }
@@ -824,29 +1078,13 @@ gint messageview_show(MessageView *messageview, MsgInfo *msginfo,
                        break;
                }
        }
-       
-       messageview->updating = TRUE;
-       file = procmsg_get_message_file_path(msginfo);
-       messageview->updating = FALSE;
-       
-       if (messageview->deferred_destroy) {
-               g_free(file);
-               messageview_destroy(messageview);
-               return 0;
-       }
-
-       if (!file) {
-               g_warning("can't get message file path.\n");
-               procmime_mimeinfo_free_all(mimeinfo);
-               textview_show_error(messageview->mimeview->textview);
-               return -1;
-       }
-       
+                       
        if (messageview->msginfo != msginfo) {
                procmsg_msginfo_free(messageview->msginfo);
                messageview->msginfo = NULL;
                messageview_set_menu_sensitive(messageview);
-               messageview->msginfo = procmsg_msginfo_get_full_info(msginfo);
+               messageview->msginfo = 
+                       procmsg_msginfo_get_full_info_from_file(msginfo, file);
                if (!messageview->msginfo)
                        messageview->msginfo = procmsg_msginfo_copy(msginfo);
        } else {
@@ -871,7 +1109,9 @@ gint messageview_show(MessageView *messageview, MsgInfo *msginfo,
        }
        mimeview_show_message(messageview->mimeview, mimeinfo, file);
        
+#ifndef GENERIC_UMPC
        messageview_set_position(messageview, 0);
+#endif
 
        if (messageview->window && msginfo->subject) {
                subject = g_strdup(msginfo->subject);
@@ -894,18 +1134,18 @@ gint messageview_show(MessageView *messageview, MsgInfo *msginfo,
        main_create_mailing_list_menu(messageview->mainwin, messageview->msginfo);
 
        if (messageview->msginfo && messageview->msginfo->extradata
-           && messageview->msginfo->extradata->partial_recv)
+           && messageview->msginfo->extradata->partial_recv
+           && !noticeview_is_visible(messageview->noticeview))
                partial_recv_show(messageview->noticeview, 
                                  messageview->msginfo);
        else if (messageview->msginfo && messageview->msginfo->extradata &&
            (messageview->msginfo->extradata->dispositionnotificationto || 
             messageview->msginfo->extradata->returnreceiptto) &&
            !MSG_IS_RETRCPT_SENT(messageview->msginfo->flags) &&
-           !prefs_common.never_send_retrcpt)
+           !prefs_common.never_send_retrcpt &&
+           !noticeview_is_visible(messageview->noticeview))
                return_receipt_show(messageview->noticeview, 
                                    messageview->msginfo);
-       else 
-               noticeview_hide(messageview->noticeview);
 
        mimeinfo = procmime_mimeinfo_next(mimeinfo);
        if (!all_headers && mimeinfo 
@@ -913,12 +1153,76 @@ gint messageview_show(MessageView *messageview, MsgInfo *msginfo,
            strcasecmp(mimeinfo->subtype, "plain")) 
                        && (mimeinfo->type != MIMETYPE_MULTIPART || 
            strcasecmp(mimeinfo->subtype, "signed"))) {
-               if (strcasecmp(mimeinfo->subtype, "html"))
+               if (strcasecmp(mimeinfo->subtype, "html")) {
+                       MimeInfo *saved_mimeinfo = mimeinfo;
+                       MimeInfo *alt_parent = mimeinfo;
+
+                       /* if multipart/{related,mixed} part, look inside for a multipart/alternative child */
+                       if (prefs_common.promote_html_part &&
+                           mimeinfo->type == MIMETYPE_MULTIPART &&
+                           (!strcasecmp(mimeinfo->subtype, "related") ||
+                            !strcasecmp(mimeinfo->subtype, "mixed"))) {
+                               for (; mimeinfo; mimeinfo = procmime_mimeinfo_next(mimeinfo)) {
+                                       if (mimeinfo->node->parent != saved_mimeinfo->node) {
+                                               /* only consider children of the 
+                                                * multipart/{related,mixed} part */
+                                               continue;
+                                       }
+                                       if (mimeinfo->type == MIMETYPE_MULTIPART && 
+                                           !strcasecmp(mimeinfo->subtype, "alternative")) {
+                                               /* we got an alternative part */
+                                               alt_parent = mimeinfo;
+                                               break;
+                                       }
+                               }
+                       }
+
+                       /* if we now have a multipart/alternative part (possibly inside a
+                        * multipart/{related,mixed} part, look for an HTML part inside */
+                       if (prefs_common.promote_html_part && mimeinfo && 
+                           mimeinfo->type == MIMETYPE_MULTIPART &&
+                           !strcasecmp(mimeinfo->subtype, "alternative")) {
+                               for (; mimeinfo; mimeinfo = procmime_mimeinfo_next(mimeinfo)) {
+                                       if (mimeinfo->node->parent != alt_parent->node) {
+                                               /* only consider children of the 
+                                                * multipart/alternative part, so as
+                                                * not to show html attachments */
+                                               continue;
+                                       }
+                                       if (mimeinfo->type == MIMETYPE_TEXT && 
+                                           !strcasecmp(mimeinfo->subtype, "html")) {
+                                               /* we got it */
+                                               mimeview_select_mimepart_icon(messageview->mimeview, mimeinfo);
+                                               goto done;
+                                       }
+                               }
+                       }
+                       
+                       /* if we didn't find anything, go back to start */
+                       if (!mimeinfo) 
+                               mimeinfo = saved_mimeinfo;
+
                        mimeview_show_part(messageview->mimeview,mimeinfo);
-               else if (prefs_common.invoke_plugin_on_html)
-                       mimeview_select_mimepart_icon(messageview->mimeview,mimeinfo);
+                       goto done;
+               } else if (prefs_common.invoke_plugin_on_html) {
+                       mimeview_select_mimepart_icon(messageview->mimeview, mimeinfo);
+                       goto done;
+               }
        }
-
+       if (!all_headers && mimeinfo &&
+           mimeinfo->type == MIMETYPE_MULTIPART &&
+           mimeview_has_viewer_for_content_type(messageview->mimeview, "text/calendar")) {
+               /* look for a calendar part or it looks really strange */
+               while (mimeinfo) {
+                       if (mimeinfo->type == MIMETYPE_TEXT &&
+                           !strcasecmp(mimeinfo->subtype, "calendar")) {
+                               mimeview_select_mimepart_icon(messageview->mimeview, mimeinfo);
+                               goto done;
+                       }
+                       mimeinfo = procmime_mimeinfo_next(mimeinfo);
+               }
+       }
+done:
        g_free(file);
 
        return 0;
@@ -953,12 +1257,14 @@ void messageview_destroy(MessageView *messageview)
        debug_print("destroy messageview\n");
        messageview_list = g_list_remove(messageview_list, messageview);
 
-       if (messageview->mainwin->summaryview->messageview == messageview)
+       if (messageview->mainwin->summaryview->messageview == messageview) {
+               messageview->mainwin->summaryview->displayed = NULL;
                messageview->mainwin->summaryview->messageview = NULL;
-
-       if (messageview->mainwin->summaryview->ext_messageview == messageview)
+       }
+       if (messageview->mainwin->summaryview->ext_messageview == messageview) {
+               messageview->mainwin->summaryview->displayed = NULL;
                messageview->mainwin->summaryview->ext_messageview = NULL;
-
+       }
        if (!messageview->deferred_destroy) {
                hooks_unregister_hook(MSGINFO_UPDATE_HOOKLIST,
                              messageview->msginfo_update_callback_id);
@@ -1041,8 +1347,8 @@ void messageview_delete(MessageView *msgview)
                        /* NOTE: does not update to next message in summaryview */
                }
        }
-#ifdef MAEMO
-       if (msgview->window) {
+#ifdef GENERIC_UMPC
+       if (msgview->window && !prefs_common.always_show_msg) {
                messageview_destroy(msgview);
        }
 #endif
@@ -1069,14 +1375,6 @@ static void messageview_update(MessageView *msgview, MsgInfo *old_msginfo)
        } 
 }
 
-void messageview_quote_color_set(void)
-{
-}
-
-void messageview_set_font(MessageView *messageview)
-{
-}
-
 TextView *messageview_get_current_textview(MessageView *messageview)
 {
        TextView *text = NULL;
@@ -1233,7 +1531,7 @@ static void messageview_size_allocate_cb(GtkWidget *widget,
        prefs_common.msgwin_width  = allocation->width;
        prefs_common.msgwin_height = allocation->height;
 }
-
+#ifndef MAEMO
 static gboolean key_pressed(GtkWidget *widget, GdkEventKey *event,
                        MessageView *messageview)
 {
@@ -1242,7 +1540,7 @@ static gboolean key_pressed(GtkWidget *widget, GdkEventKey *event,
                return TRUE;
        }
 
-       if ((event->state & (GDK_MOD1_MASK|GDK_CONTROL_MASK)) != 0)
+       if ((event->state & (GDK_MOD1_MASK|GDK_CONTROL_MASK|GDK_SHIFT_MASK)) != 0)
                return FALSE;
 
        g_signal_stop_emission_by_name(G_OBJECT(widget),
@@ -1250,6 +1548,30 @@ static gboolean key_pressed(GtkWidget *widget, GdkEventKey *event,
        mimeview_pass_key_press_event(messageview->mimeview, event);
        return FALSE;
 }
+#endif
+
+static void messageview_show_partial_display_cb(NoticeView *noticeview, MessageView *messageview)
+{
+       messageview->show_full_text = TRUE;
+       main_window_cursor_wait(mainwindow_get_mainwindow());
+       GTK_EVENTS_FLUSH();
+       messageview_show(messageview, messageview->msginfo, messageview->all_headers);
+       main_window_cursor_normal(mainwindow_get_mainwindow());
+}
+
+void messageview_show_partial_display(MessageView *messageview, MsgInfo *msginfo,
+                                            size_t length)
+{
+       gchar *msg = g_strdup_printf(_("Show all %s."), to_human_readable((goffset)length));
+       noticeview_set_icon(messageview->noticeview, STOCK_PIXMAP_NOTICE_WARN);
+       noticeview_set_text(messageview->noticeview, _("Only the first megabyte of text is shown."));
+       noticeview_set_button_text(messageview->noticeview, msg);
+       g_free(msg);
+       noticeview_set_button_press_callback(messageview->noticeview,
+                                            G_CALLBACK(messageview_show_partial_display_cb),
+                                            (gpointer) messageview);
+       noticeview_show(messageview->noticeview);
+}
 
 static void return_receipt_show(NoticeView *noticeview, MsgInfo *msginfo)
 {
@@ -1263,7 +1585,7 @@ static void return_receipt_show(NoticeView *noticeview, MsgInfo *msginfo)
        addr = g_strdup(msginfo->from);
        if (addr) {
                extract_address(addr);
-               if (account_find_from_address(addr)) {
+               if (account_find_from_address(addr, FALSE)) {
                        from_me = TRUE;
                }
                g_free(addr);
@@ -1271,7 +1593,12 @@ static void return_receipt_show(NoticeView *noticeview, MsgInfo *msginfo)
 
        if (from_me) {
                noticeview_set_icon(noticeview, STOCK_PIXMAP_NOTICE_WARN);
-               noticeview_set_text(noticeview, _("You asked for a return receipt in this message."));
+               if (MSG_IS_RETRCPT_GOT(msginfo->flags)) {
+                       noticeview_set_text(noticeview, _("You got a return receipt in this message : "
+                                                         "it has been displayed by the recipient."));
+               } else {
+                       noticeview_set_text(noticeview, _("You asked for a return receipt in this message."));
+               }
                noticeview_set_button_text(noticeview, NULL);
                noticeview_set_button_press_callback(noticeview, NULL, NULL);
        } else {
@@ -1329,7 +1656,7 @@ static void partial_recv_show(NoticeView *noticeview, MsgInfo *msginfo)
                        text = g_strdup_printf(_("This message has been "
                                        "partially retrieved;\nit is %s."),
                                        to_human_readable(
-                                               (off_t)(msginfo->total_size)));
+                                               (goffset)(msginfo->total_size)));
                        button1 = _("Mark for download");
                        button2 = _("Mark for deletion");
                        button1_cb = partial_recv_dload_clicked;
@@ -1340,7 +1667,7 @@ static void partial_recv_show(NoticeView *noticeview, MsgInfo *msginfo)
                                        "partially retrieved;\nit is %s and "
                                        "will be downloaded."),
                                        to_human_readable(
-                                               (off_t)(msginfo->total_size)));
+                                               (goffset)(msginfo->total_size)));
                        button1 = _("Unmark");
                        button1_cb = partial_recv_unmark_clicked;
                        button2 = _("Mark for deletion");
@@ -1351,7 +1678,7 @@ static void partial_recv_show(NoticeView *noticeview, MsgInfo *msginfo)
                                        "partially retrieved;\nit is %s and "
                                        "will be deleted."),
                                        to_human_readable(
-                                               (off_t)(msginfo->total_size)));
+                                               (goffset)(msginfo->total_size)));
                        button1 = _("Mark for download");
                        button1_cb = partial_recv_dload_clicked;
                        button2 = _("Unmark");
@@ -1486,9 +1813,12 @@ static void save_as_cb(gpointer data, guint action, GtkWidget *widget)
        messageview_save_as(messageview);
 }
 
-#ifdef USE_GNOMEPRINT
+#if defined(USE_GNOMEPRINT) || GTK_CHECK_VERSION(2,10,0)
 static void print_mimeview(MimeView *mimeview, gint sel_start, gint sel_end, gint partnum) 
 {
+#if !defined(USE_GNOMEPRINT) && GTK_CHECK_VERSION(2,10,0)
+       MainWindow *mainwin;
+#endif
        if (!mimeview 
        ||  !mimeview->textview
        ||  !mimeview->textview->text)
@@ -1515,8 +1845,15 @@ static void print_mimeview(MimeView *mimeview, gint sel_start, gint sel_end, gin
                        gtk_text_buffer_get_iter_at_offset(buffer, &end, sel_end);
                        gtk_text_buffer_select_range(buffer, &start, &end);
                }
-
+#if defined(USE_GNOMEPRINT)
                gedit_print(GTK_TEXT_VIEW(mimeview->textview->text));
+#else
+               /* TODO: Get the real parent window, not the main window */
+               mainwin = mainwindow_get_mainwindow();
+               printing_print(GTK_TEXT_VIEW(mimeview->textview->text),
+                              mainwin ? GTK_WINDOW(mainwin->window) : NULL,
+                               sel_start, sel_end);
+#endif
        }
 }
 
@@ -1550,10 +1887,19 @@ void messageview_print(MsgInfo *msginfo, gboolean all_headers,
 }
 #endif
 
+#if GTK_CHECK_VERSION(2,10,0) && !defined(USE_GNOMEPRINT)
+static void page_setup_cb(gpointer data, guint action, GtkWidget *widget)
+{
+       MessageView *messageview = (MessageView *)data;
+       printing_page_setup(messageview ?
+                           GTK_WINDOW(messageview->window) : NULL);
+}
+#endif
+
 static void print_cb(gpointer data, guint action, GtkWidget *widget)
 {
        MessageView *messageview = (MessageView *)data;
-#ifndef USE_GNOMEPRINT
+#if !defined(USE_GNOMEPRINT) && !GTK_CHECK_VERSION(2,10,0)
        gchar *cmdline = NULL;
        gchar *p;
 #else
@@ -1561,7 +1907,8 @@ static void print_cb(gpointer data, guint action, GtkWidget *widget)
 #endif
 
        if (!messageview->msginfo) return;
-#ifndef USE_GNOMEPRINT
+
+#if !defined(USE_GNOMEPRINT) && !GTK_CHECK_VERSION(2,10,0)
        cmdline = input_dialog(_("Print"),
                               _("Enter the print command line:\n"
                                 "('%s' will be replaced with file name)"),
@@ -1609,6 +1956,362 @@ static void search_cb(gpointer data, guint action, GtkWidget *widget)
        message_search(messageview);
 }
 
+static void prev_cb(gpointer data, guint action, GtkWidget *widget)
+{
+       MessageView *messageview = (MessageView *)data;
+       messageview->updating = TRUE;
+       summary_step(messageview->mainwin->summaryview, GTK_SCROLL_STEP_BACKWARD);
+       messageview->updating = FALSE;
+
+       if (messageview->deferred_destroy) {
+               debug_print("messageview got away!\n");
+               messageview_destroy(messageview);
+               return;
+       }
+       if (messageview->mainwin->summaryview->selected) {
+#ifndef GENERIC_UMPC
+               MsgInfo * msginfo = summary_get_selected_msg(messageview->mainwin->summaryview);
+                      
+               if (msginfo)
+                       messageview_show(messageview, msginfo, 
+                                        messageview->all_headers);
+#endif
+       } else {
+               gtk_widget_destroy(messageview->window);
+       }
+}
+
+static void next_cb(gpointer data, guint action, GtkWidget *widget)
+{
+       MessageView *messageview = (MessageView *)data;
+       messageview->updating = TRUE;
+       summary_step(messageview->mainwin->summaryview, GTK_SCROLL_STEP_FORWARD);
+       messageview->updating = FALSE;
+
+       if (messageview->deferred_destroy) {
+               debug_print("messageview got away!\n");
+               messageview_destroy(messageview);
+               return;
+       }
+       if (messageview->mainwin->summaryview->selected) {
+#ifndef GENERIC_UMPC
+               MsgInfo * msginfo = summary_get_selected_msg(messageview->mainwin->summaryview);
+                      
+               if (msginfo)
+                       messageview_show(messageview, msginfo, 
+                                        messageview->all_headers);
+#endif
+       } else {
+               gtk_widget_destroy(messageview->window);
+       }
+}
+
+static void prev_unread_cb(gpointer data, guint action, GtkWidget *widget)
+{
+       MessageView *messageview = (MessageView *)data;
+       messageview->updating = TRUE;
+       summary_select_prev_unread(messageview->mainwin->summaryview);
+       messageview->updating = FALSE;
+
+       if (messageview->deferred_destroy) {
+               debug_print("messageview got away!\n");
+               messageview_destroy(messageview);
+               return;
+       }
+       if (messageview->mainwin->summaryview->selected) {
+#ifndef GENERIC_UMPC
+               MsgInfo * msginfo = summary_get_selected_msg(messageview->mainwin->summaryview);
+                      
+               if (msginfo)
+                       messageview_show(messageview, msginfo, 
+                                        messageview->all_headers);
+#endif
+       } else {
+               gtk_widget_destroy(messageview->window);
+       }
+}
+
+static void next_unread_cb(gpointer data, guint action, GtkWidget *widget)
+{
+       MessageView *messageview = (MessageView *)data;
+       messageview->updating = TRUE;
+       summary_select_next_unread(messageview->mainwin->summaryview);
+       messageview->updating = FALSE;
+
+       if (messageview->deferred_destroy) {
+               debug_print("messageview got away!\n");
+               messageview_destroy(messageview);
+               return;
+       }
+       if (messageview->mainwin->summaryview->selected) {
+#ifndef GENERIC_UMPC
+               MsgInfo * msginfo = summary_get_selected_msg(messageview->mainwin->summaryview);
+                      
+               if (msginfo)
+                       messageview_show(messageview, msginfo, 
+                                        messageview->all_headers);
+#endif
+       } else {
+               gtk_widget_destroy(messageview->window);
+       }
+}
+
+static void prev_new_cb(gpointer data, guint action, GtkWidget *widget)
+{
+       MessageView *messageview = (MessageView *)data;
+       messageview->updating = TRUE;
+       summary_select_prev_new(messageview->mainwin->summaryview);
+       messageview->updating = FALSE;
+
+       if (messageview->deferred_destroy) {
+               debug_print("messageview got away!\n");
+               messageview_destroy(messageview);
+               return;
+       }
+       if (messageview->mainwin->summaryview->selected) {
+#ifndef GENERIC_UMPC
+               MsgInfo * msginfo = summary_get_selected_msg(messageview->mainwin->summaryview);
+                      
+               if (msginfo)
+                       messageview_show(messageview, msginfo, 
+                                        messageview->all_headers);
+#endif
+       } else {
+               gtk_widget_destroy(messageview->window);
+       }
+}
+
+static void next_new_cb(gpointer data, guint action, GtkWidget *widget)
+{
+       MessageView *messageview = (MessageView *)data;
+       messageview->updating = TRUE;
+       summary_select_next_new(messageview->mainwin->summaryview);
+       messageview->updating = FALSE;
+
+       if (messageview->deferred_destroy) {
+               debug_print("messageview got away!\n");
+               messageview_destroy(messageview);
+               return;
+       }
+       if (messageview->mainwin->summaryview->selected) {
+#ifndef GENERIC_UMPC
+               MsgInfo * msginfo = summary_get_selected_msg(messageview->mainwin->summaryview);
+                      
+               if (msginfo)
+                       messageview_show(messageview, msginfo, 
+                                        messageview->all_headers);
+#endif
+       } else {
+               gtk_widget_destroy(messageview->window);
+       }
+}
+
+static void prev_marked_cb(gpointer data, guint action, GtkWidget *widget)
+{
+       MessageView *messageview = (MessageView *)data;
+       messageview->updating = TRUE;
+       summary_select_prev_marked(messageview->mainwin->summaryview);
+       messageview->updating = FALSE;
+
+       if (messageview->deferred_destroy) {
+               debug_print("messageview got away!\n");
+               messageview_destroy(messageview);
+               return;
+       }
+       if (messageview->mainwin->summaryview->selected) {
+#ifndef GENERIC_UMPC
+               MsgInfo * msginfo = summary_get_selected_msg(messageview->mainwin->summaryview);
+                      
+               if (msginfo)
+                       messageview_show(messageview, msginfo, 
+                                        messageview->all_headers);
+#endif
+       } else {
+               gtk_widget_destroy(messageview->window);
+       }
+}
+
+static void next_marked_cb(gpointer data, guint action, GtkWidget *widget)
+{
+       MessageView *messageview = (MessageView *)data;
+       messageview->updating = TRUE;
+       summary_select_next_marked(messageview->mainwin->summaryview);
+       messageview->updating = FALSE;
+
+       if (messageview->deferred_destroy) {
+               debug_print("messageview got away!\n");
+               messageview_destroy(messageview);
+               return;
+       }
+       if (messageview->mainwin->summaryview->selected) {
+#ifndef GENERIC_UMPC
+               MsgInfo * msginfo = summary_get_selected_msg(messageview->mainwin->summaryview);
+                      
+               if (msginfo)
+                       messageview_show(messageview, msginfo, 
+                                        messageview->all_headers);
+#endif
+       } else {
+               gtk_widget_destroy(messageview->window);
+       }
+}
+
+static void prev_labeled_cb(gpointer data, guint action, GtkWidget *widget)
+{
+       MessageView *messageview = (MessageView *)data;
+       messageview->updating = TRUE;
+       summary_select_prev_labeled(messageview->mainwin->summaryview);
+       messageview->updating = FALSE;
+
+       if (messageview->deferred_destroy) {
+               debug_print("messageview got away!\n");
+               messageview_destroy(messageview);
+               return;
+       }
+       if (messageview->mainwin->summaryview->selected) {
+#ifndef GENERIC_UMPC
+               MsgInfo * msginfo = summary_get_selected_msg(messageview->mainwin->summaryview);
+                      
+               if (msginfo)
+                       messageview_show(messageview, msginfo, 
+                                        messageview->all_headers);
+#endif
+       } else {
+               gtk_widget_destroy(messageview->window);
+       }
+}
+
+static void next_labeled_cb(gpointer data, guint action, GtkWidget *widget)
+{
+       MessageView *messageview = (MessageView *)data;
+       messageview->updating = TRUE;
+       summary_select_next_labeled(messageview->mainwin->summaryview);
+       messageview->updating = FALSE;
+
+       if (messageview->deferred_destroy) {
+               debug_print("messageview got away!\n");
+               messageview_destroy(messageview);
+               return;
+       }
+       if (messageview->mainwin->summaryview->selected) {
+#ifndef GENERIC_UMPC
+               MsgInfo * msginfo = summary_get_selected_msg(messageview->mainwin->summaryview);
+                      
+               if (msginfo)
+                       messageview_show(messageview, msginfo, 
+                                        messageview->all_headers);
+#endif
+       } else {
+               gtk_widget_destroy(messageview->window);
+       }
+}
+
+static void last_read_cb(gpointer data, guint action, GtkWidget *widget)
+{
+       MessageView *messageview = (MessageView *)data;
+       messageview->updating = TRUE;
+       summary_select_last_read(messageview->mainwin->summaryview);
+       messageview->updating = FALSE;
+
+       if (messageview->deferred_destroy) {
+               debug_print("messageview got away!\n");
+               messageview_destroy(messageview);
+               return;
+       }
+       if (messageview->mainwin->summaryview->selected) {
+#ifndef GENERIC_UMPC
+               MsgInfo * msginfo = summary_get_selected_msg(messageview->mainwin->summaryview);
+                      
+               if (msginfo)
+                       messageview_show(messageview, msginfo, 
+                                        messageview->all_headers);
+#endif
+       } else {
+               gtk_widget_destroy(messageview->window);
+       }
+}
+
+static void parent_cb(gpointer data, guint action, GtkWidget *widget)
+{
+       MessageView *messageview = (MessageView *)data;
+       messageview->updating = TRUE;
+       summary_select_parent(messageview->mainwin->summaryview);
+       messageview->updating = FALSE;
+
+       if (messageview->deferred_destroy) {
+               debug_print("messageview got away!\n");
+               messageview_destroy(messageview);
+               return;
+       }
+       if (messageview->mainwin->summaryview->selected) {
+#ifndef GENERIC_UMPC
+               MsgInfo * msginfo = summary_get_selected_msg(messageview->mainwin->summaryview);
+                      
+               if (msginfo)
+                       messageview_show(messageview, msginfo, 
+                                        messageview->all_headers);
+#endif
+       } else {
+               gtk_widget_destroy(messageview->window);
+       }
+}
+
+static void goto_unread_folder_cb(gpointer data, guint action, GtkWidget *widget)
+{
+       MessageView *messageview = (MessageView *)data;
+       messageview->updating = TRUE;
+       folderview_select_next_unread(messageview->mainwin->folderview, FALSE);
+       messageview->updating = FALSE;
+
+       if (messageview->deferred_destroy) {
+               debug_print("messageview got away!\n");
+               messageview_destroy(messageview);
+               return;
+       }
+       if (messageview->mainwin->summaryview->selected) {
+#ifndef GENERIC_UMPC
+               MsgInfo * msginfo = summary_get_selected_msg(messageview->mainwin->summaryview);
+                      
+               if (msginfo)
+                       messageview_show(messageview, msginfo, 
+                                        messageview->all_headers);
+#endif
+       } else {
+               gtk_widget_destroy(messageview->window);
+       }
+}
+
+static void goto_folder_cb(gpointer data, guint action, GtkWidget *widget)
+{
+       MessageView *messageview = (MessageView *)data;
+       messageview->updating = TRUE;
+       FolderItem *to_folder;
+       messageview->updating = FALSE;
+
+       to_folder = foldersel_folder_sel(NULL, FOLDER_SEL_ALL, NULL, FALSE);
+
+       if (to_folder) {
+               folderview_select(messageview->mainwin->folderview, to_folder);
+
+               if (messageview->deferred_destroy) {
+                       debug_print("messageview got away!\n");
+                       messageview_destroy(messageview);
+                       return;
+               }
+               if (messageview->mainwin->summaryview->selected) {
+#ifndef GENERIC_UMPC
+                       MsgInfo * msginfo = summary_get_selected_msg(messageview->mainwin->summaryview);
+                      
+                       if (msginfo)
+                               messageview_show(messageview, msginfo, 
+                                                messageview->all_headers);
+#endif
+               } else {
+                       gtk_widget_destroy(messageview->window);
+               }
+       }
+}
+
 static void set_charset_cb(gpointer data, guint action, GtkWidget *widget)
 {
        MessageView *messageview = (MessageView *)data;
@@ -1749,15 +2452,42 @@ static void addressbook_open_cb(gpointer data, guint action, GtkWidget *widget)
 static void add_address_cb(gpointer data, guint action, GtkWidget *widget)
 {
        MessageView *messageview = (MessageView *)data;
-       MsgInfo *msginfo;
+       MsgInfo *msginfo, *full_msginfo;
        gchar *from;
+       GtkWidget *image = NULL;
+       GdkPixbuf *picture = NULL;
+
+       if (!messageview->msginfo || !messageview->msginfo->from) 
+               return;
 
-       if (!messageview->msginfo) return;
        msginfo = messageview->msginfo;
        Xstrdup_a(from, msginfo->from, return);
        eliminate_address_comment(from);
        extract_address(from);
-       addressbook_add_contact(msginfo->fromname, from, NULL);
+       
+       full_msginfo = procmsg_msginfo_get_full_info(msginfo);
+       if (full_msginfo &&
+           full_msginfo->extradata &&
+           full_msginfo->extradata->face) {
+               image = face_get_from_header(full_msginfo->extradata->face);
+       } 
+#if HAVE_LIBCOMPFACE
+       else if (full_msginfo &&
+                full_msginfo->extradata &&
+                full_msginfo->extradata->xface) {
+               image = xface_get_from_header(full_msginfo->extradata->xface,
+                               &messageview->mainwin->summaryview->ctree->style->white,
+                               messageview->window->window);   
+       }
+#endif
+       procmsg_msginfo_free(full_msginfo);
+       if (image)
+               picture = gtk_image_get_pixbuf(GTK_IMAGE(image));
+
+       addressbook_add_contact(msginfo->fromname, from, NULL, picture);
+
+       if (image)
+               gtk_widget_destroy(image);
 }
 
 static void create_filter_cb(gpointer data, guint action, GtkWidget *widget)
@@ -1870,6 +2600,7 @@ void messageview_list_urls (MessageView   *msgview)
 {
        GSList *cur = msgview->mimeview->textview->uri_list;
        GSList *newlist = NULL;
+       GHashTable *uri_hashtable = g_hash_table_new(g_str_hash, g_str_equal); 
        for (; cur; cur = cur->next) {
                ClickableText *uri = (ClickableText *)cur->data;
                if (uri->uri &&
@@ -1878,9 +2609,17 @@ void messageview_list_urls (MessageView  *msgview)
                     !g_ascii_strncasecmp(uri->uri, "www.", 4) ||
                     !g_ascii_strncasecmp(uri->uri, "http:", 5) ||
                     !g_ascii_strncasecmp(uri->uri, "https:", 6)))
+               {
+                       if(g_hash_table_lookup(uri_hashtable, uri->uri))
+                               continue;
+                       
                        newlist = g_slist_prepend(newlist, uri);
+                       g_hash_table_insert(uri_hashtable, uri->uri,
+                                           GUINT_TO_POINTER(g_str_hash(uri->uri)));
+               }
        }
        newlist = g_slist_reverse(newlist);
        uri_opener_open(msgview, newlist);
        g_slist_free(newlist);
+       g_hash_table_destroy(uri_hashtable);
 }