2008-03-07 [paul] 3.3.1cvs17
[claws.git] / src / messageview.c
1 /*
2  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 1999-2007 Hiroyuki Yamamoto and the Claws Mail team
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  * 
18  */
19
20 #include "defs.h"
21
22 #include <glib.h>
23 #include <glib/gi18n.h>
24 #include <gdk/gdkkeysyms.h>
25 #include <gtk/gtkvbox.h>
26 #include <gtk/gtkcontainer.h>
27 #include <gtk/gtkwindow.h>
28 #include <gtk/gtktext.h>
29 #include <gtk/gtkmenu.h>
30 #include <gtk/gtkmenuitem.h>
31 #include <stdio.h>
32 #include <ctype.h>
33 #include <string.h>
34
35 #include "main.h"
36 #include "messageview.h"
37 #include "message_search.h"
38 #include "headerview.h"
39 #include "summaryview.h"
40 #include "textview.h"
41 #include "mimeview.h"
42 #include "menu.h"
43 #include "about.h"
44 #include "filesel.h"
45 #include "foldersel.h"
46 #include "sourcewindow.h"
47 #include "addressbook.h"
48 #include "alertpanel.h"
49 #include "inputdialog.h"
50 #include "mainwindow.h"
51 #include "manage_window.h"
52 #include "procmsg.h"
53 #include "procheader.h"
54 #include "procmime.h"
55 #include "account.h"
56 #include "action.h"
57 #include "prefs_common.h"
58 #include "prefs_account.h"
59 #include "gtkutils.h"
60 #include "utils.h"
61 #include "send_message.h"
62 #include "stock_pixmap.h"
63 #include "hooks.h"
64 #include "filtering.h"
65 #include "partial_download.h"
66 #include "gedit-print.h"
67 #include "uri_opener.h"
68 #include "inc.h"
69 #include "log.h"
70 #include "combobox.h"
71 #include "printing.h"
72 #include "quoted-printable.h"
73 #include "version.h"
74 #include "statusbar.h"
75
76 static GList *messageview_list = NULL;
77
78 static gint messageview_delete_cb       (GtkWidget              *widget,
79                                          GdkEventAny            *event,
80                                          MessageView            *messageview);
81 static void messageview_size_allocate_cb(GtkWidget      *widget,
82                                          GtkAllocation  *allocation);
83 #ifndef MAEMO
84 static gboolean key_pressed             (GtkWidget      *widget,
85                                          GdkEventKey    *event,
86                                          MessageView    *messageview);
87 #endif
88 static void return_receipt_show         (NoticeView     *noticeview, 
89                                          MsgInfo        *msginfo);      
90 static void return_receipt_send_clicked (NoticeView     *noticeview, 
91                                          MsgInfo        *msginfo);
92 static void partial_recv_show           (NoticeView     *noticeview, 
93                                          MsgInfo        *msginfo);      
94 static void partial_recv_dload_clicked  (NoticeView     *noticeview, 
95                                          MsgInfo        *msginfo);
96 static void partial_recv_del_clicked    (NoticeView     *noticeview, 
97                                          MsgInfo        *msginfo);
98 static void partial_recv_unmark_clicked (NoticeView     *noticeview, 
99                                          MsgInfo        *msginfo);
100 static void save_as_cb                  (gpointer        data,
101                                          guint           action,
102                                          GtkWidget      *widget);
103 #if GTK_CHECK_VERSION(2,10,0) && !defined(USE_GNOMEPRINT)
104 static void page_setup_cb               (gpointer        data,
105                                          guint           action,
106                                          GtkWidget      *widget);
107 #endif
108 static void print_cb                    (gpointer        data,
109                                          guint           action,
110                                          GtkWidget      *widget);
111 static void close_cb                    (gpointer        data,
112                                          guint           action,
113                                          GtkWidget      *widget);
114 static void copy_cb                     (gpointer        data,
115                                          guint           action,
116                                          GtkWidget      *widget);
117 static void allsel_cb                   (gpointer        data,
118                                          guint           action,
119                                          GtkWidget      *widget);
120 static void search_cb                   (gpointer        data,
121                                          guint           action,
122                                          GtkWidget      *widget);
123
124 static void prev_cb                     (gpointer        data,
125                                          guint           action,
126                                          GtkWidget      *widget);
127 static void next_cb                     (gpointer        data,
128                                          guint           action,
129                                          GtkWidget      *widget);
130 static void prev_unread_cb              (gpointer        data,
131                                          guint           action,
132                                          GtkWidget      *widget);
133 static void next_unread_cb              (gpointer        data,
134                                          guint           action,
135                                          GtkWidget      *widget);
136 static void prev_new_cb                 (gpointer        data,
137                                          guint           action,
138                                          GtkWidget      *widget);
139 static void next_new_cb                 (gpointer        data,
140                                          guint           action,
141                                          GtkWidget      *widget);
142 static void prev_marked_cb              (gpointer        data,
143                                          guint           action,
144                                          GtkWidget      *widget);
145 static void next_marked_cb              (gpointer        data,
146                                          guint           action,
147                                          GtkWidget      *widget);
148 static void prev_labeled_cb             (gpointer        data,
149                                          guint           action,
150                                          GtkWidget      *widget);
151 static void next_labeled_cb             (gpointer        data,
152                                          guint           action,
153                                          GtkWidget      *widget);
154 static void last_read_cb                (gpointer        data,
155                                          guint           action,
156                                          GtkWidget      *widget);
157 static void parent_cb                   (gpointer        data,
158                                          guint           action,
159                                          GtkWidget      *widget);
160 static void goto_unread_folder_cb       (gpointer        data,
161                                          guint           action,
162                                          GtkWidget      *widget);
163 static void goto_folder_cb              (gpointer        data,
164                                          guint           action,
165                                          GtkWidget      *widget);
166
167 static void set_charset_cb              (gpointer        data,
168                                          guint           action,
169                                          GtkWidget      *widget);
170 static void set_decode_cb               (gpointer        data,
171                                          guint           action,
172                                          GtkWidget      *widget);
173 static void view_source_cb              (gpointer        data,
174                                          guint           action,
175                                          GtkWidget      *widget);
176 static void show_all_header_cb          (gpointer        data,
177                                          guint           action,
178                                          GtkWidget      *widget);
179 static void msg_hide_quotes_cb          (gpointer        data,
180                                          guint           action,
181                                          GtkWidget      *widget);
182
183 static void compose_cb                  (gpointer        data,
184                                          guint           action,
185                                          GtkWidget      *widget);
186 static void reply_cb                    (gpointer        data,
187                                          guint           action,
188                                          GtkWidget      *widget);
189
190 static PrefsAccount *select_account_from_list
191                                         (GList          *ac_list);
192 static void addressbook_open_cb         (gpointer        data,
193                                          guint           action,
194                                          GtkWidget      *widget);
195 static void add_address_cb              (gpointer        data,
196                                          guint           action,
197                                          GtkWidget      *widget);
198 static void create_filter_cb            (gpointer        data,
199                                          guint           action,
200                                          GtkWidget      *widget);
201 static void create_processing_cb        (gpointer        data,
202                                          guint           action,
203                                          GtkWidget      *widget);
204 static void open_urls_cb                (gpointer        data,
205                                          guint           action,
206                                          GtkWidget      *widget);
207
208 static void about_cb                    (gpointer        data,
209                                          guint           action,
210                                          GtkWidget      *widget);
211 static void messageview_update          (MessageView    *msgview,
212                                          MsgInfo        *old_msginfo);
213 static gboolean messageview_update_msg  (gpointer source, gpointer data);
214
215 static GList *msgview_list = NULL;
216 static GtkItemFactoryEntry msgview_entries[] =
217 {
218         {N_("/_File"),                  NULL, NULL, 0, "<Branch>"},
219         {N_("/_File/_Save as..."),      "<control>S", save_as_cb, 0, NULL},
220 #if GTK_CHECK_VERSION(2,10,0) && !defined(USE_GNOMEPRINT)
221         {N_("/_File/Page setup..."),    NULL, page_setup_cb, 0, NULL},
222 #endif
223         {N_("/_File/_Print..."),        "<control>P", print_cb, 0, NULL},
224         {N_("/_File/---"),              NULL, NULL, 0, "<Separator>"},
225         {N_("/_File/_Close"),           "<control>W", close_cb, 0, NULL},
226
227         {N_("/_Edit"),                  NULL, NULL, 0, "<Branch>"},
228         {N_("/_Edit/_Copy"),            "<control>C", copy_cb, 0, NULL},
229         {N_("/_Edit/Select _all"),      "<control>A", allsel_cb, 0, NULL},
230         {N_("/_Edit/---"),              NULL, NULL, 0, "<Separator>"},
231         {N_("/_Edit/_Find in current message..."),
232                                         "<control>F", search_cb, 0, NULL},
233
234         {N_("/_View"),                  NULL, NULL, 0, "<Branch>"},
235         {N_("/_View/_Go to"),                   NULL, NULL, 0, "<Branch>"},
236         {N_("/_View/_Go to/_Previous message"), "P", prev_cb, 0, NULL},
237         {N_("/_View/_Go to/_Next message"),     "N", next_cb, 0, NULL},
238         {N_("/_View/_Go to/---"),               NULL, NULL, 0, "<Separator>"},
239         {N_("/_View/_Go to/P_revious unread message"),
240                                                 "<shift>P", prev_unread_cb, 0, NULL},
241         {N_("/_View/_Go to/N_ext unread message"),
242                                                 "<shift>N", next_unread_cb, 0, NULL},
243         {N_("/_View/_Go to/---"),               NULL, NULL, 0, "<Separator>"},
244         {N_("/_View/_Go to/Previous ne_w message"),     NULL, prev_new_cb, 0, NULL},
245         {N_("/_View/_Go to/Ne_xt new message"), NULL, next_new_cb, 0, NULL},
246         {N_("/_View/_Go to/---"),               NULL, NULL, 0, "<Separator>"},
247         {N_("/_View/_Go to/Previous _marked message"),
248                                                 NULL, prev_marked_cb, 0, NULL},
249         {N_("/_View/_Go to/Next m_arked message"),
250                                                 NULL, next_marked_cb, 0, NULL},
251         {N_("/_View/_Go to/---"),               NULL, NULL, 0, "<Separator>"},
252         {N_("/_View/_Go to/Previous _labeled message"),
253                                                 NULL, prev_labeled_cb, 0, NULL},
254         {N_("/_View/_Go to/Next la_beled message"),
255                                                 NULL, next_labeled_cb, 0, NULL},
256         {N_("/_View/_Go to/---"),               NULL, NULL, 0, "<Separator>"},
257         {N_("/_View/_Go to/Last read message"),
258                                                 NULL, last_read_cb, 0, NULL},
259         {N_("/_View/_Go to/Parent message"),
260                                                 "<control>Up", parent_cb, 0, NULL},
261         {N_("/_View/_Go to/---"),               NULL, NULL, 0, "<Separator>"},
262         {N_("/_View/_Go to/Next unread _folder"),       "<shift>G", goto_unread_folder_cb, 0, NULL},
263         {N_("/_View/_Go to/_Other folder..."),  "G", goto_folder_cb, 0, NULL},
264         {N_("/_View/---"),                      NULL, NULL, 0, "<Separator>"},
265
266 #define ENC_SEPARATOR \
267         {N_("/_View/Character _encoding/---"),  NULL, NULL, 0, "<Separator>"}
268 #define ENC_ACTION(action) \
269         NULL, set_charset_cb, action, "/View/Character encoding/Auto detect"
270
271         {N_("/_View/Character _encoding"),      NULL, NULL, 0, "<Branch>"},
272         {N_("/_View/Character _encoding/_Auto detect"),
273                                         NULL, set_charset_cb, C_AUTO, "<RadioItem>"},
274         ENC_SEPARATOR,
275         {N_("/_View/Character _encoding/7bit ASCII (US-ASC_II)"),
276          ENC_ACTION(C_US_ASCII)},
277
278         {N_("/_View/Character _encoding/Unicode (_UTF-8)"),
279          ENC_ACTION(C_UTF_8)},
280         ENC_SEPARATOR,
281         {N_("/_View/Character _encoding/Western European (ISO-8859-_1)"),
282          ENC_ACTION(C_ISO_8859_1)},
283         {N_("/_View/Character _encoding/Western European (ISO-8859-15)"),
284          ENC_ACTION(C_ISO_8859_15)},
285         {N_("/_View/Character _encoding/Western European (Windows-1252)"),
286          ENC_ACTION(C_WINDOWS_1252)},
287         ENC_SEPARATOR,
288         {N_("/_View/Character _encoding/Central European (ISO-8859-_2)"),
289          ENC_ACTION(C_ISO_8859_2)},
290         ENC_SEPARATOR,
291         {N_("/_View/Character _encoding/_Baltic (ISO-8859-13)"),
292          ENC_ACTION(C_ISO_8859_13)},
293         {N_("/_View/Character _encoding/Baltic (ISO-8859-_4)"),
294          ENC_ACTION(C_ISO_8859_4)},
295         ENC_SEPARATOR,
296         {N_("/_View/Character _encoding/Greek (ISO-8859-_7)"),
297          ENC_ACTION(C_ISO_8859_7)},
298         ENC_SEPARATOR,
299         {N_("/_View/Character _encoding/Hebrew (ISO-8859-_8)"),
300          ENC_ACTION(C_ISO_8859_8)},
301         {N_("/_View/Character _encoding/Hebrew (Windows-1255)"),
302          ENC_ACTION(C_CP1255)},
303         ENC_SEPARATOR,
304         {N_("/_View/Character _encoding/Arabic (ISO-8859-_6)"),
305          ENC_ACTION(C_ISO_8859_6)},
306         {N_("/_View/Character _encoding/Arabic (Windows-1256)"),
307          ENC_ACTION(C_CP1256)},
308         ENC_SEPARATOR,
309         {N_("/_View/Character _encoding/Turkish (ISO-8859-_9)"),
310          ENC_ACTION(C_ISO_8859_9)},
311         ENC_SEPARATOR,
312         {N_("/_View/Character _encoding/Cyrillic (ISO-8859-_5)"),
313          ENC_ACTION(C_ISO_8859_5)},
314         {N_("/_View/Character _encoding/Cyrillic (KOI8-_R)"),
315          ENC_ACTION(C_KOI8_R)},
316         {N_("/_View/Character _encoding/Cyrillic (KOI8-U)"),
317          ENC_ACTION(C_KOI8_U)},
318         {N_("/_View/Character _encoding/Cyrillic (Windows-1251)"),
319          ENC_ACTION(C_CP1251)},
320         ENC_SEPARATOR,
321         {N_("/_View/Character _encoding/Japanese (ISO-2022-_JP)"),
322          ENC_ACTION(C_ISO_2022_JP)},
323         {N_("/_View/Character _encoding/Japanese (ISO-2022-JP-2)"),
324          ENC_ACTION(C_ISO_2022_JP_2)},
325         {N_("/_View/Character _encoding/Japanese (_EUC-JP)"),
326          ENC_ACTION(C_EUC_JP)},
327         {N_("/_View/Character _encoding/Japanese (_Shift__JIS)"),
328          ENC_ACTION(C_SHIFT_JIS)},
329         ENC_SEPARATOR,
330         {N_("/_View/Character _encoding/Simplified Chinese (_GB2312)"),
331          ENC_ACTION(C_GB2312)},
332         {N_("/_View/Character _encoding/Simplified Chinese (GBK)"),
333          ENC_ACTION(C_GBK)},
334         {N_("/_View/Character _encoding/Traditional Chinese (_Big5)"),
335          ENC_ACTION(C_BIG5)},
336         {N_("/_View/Character _encoding/Traditional Chinese (EUC-_TW)"),
337          ENC_ACTION(C_EUC_TW)},
338         {N_("/_View/Character _encoding/Chinese (ISO-2022-_CN)"),
339          ENC_ACTION(C_ISO_2022_CN)},
340         ENC_SEPARATOR,
341         {N_("/_View/Character _encoding/Korean (EUC-_KR)"),
342          ENC_ACTION(C_EUC_KR)},
343         {N_("/_View/Character _encoding/Korean (ISO-2022-KR)"),
344          ENC_ACTION(C_ISO_2022_KR)},
345         ENC_SEPARATOR,
346         {N_("/_View/Character _encoding/Thai (TIS-620)"),
347          ENC_ACTION(C_TIS_620)},
348         {N_("/_View/Character _encoding/Thai (Windows-874)"),
349          ENC_ACTION(C_WINDOWS_874)},
350
351 #undef ENC_SEPARATOR
352 #undef ENC_ACTION
353
354 #define DEC_SEPARATOR \
355         {N_("/_View/Decode/---"),               NULL, NULL, 0, "<Separator>"}
356 #define DEC_ACTION(action) \
357          NULL, set_decode_cb, action, "/View/Decode/Auto detect"
358         {N_("/_View/Decode"),           NULL, NULL, 0, "<Branch>"},
359         {N_("/_View/Decode/_Auto detect"),
360          NULL, set_decode_cb, 0, "<RadioItem>"},
361         {N_("/_View/Decode/---"),               NULL, NULL, 0, "<Separator>"},
362         {N_("/_View/Decode/_8bit"),             DEC_ACTION(ENC_8BIT)},
363         {N_("/_View/Decode/_Quoted printable"), DEC_ACTION(ENC_QUOTED_PRINTABLE)},
364         {N_("/_View/Decode/_Base64"),           DEC_ACTION(ENC_BASE64)},
365         {N_("/_View/Decode/_Uuencode"),         DEC_ACTION(ENC_X_UUENCODE)},
366
367 #undef DEC_SEPARATOR
368 #undef DEC_ACTION
369
370         {N_("/_View/---"),              NULL, NULL, 0, "<Separator>"},
371         {N_("/_View/Mess_age source"),  "<control>U", view_source_cb, 0, NULL},
372         {N_("/_View/Show all _headers"),"<control>H", show_all_header_cb, 0, "<ToggleItem>"},
373         {N_("/_View/Quotes"),                   NULL, NULL, 0, "<Branch>"},
374         {N_("/_View/Quotes/_Fold all"),         "<control><shift>Q", msg_hide_quotes_cb, 1, "<ToggleItem>"},
375         {N_("/_View/Quotes/Fold from level _2"),NULL, msg_hide_quotes_cb, 2, "<ToggleItem>"},
376         {N_("/_View/Quotes/Fold from level _3"),NULL, msg_hide_quotes_cb, 3, "<ToggleItem>"},
377
378         {N_("/_Message"),               NULL, NULL, 0, "<Branch>"},
379         {N_("/_Message/Compose _new message"),
380                                         "<control>M", compose_cb, 0, NULL},
381         {N_("/_Message/---"),           NULL, NULL, 0, "<Separator>"},
382         {N_("/_Message/_Reply"),        "<control>R", reply_cb, COMPOSE_REPLY, NULL},
383         {N_("/_Message/Repl_y to/_all"),
384                                         "<control><shift>R", reply_cb, COMPOSE_REPLY_TO_ALL, NULL},
385         {N_("/_Message/Repl_y to/_sender"),
386                                         NULL, reply_cb, COMPOSE_REPLY_TO_SENDER, NULL},
387         {N_("/_Message/Repl_y to/mailing _list"),
388                                         "<control>L", reply_cb, COMPOSE_REPLY_TO_LIST, NULL},
389         {N_("/_Message/---"),           NULL, NULL, 0, "<Separator>"},
390         {N_("/_Message/_Forward"),      "<control><alt>F", reply_cb, COMPOSE_FORWARD_INLINE, NULL},
391         {N_("/_Message/For_ward as attachment"),
392                                         NULL, reply_cb, COMPOSE_FORWARD_AS_ATTACH, NULL},
393         {N_("/_Message/Redirec_t"),     NULL, reply_cb, COMPOSE_REDIRECT, NULL},
394
395         {N_("/_Tools"),                 NULL, NULL, 0, "<Branch>"},
396         {N_("/_Tools/_Address book"),   "<control><shift>A", addressbook_open_cb, 0, NULL},
397         {N_("/_Tools/Add sender to address boo_k"),
398                                         NULL, add_address_cb, 0, NULL},
399         {N_("/_Tools/---"),             NULL, NULL, 0, "<Separator>"},
400         {N_("/_Tools/_Create filter rule"),
401                                         NULL, NULL, 0, "<Branch>"},
402         {N_("/_Tools/_Create filter rule/_Automatically"),
403                                         NULL, create_filter_cb, FILTER_BY_AUTO, NULL},
404         {N_("/_Tools/_Create filter rule/by _From"),
405                                         NULL, create_filter_cb, FILTER_BY_FROM, NULL},
406         {N_("/_Tools/_Create filter rule/by _To"),
407                                         NULL, create_filter_cb, FILTER_BY_TO, NULL},
408         {N_("/_Tools/_Create filter rule/by _Subject"),
409                                         NULL, create_filter_cb, FILTER_BY_SUBJECT, NULL},
410         {N_("/_Tools/Create processing rule"),
411                                         NULL, NULL, 0, "<Branch>"},
412         {N_("/_Tools/Create processing rule/_Automatically"),
413                                         NULL, create_processing_cb, FILTER_BY_AUTO, NULL},
414         {N_("/_Tools/Create processing rule/by _From"),
415                                         NULL, create_processing_cb, FILTER_BY_FROM, NULL},
416         {N_("/_Tools/Create processing rule/by _To"),
417                                         NULL, create_processing_cb, FILTER_BY_TO, NULL},
418         {N_("/_Tools/Create processing rule/by _Subject"),
419                                         NULL, create_processing_cb, FILTER_BY_SUBJECT, NULL},
420         {N_("/_Tools/---"),             NULL, NULL, 0, "<Separator>"},
421         {N_("/_Tools/List _URLs..."),   "<shift><control>U", open_urls_cb, 0, NULL},
422         {N_("/_Tools/---"),             NULL, NULL, 0, "<Separator>"},
423         {N_("/_Tools/Actio_ns"),        NULL, NULL, 0, "<Branch>"},
424
425         {N_("/_Help"),                  NULL, NULL, 0, "<Branch>"},
426         {N_("/_Help/_About"),           NULL, about_cb, 0, NULL}
427 };
428
429 MessageView *messageview_create(MainWindow *mainwin)
430 {
431         MessageView *messageview;
432         GtkWidget *vbox;
433         HeaderView *headerview;
434         MimeView *mimeview;
435         NoticeView *noticeview;
436
437         debug_print("Creating message view...\n");
438         messageview = g_new0(MessageView, 1);
439
440         headerview = headerview_create();
441
442         noticeview = noticeview_create(mainwin);
443
444         mimeview = mimeview_create(mainwin);
445         mimeview->textview = textview_create();
446         mimeview->textview->messageview = messageview;
447         mimeview->messageview = messageview;
448
449         vbox = gtk_vbox_new(FALSE, 0);
450         gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET_PTR(headerview),
451                            FALSE, FALSE, 0);
452         gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET_PTR(noticeview),
453                            FALSE, FALSE, 0);
454         gtk_box_pack_start(GTK_BOX(vbox),
455                            GTK_WIDGET_PTR(mimeview), TRUE, TRUE, 0);
456         gtk_widget_show(vbox);
457
458         messageview->vbox        = vbox;
459         messageview->new_window  = FALSE;
460         messageview->window      = NULL;
461         messageview->headerview  = headerview;
462         messageview->mimeview    = mimeview;
463         messageview->noticeview = noticeview;
464         messageview->mainwin    = mainwin;
465
466         messageview->statusbar     = NULL;
467         messageview->statusbar_cid = 0;
468
469         messageview->msginfo_update_callback_id =
470                 hooks_register_hook(MSGINFO_UPDATE_HOOKLIST, messageview_update_msg, (gpointer) messageview);
471
472         return messageview;
473 }
474
475 GList *messageview_get_msgview_list(void)
476 {
477         return msgview_list;
478 }
479
480 void messageview_update_actions_menu(MessageView *msgview)
481 {
482         GtkItemFactory *ifactory;
483
484         /* Messages opened in a new window do not have a menu bar */
485         if (msgview->menubar == NULL)
486                 return;
487         ifactory = gtk_item_factory_from_widget(msgview->menubar);
488         action_update_msgview_menu(ifactory, "/Tools/Actions", msgview);
489 }
490
491 static void messageview_add_toolbar(MessageView *msgview, GtkWidget *window) 
492 {
493         GtkWidget *handlebox;
494         GtkWidget *vbox;
495         GtkWidget *menubar;
496 #ifndef MAEMO
497         GtkWidget *statusbar = NULL;
498 #endif
499         guint n_menu_entries;
500
501         vbox = gtk_vbox_new(FALSE, 0);
502         gtk_widget_show(vbox);
503         gtk_container_add(GTK_CONTAINER(window), vbox); 
504
505         n_menu_entries = sizeof(msgview_entries) / sizeof(msgview_entries[0]);
506         menubar = menubar_create(window, msgview_entries,
507                                  n_menu_entries, "<MessageView>", msgview);
508         gtk_widget_show(menubar);
509         gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, TRUE, 0);
510
511         if (prefs_common.toolbar_detachable) {
512                 handlebox = gtk_handle_box_new();
513         } else {
514                 handlebox = gtk_hbox_new(FALSE, 0);
515         }
516         gtk_box_pack_start(GTK_BOX(vbox), handlebox, FALSE, FALSE, 0);
517         gtk_widget_realize(handlebox);
518 #ifdef MAEMO
519         msgview->toolbar = toolbar_create(TOOLBAR_MSGVIEW, window,
520                                           (gpointer)msgview);
521         msgview->statusbar = NULL;
522         msgview->statusbar_cid = 0;
523 #else
524         msgview->toolbar = toolbar_create(TOOLBAR_MSGVIEW, handlebox,
525                                           (gpointer)msgview);
526         statusbar = gtk_statusbar_new();
527         gtk_widget_show(statusbar);
528         gtk_box_pack_end(GTK_BOX(vbox), statusbar, FALSE, FALSE, 0);
529         msgview->statusbar = statusbar;
530         msgview->statusbar_cid = gtk_statusbar_get_context_id
531                 (GTK_STATUSBAR(statusbar), "Message View");
532 #endif
533
534
535         msgview->handlebox = handlebox;
536         msgview->menubar   = menubar;
537
538         gtk_container_add(GTK_CONTAINER(vbox),
539                           GTK_WIDGET_PTR(msgview));
540
541         messageview_update_actions_menu(msgview);
542
543         msgview_list = g_list_append(msgview_list, msgview);
544 }
545
546 static MessageView *messageview_create_with_new_window_visible(MainWindow *mainwin, gboolean show)
547 {
548         MessageView *msgview;
549         GtkWidget *window;
550         static GdkGeometry geometry;
551
552         window = gtkut_window_new(GTK_WINDOW_TOPLEVEL, "messageview");
553         gtk_window_set_title(GTK_WINDOW(window), _("Claws Mail - Message View"));
554         gtk_window_set_resizable(GTK_WINDOW(window), TRUE);
555
556         if (!geometry.min_height) {
557                 geometry.min_width = 320;
558                 geometry.min_height = 200;
559         }
560         gtk_window_set_geometry_hints(GTK_WINDOW(window), NULL, &geometry,
561                                       GDK_HINT_MIN_SIZE);
562
563         gtk_widget_set_size_request(window, prefs_common.msgwin_width,
564                                     prefs_common.msgwin_height);
565
566         msgview = messageview_create(mainwin);
567
568         g_signal_connect(G_OBJECT(window), "size_allocate",
569                          G_CALLBACK(messageview_size_allocate_cb),
570                          msgview);
571         g_signal_connect(G_OBJECT(window), "delete_event",
572                          G_CALLBACK(messageview_delete_cb), msgview);
573 #ifdef MAEMO
574         maemo_connect_key_press_to_mainwindow(GTK_WINDOW(window));
575 #else
576         g_signal_connect(G_OBJECT(window), "key_press_event",
577                          G_CALLBACK(key_pressed), msgview);
578 #endif
579         messageview_add_toolbar(msgview, window);
580
581         if (show) {
582                 gtk_widget_grab_focus(msgview->mimeview->textview->text);
583                 gtk_widget_show(window);
584         } else {
585                 gtk_widget_realize(window);
586         }
587
588         msgview->new_window = TRUE;
589         msgview->window = window;
590         msgview->visible = TRUE;
591
592         toolbar_set_style(msgview->toolbar->toolbar, msgview->handlebox, 
593                           prefs_common.toolbar_style);
594         messageview_init(msgview);
595
596         return msgview;
597 }
598
599 MessageView *messageview_create_with_new_window(MainWindow *mainwin)
600 {
601         return messageview_create_with_new_window_visible(mainwin, TRUE);
602 }
603 void messageview_init(MessageView *messageview)
604 {
605         headerview_init(messageview->headerview);
606         mimeview_init(messageview->mimeview);
607         /*messageview_set_font(messageview);*/
608
609         noticeview_hide(messageview->noticeview);
610 }
611
612 static void notification_convert_header(gchar *dest, gint len, 
613                                         const gchar *src_,
614                                         gint header_len)
615 {
616         char *src;
617
618         g_return_if_fail(src_ != NULL);
619         g_return_if_fail(dest != NULL);
620
621         if (len < 1) return;
622
623         Xstrndup_a(src, src_, len, return);
624
625         remove_return(src);
626
627         if (is_ascii_str(src)) {
628                 strncpy2(dest, src, len);
629                 dest[len - 1] = '\0';
630                 return;
631         } else
632                 conv_encode_header(dest, len, src, header_len, FALSE);
633 }
634
635 static gint disposition_notification_send(MsgInfo *msginfo)
636 {
637         gchar buf[BUFFSIZE];
638         gchar tmp[MAXPATHLEN + 1];
639         FILE *fp;
640         GList *ac_list;
641         PrefsAccount *account = NULL;
642         gint ok;
643         gchar *to;
644         FolderItem *queue, *outbox;
645         gint num;
646         gchar *path;
647         gchar *addr;
648         gchar *addrp;
649         gchar *foo = NULL;
650         gboolean queued_removed = FALSE;
651         gchar *boundary = NULL;
652         gchar *date = NULL;
653         gchar *orig_to = NULL;
654         gchar *enc_sub = NULL;
655
656         if (!msginfo->extradata)
657                 return -1;
658         if (!msginfo->extradata->returnreceiptto && 
659             !msginfo->extradata->dispositionnotificationto) 
660                 return -1;
661
662         /* RFC2298: Test for Return-Path */
663         if (msginfo->extradata->dispositionnotificationto)
664                 to = msginfo->extradata->dispositionnotificationto;
665         else
666                 to = msginfo->extradata->returnreceiptto;
667
668         ok = procheader_get_header_from_msginfo(msginfo, buf, sizeof(buf),
669                                 "Return-Path:");
670         if (ok == 0) {
671                 gchar *to_addr = g_strdup(to);
672                 extract_address(to_addr);
673                 extract_address(buf);
674                 ok = strcasecmp(to_addr, buf);
675                 g_free(to_addr);
676         } else {
677                 strncpy(buf, _("<No Return-Path found>"), 
678                                 sizeof(buf));
679         }
680         
681         if (ok != 0) {
682                 AlertValue val;
683                 gchar *message;
684                 message = g_markup_printf_escaped(
685                   _("The notification address to which the return receipt is\n"
686                     "to be sent does not correspond to the return path:\n"
687                     "Notification address: %s\n"
688                     "Return path: %s\n"
689                     "It is advised to not to send the return receipt."),
690                   to, buf);
691                 val = alertpanel_full(_("Warning"), message,
692                                 _("_Don't Send"), _("_Send"), NULL, FALSE,
693                                 NULL, ALERT_WARNING, G_ALERTDEFAULT);
694                 g_free(message);                                
695                 if (val != G_ALERTALTERNATE)
696                         return -1;
697         }
698
699         ac_list = account_find_all_from_address(NULL, msginfo->to);
700         ac_list = account_find_all_from_address(ac_list, msginfo->cc);
701
702         if (ac_list == NULL) {
703                 AlertValue val = 
704                 alertpanel_full(_("Warning"),
705                   _("This message is asking for a return receipt notification\n"
706                     "but according to its 'To:' and 'CC:' headers it was not\n"
707                     "officially addressed to you.\n"
708                     "It is advised to not to send the return receipt."),
709                   _("_Don't Send"), _("_Send"), NULL, FALSE,
710                   NULL, ALERT_WARNING, G_ALERTDEFAULT);
711                 if (val != G_ALERTALTERNATE)
712                         return -1;
713         }
714
715         if (g_list_length(ac_list) > 1) {
716                 if ((account = select_account_from_list(ac_list)) == NULL)
717                         return -1;
718         }
719         else if (ac_list != NULL)
720                 account = (PrefsAccount *) ac_list->data;
721         g_list_free(ac_list);
722
723         if (account == NULL)
724                 account = account_get_default();
725         if (!account || account->protocol == A_NNTP) {
726                 alertpanel_error(_("Account for sending mail is not specified.\n"
727                                    "Please select a mail account before sending."));
728                 return -1;
729         }
730
731         /* write to temporary file */
732         g_snprintf(tmp, sizeof(tmp), "%s%ctmpmsg%p",
733                    get_rc_dir(), G_DIR_SEPARATOR, msginfo);
734
735         if ((fp = g_fopen(tmp, "wb")) == NULL) {
736                 FILE_OP_ERROR(tmp, "fopen");
737                 return -1;
738         }
739
740         /* chmod for security */
741         if (change_file_mode_rw(fp, tmp) < 0) {
742                 FILE_OP_ERROR(tmp, "chmod");
743                 g_warning("can't change file mode\n");
744         }
745         
746         addr = g_strdup(to);
747         
748         extract_address(addr);
749         addrp = addr;
750         
751         /* write queue headers */
752         if (fprintf(fp, "AF:\n"
753                     "NF:0\n"
754                     "PS:10\n"
755                     "SRH:1\n"
756                     "SFN:\n"
757                     "DSR:\n"
758                     "MID:\n"
759                     "CFG:\n"
760                     "PT:0\n"
761                     "S:%s\n"
762                     "RQ:\n"
763                     "SSV:%s\n"
764                     "SSH:\n"
765                     "R:<%s>\n", 
766                     account->address,
767                     account->smtp_server?account->smtp_server:"",
768                     addrp) < 0) {
769                 g_free(addrp);
770                 fclose(fp);
771                 g_unlink(tmp);
772                 return -1;
773         }
774
775         g_free(addrp);
776         
777         /* check whether we need to save the message */
778         outbox = account_get_special_folder(account, F_OUTBOX); 
779         if (folder_get_default_outbox() == outbox && !prefs_common.savemsg)
780                 outbox = NULL;
781         if (outbox) {
782                 path = folder_item_get_identifier(outbox);
783                 if (fprintf(fp, "SCF:%s\n", path) < 0) {
784                         g_free(path);
785                         fclose(fp);
786                         g_unlink(tmp);
787                         return -1;
788                 }
789                 g_free(path);
790         }               
791
792         if (fprintf(fp, "X-Claws-End-Special-Headers: 1\n") < 0) {
793                 fclose(fp);
794                 g_unlink(tmp);
795                 return -1;
796         }
797
798         /* Date */
799         get_rfc822_date(buf, sizeof(buf));
800         if (fprintf(fp, "Date: %s\n", buf) < 0) {
801                 fclose(fp);
802                 g_unlink(tmp);
803                 return -1;
804         }
805
806         /* From */
807         if (account->name && *account->name) {
808                 notification_convert_header
809                         (buf, sizeof(buf), account->name,
810                          strlen("From: "));
811                 if (fprintf(fp, "From: %s <%s>\n", buf, account->address) < 0) {
812                         fclose(fp);
813                         g_unlink(tmp);
814                         return -1;
815                 }
816         } else
817                 if (fprintf(fp, "From: %s\n", account->address) < 0) {
818                         fclose(fp);
819                         g_unlink(tmp);
820                         return -1;
821                 }
822
823
824         if (fprintf(fp, "To: %s\n", to) < 0) {
825                 fclose(fp);
826                 g_unlink(tmp);
827                 return -1;
828         }
829
830         /* Subject */
831         notification_convert_header(buf, sizeof(buf), msginfo->subject,
832                                     strlen("Subject: "));
833         if (fprintf(fp, "Subject: Disposition notification: %s\n", buf) < 0) {
834                 fclose(fp);
835                 g_unlink(tmp);
836                 return -1;
837         }
838
839         /* Message ID */
840         if (account->set_domain && account->domain) {
841                 g_snprintf(buf, sizeof(buf), "%s", account->domain); 
842         } else if (!strncmp(get_domain_name(), "localhost", strlen("localhost"))) {
843                 g_snprintf(buf, sizeof(buf), "%s", 
844                         strchr(account->address, '@') ?
845                                 strchr(account->address, '@')+1 :
846                                 account->address);
847         } else {
848                 g_snprintf(buf, sizeof(buf), "%s", "");
849         }
850         
851         if (account->gen_msgid) {
852                 generate_msgid(buf, sizeof(buf));
853
854                 if (fprintf(fp, "Message-ID: <%s>\n", buf) < 0) {
855                         fclose(fp);
856                         g_unlink(tmp);
857                         return -1;
858                 }
859         }
860
861         boundary = generate_mime_boundary("DN");
862         get_rfc822_date(buf, sizeof(buf));
863         date = g_strdup(buf);
864         if (msginfo->to) {
865                 orig_to = g_strdup(msginfo->to);
866                 extract_address(orig_to);
867         }
868         if (msginfo->subject) {
869                 enc_sub = g_malloc0(strlen(msginfo->subject)*8);
870                 qp_encode_line(enc_sub, (const guchar *)msginfo->subject);
871                 g_strstrip(enc_sub);
872         }
873         if (fprintf(fp, "MIME-Version: 1.0\n"
874                         "Content-Type: multipart/report; report-type=disposition-notification;\n"
875                         "  boundary=\"%s\"\n"
876                         "\n"
877                         "--%s\n"
878                         "Content-Type: text/plain; charset=UTF-8\n"
879                         "Content-Transfer-Encoding: quoted-printable\n"
880                         "\n"
881                         "The message sent on: %s\n"
882                         "To: %s\n"
883                         "With subject: \"%s\"\n"
884                         "has been displayed at %s.\n"
885                         "\n"
886                         "There is no guarantee that the message has been read or understood.\n"
887                         "\n"
888                         "--%s\n"
889                         "Content-Type: message/disposition-notification\n"
890                         "\n"
891                         "Reporting-UA: %s\n"
892                         "Original-Recipient: rfc822;%s\n"
893                         "Final-Recipient: rfc822;%s\n"
894                         "Original-Message-ID: <%s>\n"
895                         "Disposition: manual-action/MDN-sent-manually; displayed\n"
896                         "\n"
897                         "--%s\n"
898                         "Content-Type: application/octet-stream\n"
899                         "Reporting-UA: %s\n"
900                         "Original-Recipient: rfc822;%s\n"
901                         "Final-Recipient: rfc822;%s\n"
902                         "Original-Message-ID: <%s>\n"
903                         "Disposition: manual-action/MDN-sent-manually; displayed\n"
904                         "\n"
905                         "--%s--\n", 
906                         boundary, 
907                         boundary,
908                         msginfo->date, 
909                         orig_to?orig_to:"No To:",
910                         enc_sub?enc_sub:"No subject",
911                         date,
912                         boundary,
913                         PROG_VERSION,
914                         orig_to?orig_to:"No To:",
915                         account->address,
916                         msginfo->msgid?msginfo->msgid:"NO MESSAGE ID",
917                         boundary,
918                         PROG_VERSION,
919                         orig_to?orig_to:"No To:",
920                         account->address,
921                         msginfo->msgid?msginfo->msgid:"NO MESSAGE ID",
922                         boundary) < 0) {
923                 fclose(fp);
924                 g_unlink(tmp);
925                 g_free(boundary);
926                 return -1;
927         }
928
929         g_free(enc_sub);
930         g_free(orig_to);
931         g_free(date);
932         g_free(boundary);
933
934         if (fclose(fp) == EOF) {
935                 FILE_OP_ERROR(tmp, "fclose");
936                 g_unlink(tmp);
937                 return -1;
938         }
939
940         /* put it in queue */
941         queue = account_get_special_folder(account, F_QUEUE);
942         if (!queue) queue = folder_get_default_queue();
943         if (!queue) {
944                 g_warning("can't find queue folder\n");
945                 g_unlink(tmp);
946                 return -1;
947         }
948         folder_item_scan(queue);
949         if ((num = folder_item_add_msg(queue, tmp, NULL, TRUE)) < 0) {
950                 g_warning("can't queue the message\n");
951                 g_unlink(tmp);
952                 return -1;
953         }
954                 
955         if (prefs_common.work_offline && 
956             !inc_offline_should_override(TRUE,
957                 _("Claws Mail needs network access in order "
958                   "to send this email.")))
959                 return 0;
960
961         /* send it */
962         path = folder_item_fetch_msg(queue, num);
963         ok = procmsg_send_message_queue(path, &foo, queue, num, &queued_removed);
964         g_free(path);
965         g_free(foo);
966         if (ok == 0 && !queued_removed)
967                 folder_item_remove_msg(queue, num);
968
969         return ok;
970 }
971
972 static gboolean find_encrypted_func(GNode *node, gpointer data)
973 {
974         MimeInfo *mimeinfo = (MimeInfo *) node->data;
975         MimeInfo **encinfo = (MimeInfo **) data;
976         
977         if (privacy_mimeinfo_is_encrypted(mimeinfo)) {
978                 *encinfo = mimeinfo;
979                 return TRUE;
980         }
981         
982         return FALSE;
983 }
984
985 static MimeInfo *find_encrypted_part(MimeInfo *rootinfo)
986 {
987         MimeInfo *encinfo = NULL;
988
989         g_node_traverse(rootinfo->node, G_IN_ORDER, G_TRAVERSE_ALL, -1,
990                 find_encrypted_func, &encinfo);
991         
992         return encinfo;
993 }
994
995 gint messageview_show(MessageView *messageview, MsgInfo *msginfo,
996                       gboolean all_headers)
997 {
998         gchar *file;
999         MimeInfo *mimeinfo, *encinfo;
1000         gchar *subject = NULL;
1001         g_return_val_if_fail(msginfo != NULL, -1);
1002
1003         if (messageview->mimeview->textview &&
1004             messageview->mimeview->textview->loading) {
1005                 messageview->mimeview->textview->stop_loading = TRUE;
1006                 return 0;
1007         }
1008
1009         if (messageview->toolbar)
1010                 toolbar_set_learn_button
1011                         (messageview->toolbar,
1012                          MSG_IS_SPAM(msginfo->flags)?LEARN_HAM:LEARN_SPAM);
1013         else
1014                 toolbar_set_learn_button
1015                         (messageview->mainwin->toolbar,
1016                          MSG_IS_SPAM(msginfo->flags)?LEARN_HAM:LEARN_SPAM);
1017
1018         if (messageview->toolbar) {
1019                 if (messageview->toolbar->learn_spam_btn)
1020                         gtk_widget_set_sensitive(
1021                                 messageview->toolbar->learn_spam_btn, 
1022                                 procmsg_spam_can_learn());
1023         }
1024         
1025         noticeview_hide(messageview->noticeview);
1026         mimeview_clear(messageview->mimeview);
1027         messageview->updating = TRUE;
1028
1029         if (msginfo->size > 1024*1024)
1030                 statuswindow_print_all(_("Fetching message (%s)..."),
1031                         to_human_readable(msginfo->size));
1032         
1033         file = procmsg_get_message_file_path(msginfo);
1034
1035         if (msginfo->size > 1024*1024)
1036                 statuswindow_pop_all();
1037
1038         if (!file) {
1039                 g_warning("can't get message file path.\n");
1040                 textview_show_error(messageview->mimeview->textview);
1041                 return -1;
1042         }
1043         
1044         if (!folder_has_parent_of_type(msginfo->folder, F_QUEUE) &&
1045             !folder_has_parent_of_type(msginfo->folder, F_DRAFT))
1046                 mimeinfo = procmime_scan_file(file);
1047         else
1048                 mimeinfo = procmime_scan_queue_file(file);
1049
1050         messageview->updating = FALSE;
1051         
1052         if (messageview->deferred_destroy) {
1053                 g_free(file);
1054                 messageview_destroy(messageview);
1055                 return 0;
1056         }
1057
1058         if (!mimeinfo) {
1059                 textview_show_error(messageview->mimeview->textview);
1060                 return -1;
1061         }
1062
1063         while ((encinfo = find_encrypted_part(mimeinfo)) != NULL) {
1064                 debug_print("decrypting message part\n");
1065                 if (privacy_mimeinfo_decrypt(encinfo) < 0) {
1066                         alertpanel_error(_("Couldn't decrypt: %s"),
1067                                 privacy_get_error());
1068                         break;
1069                 }
1070         }
1071                         
1072         if (messageview->msginfo != msginfo) {
1073                 procmsg_msginfo_free(messageview->msginfo);
1074                 messageview->msginfo = NULL;
1075                 messageview_set_menu_sensitive(messageview);
1076                 messageview->msginfo = 
1077                         procmsg_msginfo_get_full_info_from_file(msginfo, file);
1078                 if (!messageview->msginfo)
1079                         messageview->msginfo = procmsg_msginfo_copy(msginfo);
1080         } else {
1081                 messageview->msginfo = NULL;
1082                 messageview_set_menu_sensitive(messageview);
1083                 messageview->msginfo = msginfo;
1084         }
1085         headerview_show(messageview->headerview, messageview->msginfo);
1086
1087         messageview_set_position(messageview, 0);
1088
1089         textview_set_all_headers(messageview->mimeview->textview, 
1090                         messageview->all_headers);
1091
1092 #ifdef MAEMO
1093         maemo_window_full_screen_if_needed(GTK_WINDOW(messageview->window));
1094 #endif
1095         if (messageview->window) {
1096                 gtk_window_set_title(GTK_WINDOW(messageview->window), 
1097                                 _("Claws Mail - Message View"));
1098                 GTK_EVENTS_FLUSH();
1099         }
1100         mimeview_show_message(messageview->mimeview, mimeinfo, file);
1101         
1102 #ifndef MAEMO
1103         messageview_set_position(messageview, 0);
1104 #endif
1105
1106         if (messageview->window && msginfo->subject) {
1107                 subject = g_strdup(msginfo->subject);
1108                 if (!g_utf8_validate(subject, -1, NULL)) {
1109                         g_free(subject);
1110                         subject = g_malloc(strlen(msginfo->subject)*2 +1);
1111                         conv_localetodisp(subject, strlen(msginfo->subject)*2 +1, 
1112                                 msginfo->subject);
1113                 }
1114                 if (g_utf8_validate(subject, -1, NULL))
1115                         gtk_window_set_title(GTK_WINDOW(messageview->window), 
1116                                 subject);
1117                 g_free(subject);
1118         }
1119
1120         if (msginfo && msginfo->folder) {
1121                 msginfo->folder->last_seen = msginfo->msgnum;   
1122         }
1123
1124         main_create_mailing_list_menu(messageview->mainwin, messageview->msginfo);
1125
1126         if (messageview->msginfo && messageview->msginfo->extradata
1127             && messageview->msginfo->extradata->partial_recv)
1128                 partial_recv_show(messageview->noticeview, 
1129                                   messageview->msginfo);
1130         else if (messageview->msginfo && messageview->msginfo->extradata &&
1131             (messageview->msginfo->extradata->dispositionnotificationto || 
1132              messageview->msginfo->extradata->returnreceiptto) &&
1133             !MSG_IS_RETRCPT_SENT(messageview->msginfo->flags) &&
1134             !prefs_common.never_send_retrcpt)
1135                 return_receipt_show(messageview->noticeview, 
1136                                     messageview->msginfo);
1137
1138         mimeinfo = procmime_mimeinfo_next(mimeinfo);
1139         if (!all_headers && mimeinfo 
1140                         && (mimeinfo->type != MIMETYPE_TEXT || 
1141             strcasecmp(mimeinfo->subtype, "plain")) 
1142                         && (mimeinfo->type != MIMETYPE_MULTIPART || 
1143             strcasecmp(mimeinfo->subtype, "signed"))) {
1144                 if (strcasecmp(mimeinfo->subtype, "html")) {
1145                         mimeview_show_part(messageview->mimeview,mimeinfo);
1146                         goto done;
1147                 } else if (prefs_common.invoke_plugin_on_html) {
1148                         mimeview_select_mimepart_icon(messageview->mimeview, mimeinfo);
1149                         goto done;
1150                 }
1151         }
1152         if (!all_headers && mimeinfo &&
1153             mimeinfo->type == MIMETYPE_MULTIPART &&
1154             mimeview_has_viewer_for_content_type(messageview->mimeview, "text/calendar")) {
1155                 /* look for a calendar part or it looks really strange */
1156                 while (mimeinfo) {
1157                         if (mimeinfo->type == MIMETYPE_TEXT &&
1158                             !strcasecmp(mimeinfo->subtype, "calendar")) {
1159                                 mimeview_select_mimepart_icon(messageview->mimeview, mimeinfo);
1160                                 goto done;
1161                         }
1162                         mimeinfo = procmime_mimeinfo_next(mimeinfo);
1163                 }
1164         }
1165 done:
1166         g_free(file);
1167
1168         return 0;
1169 }
1170
1171 void messageview_reflect_prefs_pixmap_theme(void)
1172 {
1173         GList *cur;
1174         MessageView *msgview;
1175
1176         for (cur = msgview_list; cur != NULL; cur = cur->next) {
1177                 msgview = (MessageView*)cur->data;
1178                 toolbar_update(TOOLBAR_MSGVIEW, msgview);
1179                 mimeview_update(msgview->mimeview);
1180         }
1181 }
1182
1183 void messageview_clear(MessageView *messageview)
1184 {
1185         if (!messageview)
1186                 return;
1187         procmsg_msginfo_free(messageview->msginfo);
1188         messageview->msginfo = NULL;
1189         messageview->filtered = FALSE;
1190         mimeview_clear(messageview->mimeview);
1191         headerview_clear(messageview->headerview);
1192         noticeview_hide(messageview->noticeview);
1193 }
1194
1195 void messageview_destroy(MessageView *messageview)
1196 {
1197         debug_print("destroy messageview\n");
1198         messageview_list = g_list_remove(messageview_list, messageview);
1199
1200         if (messageview->mainwin->summaryview->messageview == messageview) {
1201                 messageview->mainwin->summaryview->displayed = NULL;
1202                 messageview->mainwin->summaryview->messageview = NULL;
1203         }
1204         if (messageview->mainwin->summaryview->ext_messageview == messageview) {
1205                 messageview->mainwin->summaryview->displayed = NULL;
1206                 messageview->mainwin->summaryview->ext_messageview = NULL;
1207         }
1208         if (!messageview->deferred_destroy) {
1209                 hooks_unregister_hook(MSGINFO_UPDATE_HOOKLIST,
1210                               messageview->msginfo_update_callback_id);
1211         }
1212
1213         if (messageview->updating) {
1214                 debug_print("uh oh, better not touch that now (fetching)\n");
1215                 messageview->deferred_destroy = TRUE;
1216                 gtk_widget_hide(messageview->window);
1217                 return;
1218         }
1219         
1220         if (messageview->mimeview->textview
1221         &&  messageview->mimeview->textview->loading) {
1222                 debug_print("uh oh, better not touch that now (loading text)\n");
1223                 messageview->deferred_destroy = TRUE;
1224                 messageview->mimeview->textview->stop_loading = TRUE;
1225                 gtk_widget_hide(messageview->window);
1226                 return;
1227         }
1228
1229         headerview_destroy(messageview->headerview);
1230         mimeview_destroy(messageview->mimeview);
1231         noticeview_destroy(messageview->noticeview);
1232
1233         procmsg_msginfo_free(messageview->msginfo);
1234         toolbar_clear_list(TOOLBAR_MSGVIEW);
1235         if (messageview->toolbar) {
1236                 toolbar_destroy(messageview->toolbar);
1237                 g_free(messageview->toolbar);
1238         }
1239         
1240         msgview_list = g_list_remove(msgview_list, messageview); 
1241
1242         if (messageview->window)
1243                 gtk_widget_destroy(messageview->window);
1244         g_free(messageview);
1245 }
1246
1247 void messageview_delete(MessageView *msgview)
1248 {
1249         MsgInfo *msginfo = NULL;
1250         FolderItem *trash = NULL;
1251         PrefsAccount *ac = NULL;
1252
1253         if (msgview->msginfo && msgview->mainwin && msgview->mainwin->summaryview)
1254                 msginfo = summary_get_selected_msg(msgview->mainwin->summaryview);
1255         
1256         /* need a procmsg_msginfo_equal() */
1257         if (msginfo && msgview->msginfo && 
1258             msginfo->msgnum == msgview->msginfo->msgnum && 
1259             msginfo->folder == msgview->msginfo->folder) {
1260                 summary_delete_trash(msgview->mainwin->summaryview);
1261         } else {                
1262                 msginfo = msgview->msginfo;
1263
1264                 g_return_if_fail(msginfo != NULL);
1265
1266                 /* to get the trash folder, we have to choose either
1267                  * the folder's or account's trash default - we prefer
1268                  * the one in the account prefs */
1269                 if (msginfo->folder) {
1270                         if (NULL != (ac = account_find_from_item(msginfo->folder)))
1271                                 trash = account_get_special_folder(ac, F_TRASH);
1272                         if (!trash && msginfo->folder->folder)  
1273                                 trash = msginfo->folder->folder->trash;
1274                         /* if still not found, use the default */
1275                         if (!trash) 
1276                                 trash = folder_get_default_trash();
1277                 }       
1278
1279                 g_return_if_fail(trash != NULL);
1280
1281                 if (prefs_common.immediate_exec)
1282                         /* TODO: Delete from trash */
1283                         folder_item_move_msg(trash, msginfo);
1284                 else {
1285                         procmsg_msginfo_set_to_folder(msginfo, trash);
1286                         procmsg_msginfo_set_flags(msginfo, MSG_DELETED, 0);
1287                         /* NOTE: does not update to next message in summaryview */
1288                 }
1289         }
1290 #ifdef MAEMO
1291         if (msgview->window && !prefs_common.always_show_msg) {
1292                 messageview_destroy(msgview);
1293         }
1294 #endif
1295 }
1296
1297 /* 
1298  * \brief update messageview with currently selected message in summaryview
1299  *        leave unchanged if summaryview is empty
1300  * \param pointer to MessageView
1301  */     
1302 static void messageview_update(MessageView *msgview, MsgInfo *old_msginfo)
1303 {
1304         SummaryView *summaryview = (SummaryView*)msgview->mainwin->summaryview;
1305
1306         g_return_if_fail(summaryview != NULL);
1307         
1308         if (summaryview->selected) {
1309                 MsgInfo *msginfo = summary_get_selected_msg(summaryview);
1310                 if (msginfo == NULL || msginfo == old_msginfo)
1311                         return;
1312
1313                 messageview_show(msgview, msginfo, 
1314                                  msgview->all_headers);
1315         } 
1316 }
1317
1318 TextView *messageview_get_current_textview(MessageView *messageview)
1319 {
1320         TextView *text = NULL;
1321
1322         text = messageview->mimeview->textview;
1323
1324         return text;
1325 }
1326
1327 MimeInfo *messageview_get_selected_mime_part(MessageView *messageview)
1328 {
1329         return mimeview_get_selected_part(messageview->mimeview);
1330 }
1331
1332 void messageview_copy_clipboard(MessageView *messageview)
1333 {
1334         gchar *text = messageview_get_selection(messageview);
1335         if (text) {
1336                 gtk_clipboard_set_text(
1337                         gtk_clipboard_get(GDK_SELECTION_CLIPBOARD),
1338                         text, -1);
1339         }
1340         g_free(text);
1341 }
1342
1343 void messageview_select_all(MessageView *messageview)
1344 {
1345         TextView *text;
1346
1347         text = messageview_get_current_textview(messageview);
1348         if (text) {
1349                 GtkTextView *textview = GTK_TEXT_VIEW(text->text);
1350                 GtkTextBuffer *buffer;
1351                 GtkTextIter start, end;
1352
1353                 buffer = gtk_text_view_get_buffer(textview);
1354                 gtk_text_buffer_get_bounds(buffer, &start, &end);
1355                 gtk_text_buffer_select_range(buffer, &start, &end);
1356         }
1357 }
1358
1359 void messageview_set_position(MessageView *messageview, gint pos)
1360 {
1361         TextView *text;
1362
1363         text = messageview_get_current_textview(messageview);
1364         if (text)
1365                 textview_set_position(text, pos);
1366 }
1367
1368 gboolean messageview_search_string(MessageView *messageview, const gchar *str,
1369                                    gboolean case_sens)
1370 {
1371         TextView *text;
1372
1373         if (messageview->mimeview->type == MIMEVIEW_VIEWER) {
1374                 MimeViewer *viewer = messageview->mimeview->mimeviewer;
1375                 if (viewer && viewer->text_search) {
1376                         return viewer->text_search(viewer, FALSE, str, case_sens);
1377                 }
1378         }
1379
1380         text = messageview_get_current_textview(messageview);
1381         if (text)
1382                 return textview_search_string(text, str, case_sens);
1383         return FALSE;
1384 }
1385
1386 gboolean messageview_search_string_backward(MessageView *messageview,
1387                                             const gchar *str,
1388                                             gboolean case_sens)
1389 {
1390         TextView *text;
1391
1392         if (messageview->mimeview->type == MIMEVIEW_VIEWER) {
1393                 MimeViewer *viewer = messageview->mimeview->mimeviewer;
1394                 if (viewer && viewer->text_search) {
1395                         return viewer->text_search(viewer, TRUE, str, case_sens);
1396                 }
1397         }
1398
1399         text = messageview_get_current_textview(messageview);
1400         if (text)       
1401                 return textview_search_string_backward(text,
1402                                                        str, case_sens);
1403         return FALSE;
1404 }
1405
1406 gboolean messageview_is_visible(MessageView *messageview)
1407 {
1408         if (messageview == NULL)
1409                 return FALSE;
1410         return messageview->visible;
1411 }
1412
1413 static void messageview_save_as(MessageView *messageview)
1414 {
1415         gchar *filename = NULL;
1416         MsgInfo *msginfo;
1417         gchar *src, *dest, *tmp;
1418
1419         if (!messageview->msginfo) return;
1420         msginfo = messageview->msginfo;
1421
1422         if (msginfo->subject) {
1423                 Xstrdup_a(filename, msginfo->subject, return);
1424                 subst_for_filename(filename);
1425         }
1426         if (filename && !g_utf8_validate(filename, -1, NULL)) {
1427                 gchar *oldstr = filename;
1428                 filename = conv_codeset_strdup(filename,
1429                                                conv_get_locale_charset_str(),
1430                                                CS_UTF_8);
1431                 if (!filename) {
1432                         g_warning("messageview_save_as(): failed to convert character set.");
1433                         filename = g_strdup(oldstr);
1434                 }
1435                 dest = filesel_select_file_save(_("Save as"), filename);
1436                 g_free(filename);
1437         } else
1438                 dest = filesel_select_file_save(_("Save as"), filename);
1439         if (!dest) return;
1440         if (is_file_exist(dest)) {
1441                 AlertValue aval;
1442
1443                 aval = alertpanel(_("Overwrite"),
1444                                   _("Overwrite existing file?"),
1445                                   GTK_STOCK_CANCEL, GTK_STOCK_OK, NULL);
1446                 if (G_ALERTALTERNATE != aval) return;
1447         }
1448
1449         src = procmsg_get_message_file(msginfo);
1450         if (copy_file(src, dest, TRUE) < 0) {
1451                 tmp =  g_path_get_basename(dest);
1452                 alertpanel_error(_("Couldn't save the file '%s'."), tmp);
1453                 g_free(tmp);
1454         }
1455         g_free(dest);
1456         g_free(src);
1457 }
1458
1459 static gint messageview_delete_cb(GtkWidget *widget, GdkEventAny *event,
1460                                   MessageView *messageview)
1461 {
1462         messageview_destroy(messageview);
1463         return TRUE;
1464 }
1465
1466 static void messageview_size_allocate_cb(GtkWidget *widget,
1467                                          GtkAllocation *allocation)
1468 {
1469         g_return_if_fail(allocation != NULL);
1470
1471         prefs_common.msgwin_width  = allocation->width;
1472         prefs_common.msgwin_height = allocation->height;
1473 }
1474 #ifndef MAEMO
1475 static gboolean key_pressed(GtkWidget *widget, GdkEventKey *event,
1476                         MessageView *messageview)
1477 {
1478         if (event && event->keyval == GDK_Escape && messageview->window) {
1479                 messageview_destroy(messageview);
1480                 return TRUE;
1481         }
1482
1483         if ((event->state & (GDK_MOD1_MASK|GDK_CONTROL_MASK|GDK_SHIFT_MASK)) != 0)
1484                 return FALSE;
1485
1486         g_signal_stop_emission_by_name(G_OBJECT(widget),
1487                                         "key_press_event");
1488         mimeview_pass_key_press_event(messageview->mimeview, event);
1489         return FALSE;
1490 }
1491 #endif
1492 static void return_receipt_show(NoticeView *noticeview, MsgInfo *msginfo)
1493 {
1494         gchar *addr = NULL;
1495         gboolean from_me = FALSE;
1496         if (msginfo->folder 
1497                 && (folder_has_parent_of_type(msginfo->folder, F_QUEUE)
1498                  || folder_has_parent_of_type(msginfo->folder, F_DRAFT)))
1499                 return;
1500
1501         addr = g_strdup(msginfo->from);
1502         if (addr) {
1503                 extract_address(addr);
1504                 if (account_find_from_address(addr, FALSE)) {
1505                         from_me = TRUE;
1506                 }
1507                 g_free(addr);
1508         }
1509
1510         if (from_me) {
1511                 noticeview_set_icon(noticeview, STOCK_PIXMAP_NOTICE_WARN);
1512                 if (MSG_IS_RETRCPT_GOT(msginfo->flags)) {
1513                         noticeview_set_text(noticeview, _("You got a return receipt in this message : "
1514                                                           "it has been displayed by the recipient."));
1515                 } else {
1516                         noticeview_set_text(noticeview, _("You asked for a return receipt in this message."));
1517                 }
1518                 noticeview_set_button_text(noticeview, NULL);
1519                 noticeview_set_button_press_callback(noticeview, NULL, NULL);
1520         } else {
1521                 noticeview_set_icon(noticeview, STOCK_PIXMAP_NOTICE_WARN);
1522                 noticeview_set_text(noticeview, _("This message asks for a return receipt."));
1523                 noticeview_set_button_text(noticeview, _("Send receipt"));
1524                 noticeview_set_button_press_callback(noticeview,
1525                                                      G_CALLBACK(return_receipt_send_clicked),
1526                                                      (gpointer) msginfo);
1527         }
1528         noticeview_show(noticeview);
1529 }
1530
1531 static void return_receipt_send_clicked(NoticeView *noticeview, MsgInfo *msginfo)
1532 {
1533         MsgInfo *tmpmsginfo;
1534         gchar *file;
1535
1536         file = procmsg_get_message_file_path(msginfo);
1537         if (!file) {
1538                 g_warning("can't get message file path.\n");
1539                 return;
1540         }
1541
1542         tmpmsginfo = procheader_parse_file(file, msginfo->flags, TRUE, TRUE);
1543         tmpmsginfo->folder = msginfo->folder;
1544         tmpmsginfo->msgnum = msginfo->msgnum;
1545
1546         if (disposition_notification_send(tmpmsginfo) >= 0) {
1547                 procmsg_msginfo_set_flags(msginfo, MSG_RETRCPT_SENT, 0);
1548                 noticeview_hide(noticeview);
1549         }               
1550
1551         procmsg_msginfo_free(tmpmsginfo);
1552         g_free(file);
1553 }
1554
1555 static void partial_recv_show(NoticeView *noticeview, MsgInfo *msginfo)
1556 {
1557         gchar *text = NULL;
1558         gchar *button1 = NULL;
1559         gchar *button2 = NULL;
1560         void  *button1_cb = NULL;
1561         void  *button2_cb = NULL;
1562
1563         if (!msginfo->extradata)
1564                 return;
1565         if (!partial_msg_in_uidl_list(msginfo)) {
1566                 text = g_strdup_printf(_("This message has been partially "
1567                                 "retrieved,\nand has been deleted from the "
1568                                 "server."));
1569         } else {
1570                 switch (msginfo->planned_download) {
1571                 case POP3_PARTIAL_DLOAD_UNKN:
1572                         text = g_strdup_printf(_("This message has been "
1573                                         "partially retrieved;\nit is %s."),
1574                                         to_human_readable(
1575                                                 (off_t)(msginfo->total_size)));
1576                         button1 = _("Mark for download");
1577                         button2 = _("Mark for deletion");
1578                         button1_cb = partial_recv_dload_clicked;
1579                         button2_cb = partial_recv_del_clicked;
1580                         break;
1581                 case POP3_PARTIAL_DLOAD_DLOAD:
1582                         text = g_strdup_printf(_("This message has been "
1583                                         "partially retrieved;\nit is %s and "
1584                                         "will be downloaded."),
1585                                         to_human_readable(
1586                                                 (off_t)(msginfo->total_size)));
1587                         button1 = _("Unmark");
1588                         button1_cb = partial_recv_unmark_clicked;
1589                         button2 = _("Mark for deletion");
1590                         button2_cb = partial_recv_del_clicked;
1591                         break;
1592                 case POP3_PARTIAL_DLOAD_DELE:
1593                         text = g_strdup_printf(_("This message has been "
1594                                         "partially retrieved;\nit is %s and "
1595                                         "will be deleted."),
1596                                         to_human_readable(
1597                                                 (off_t)(msginfo->total_size)));
1598                         button1 = _("Mark for download");
1599                         button1_cb = partial_recv_dload_clicked;
1600                         button2 = _("Unmark");
1601                         button2_cb = partial_recv_unmark_clicked;
1602                         break;
1603                 default:
1604                         return;
1605                 }
1606         }
1607         
1608         noticeview_set_icon(noticeview, STOCK_PIXMAP_NOTICE_WARN);
1609         noticeview_set_text(noticeview, text);
1610         g_free(text);
1611         noticeview_set_button_text(noticeview, button1);
1612         noticeview_set_button_press_callback(noticeview,
1613                      G_CALLBACK(button1_cb), (gpointer) msginfo);
1614
1615         noticeview_set_2ndbutton_text(noticeview, button2);
1616         noticeview_set_2ndbutton_press_callback(noticeview,
1617                      G_CALLBACK(button2_cb), (gpointer) msginfo);
1618
1619         noticeview_show(noticeview);
1620 }
1621
1622 static void partial_recv_dload_clicked(NoticeView *noticeview, 
1623                                        MsgInfo *msginfo)
1624 {
1625         if (partial_mark_for_download(msginfo) == 0) {
1626                 partial_recv_show(noticeview, msginfo);
1627         }
1628 }
1629
1630 static void partial_recv_del_clicked(NoticeView *noticeview, 
1631                                        MsgInfo *msginfo)
1632 {
1633         if (partial_mark_for_delete(msginfo) == 0) {
1634                 partial_recv_show(noticeview, msginfo);
1635         }
1636 }
1637
1638 static void partial_recv_unmark_clicked(NoticeView *noticeview, 
1639                                        MsgInfo *msginfo)
1640 {
1641         if (partial_unmark(msginfo) == 0) {
1642                 partial_recv_show(noticeview, msginfo);
1643         }
1644 }
1645
1646 static void select_account_cb(GtkWidget *w, gpointer data)
1647 {
1648         *(gint*)data = combobox_get_active_data(GTK_COMBO_BOX(w));
1649 }
1650
1651 static PrefsAccount *select_account_from_list(GList *ac_list)
1652 {
1653         GtkWidget *optmenu;
1654         gint account_id;
1655
1656         g_return_val_if_fail(ac_list != NULL, NULL);
1657         g_return_val_if_fail(ac_list->data != NULL, NULL);
1658         
1659         optmenu = gtkut_account_menu_new(ac_list,
1660                         G_CALLBACK(select_account_cb),
1661                         &account_id);
1662         if (!optmenu)
1663                 return NULL;
1664         account_id = ((PrefsAccount *) ac_list->data)->account_id;
1665         if (alertpanel_with_widget(
1666                                 _("Return Receipt Notification"),
1667                                 _("The message was sent to several of your "
1668                                   "accounts.\n"
1669                                   "Please choose which account do you want to "
1670                                   "use for sending the receipt notification:"),
1671                                 _("_Cancel"), _("_Send Notification"), NULL,
1672                                 FALSE, G_ALERTDEFAULT, optmenu) != G_ALERTALTERNATE)
1673                 return NULL;
1674         return account_find_from_id(account_id);
1675 }
1676
1677 /* 
1678  * \brief return selected messageview text, when nothing is 
1679  *        selected and message was filtered, return complete text
1680  *
1681  * \param  pointer to Messageview 
1682  *
1683  * \return pointer to text (needs to be free'd by calling func)
1684  */
1685 gchar *messageview_get_selection(MessageView *msgview)
1686 {
1687         TextView *textview;
1688         gchar *text = NULL;
1689         GtkTextView *edit = NULL;
1690         GtkTextBuffer *textbuf;
1691         gint body_pos = 0;
1692         
1693         g_return_val_if_fail(msgview != NULL, NULL);
1694
1695         if (msgview->mimeview->type == MIMEVIEW_VIEWER) {
1696                 MimeViewer *viewer = msgview->mimeview->mimeviewer;
1697                 if (viewer && viewer->get_selection) {
1698                         text = viewer->get_selection(viewer);
1699                         if (text)
1700                                 return text;
1701                 }
1702         }
1703
1704         textview = messageview_get_current_textview(msgview);
1705         g_return_val_if_fail(textview != NULL, NULL);
1706
1707         edit = GTK_TEXT_VIEW(textview->text);
1708         g_return_val_if_fail(edit != NULL, NULL);
1709         body_pos = textview->body_pos;
1710
1711         textbuf = gtk_text_view_get_buffer(edit);
1712
1713         if (gtk_text_buffer_get_selection_bounds(textbuf, NULL, NULL))
1714                 return gtkut_text_view_get_selection(edit);
1715         else if (msgview->filtered) {
1716                 GtkTextIter start_iter, end_iter;
1717                 gtk_text_buffer_get_iter_at_offset(textbuf, &start_iter, body_pos);
1718                 gtk_text_buffer_get_end_iter(textbuf, &end_iter);
1719                 gtk_text_buffer_get_text(textbuf, &start_iter, &end_iter, FALSE);
1720         } else
1721                 text = NULL;
1722
1723         return text;
1724 }
1725
1726 static void save_as_cb(gpointer data, guint action, GtkWidget *widget)
1727 {
1728         MessageView *messageview = (MessageView *)data;
1729         messageview_save_as(messageview);
1730 }
1731
1732 #if defined(USE_GNOMEPRINT) || GTK_CHECK_VERSION(2,10,0)
1733 static void print_mimeview(MimeView *mimeview, gint sel_start, gint sel_end, gint partnum) 
1734 {
1735 #if !defined(USE_GNOMEPRINT) && GTK_CHECK_VERSION(2,10,0)
1736         MainWindow *mainwin;
1737 #endif
1738         if (!mimeview 
1739         ||  !mimeview->textview
1740         ||  !mimeview->textview->text)
1741                 alertpanel_warning(_("Cannot print: the message doesn't "
1742                                      "contain text."));
1743         else {
1744                 gtk_widget_realize(mimeview->textview->text);
1745                 if (partnum > 0) {
1746                         mimeview_select_part_num(mimeview, partnum);
1747                 }
1748                 if (mimeview->type == MIMEVIEW_VIEWER) {
1749                         MimeViewer *viewer = mimeview->mimeviewer;
1750                         if (viewer && viewer->print) {
1751                                 viewer->print(viewer);
1752                                 return;
1753                         }
1754                 }
1755                 if (sel_start != -1 && sel_end != -1) {
1756                         GtkTextIter start, end;
1757                         GtkTextView *text = GTK_TEXT_VIEW(mimeview->textview->text);
1758                         GtkTextBuffer *buffer = gtk_text_view_get_buffer(text);
1759
1760                         gtk_text_buffer_get_iter_at_offset(buffer, &start, sel_start);
1761                         gtk_text_buffer_get_iter_at_offset(buffer, &end, sel_end);
1762                         gtk_text_buffer_select_range(buffer, &start, &end);
1763                 }
1764 #if defined(USE_GNOMEPRINT)
1765                 gedit_print(GTK_TEXT_VIEW(mimeview->textview->text));
1766 #else
1767                 /* TODO: Get the real parent window, not the main window */
1768                 mainwin = mainwindow_get_mainwindow();
1769                 printing_print(GTK_TEXT_VIEW(mimeview->textview->text),
1770                                mainwin ? GTK_WINDOW(mainwin->window) : NULL,
1771                                 sel_start, sel_end);
1772 #endif
1773         }
1774 }
1775
1776 void messageview_print(MsgInfo *msginfo, gboolean all_headers, 
1777                         gint sel_start, gint sel_end, gint partnum) 
1778 {
1779         PangoFontDescription *font_desc = NULL;
1780         MessageView *tmpview = messageview_create_with_new_window_visible(
1781                                 mainwindow_get_mainwindow(), FALSE);
1782
1783         if (prefs_common.use_different_print_font) {
1784                 font_desc = pango_font_description_from_string
1785                                                 (prefs_common.printfont);
1786         } else {
1787                 font_desc = pango_font_description_from_string
1788                                                 (prefs_common.textfont);
1789         }
1790         if (font_desc) {
1791                 gtk_widget_modify_font(tmpview->mimeview->textview->text, 
1792                         font_desc);
1793                 pango_font_description_free(font_desc);
1794         }
1795
1796         tmpview->all_headers = all_headers;
1797         if (msginfo && messageview_show(tmpview, msginfo, 
1798                 tmpview->all_headers) >= 0) {
1799                         print_mimeview(tmpview->mimeview, 
1800                                 sel_start, sel_end, partnum);
1801         }
1802         messageview_destroy(tmpview);
1803 }
1804 #endif
1805
1806 #if GTK_CHECK_VERSION(2,10,0) && !defined(USE_GNOMEPRINT)
1807 static void page_setup_cb(gpointer data, guint action, GtkWidget *widget)
1808 {
1809         MessageView *messageview = (MessageView *)data;
1810         printing_page_setup(messageview ?
1811                             GTK_WINDOW(messageview->window) : NULL);
1812 }
1813 #endif
1814
1815 static void print_cb(gpointer data, guint action, GtkWidget *widget)
1816 {
1817         MessageView *messageview = (MessageView *)data;
1818 #if !defined(USE_GNOMEPRINT) && !GTK_CHECK_VERSION(2,10,0)
1819         gchar *cmdline = NULL;
1820         gchar *p;
1821 #else
1822         gint sel_start = -1, sel_end = -1, partnum = 0;
1823 #endif
1824
1825         if (!messageview->msginfo) return;
1826
1827 #if !defined(USE_GNOMEPRINT) && !GTK_CHECK_VERSION(2,10,0)
1828         cmdline = input_dialog(_("Print"),
1829                                _("Enter the print command line:\n"
1830                                  "('%s' will be replaced with file name)"),
1831                                prefs_common.print_cmd);
1832         if (!cmdline) return;
1833         if (!(p = strchr(cmdline, '%')) || *(p + 1) != 's' ||
1834             strchr(p + 2, '%')) {
1835                 alertpanel_error(_("Print command line is invalid:\n'%s'"),
1836                                  cmdline);
1837                 g_free(cmdline);
1838                 return;
1839         }
1840         procmsg_print_message(messageview->msginfo, cmdline);
1841         g_free(cmdline);
1842 #else
1843         partnum = mimeview_get_selected_part_num(messageview->mimeview);
1844         textview_get_selection_offsets(messageview->mimeview->textview,
1845                 &sel_start, &sel_end);
1846         messageview_print(messageview->msginfo, messageview->all_headers, 
1847                 sel_start, sel_end, partnum);
1848 #endif
1849 }
1850
1851 static void close_cb(gpointer data, guint action, GtkWidget *widget)
1852 {
1853         MessageView *messageview = (MessageView *)data;
1854         messageview_destroy(messageview);
1855 }
1856
1857 static void copy_cb(gpointer data, guint action, GtkWidget *widget)
1858 {
1859         MessageView *messageview = (MessageView *)data;
1860         messageview_copy_clipboard(messageview);
1861 }
1862
1863 static void allsel_cb(gpointer data, guint action, GtkWidget *widget)
1864 {
1865         MessageView *messageview = (MessageView *)data;
1866         messageview_select_all(messageview);
1867 }
1868
1869 static void search_cb(gpointer data, guint action, GtkWidget *widget)
1870 {
1871         MessageView *messageview = (MessageView *)data;
1872         message_search(messageview);
1873 }
1874
1875 static void prev_cb(gpointer data, guint action, GtkWidget *widget)
1876 {
1877         MessageView *messageview = (MessageView *)data;
1878         messageview->updating = TRUE;
1879         summary_step(messageview->mainwin->summaryview, GTK_SCROLL_STEP_BACKWARD);
1880         messageview->updating = FALSE;
1881
1882         if (messageview->deferred_destroy) {
1883                 debug_print("messageview got away!\n");
1884                 messageview_destroy(messageview);
1885                 return;
1886         }
1887         if (messageview->mainwin->summaryview->selected) {
1888 #ifndef MAEMO
1889                 MsgInfo * msginfo = summary_get_selected_msg(messageview->mainwin->summaryview);
1890                        
1891                 if (msginfo)
1892                         messageview_show(messageview, msginfo, 
1893                                          messageview->all_headers);
1894 #endif
1895         } else {
1896                 gtk_widget_destroy(messageview->window);
1897         }
1898 }
1899
1900 static void next_cb(gpointer data, guint action, GtkWidget *widget)
1901 {
1902         MessageView *messageview = (MessageView *)data;
1903         messageview->updating = TRUE;
1904         summary_step(messageview->mainwin->summaryview, GTK_SCROLL_STEP_FORWARD);
1905         messageview->updating = FALSE;
1906
1907         if (messageview->deferred_destroy) {
1908                 debug_print("messageview got away!\n");
1909                 messageview_destroy(messageview);
1910                 return;
1911         }
1912         if (messageview->mainwin->summaryview->selected) {
1913 #ifndef MAEMO
1914                 MsgInfo * msginfo = summary_get_selected_msg(messageview->mainwin->summaryview);
1915                        
1916                 if (msginfo)
1917                         messageview_show(messageview, msginfo, 
1918                                          messageview->all_headers);
1919 #endif
1920         } else {
1921                 gtk_widget_destroy(messageview->window);
1922         }
1923 }
1924
1925 static void prev_unread_cb(gpointer data, guint action, GtkWidget *widget)
1926 {
1927         MessageView *messageview = (MessageView *)data;
1928         messageview->updating = TRUE;
1929         summary_select_prev_unread(messageview->mainwin->summaryview);
1930         messageview->updating = FALSE;
1931
1932         if (messageview->deferred_destroy) {
1933                 debug_print("messageview got away!\n");
1934                 messageview_destroy(messageview);
1935                 return;
1936         }
1937         if (messageview->mainwin->summaryview->selected) {
1938 #ifndef MAEMO
1939                 MsgInfo * msginfo = summary_get_selected_msg(messageview->mainwin->summaryview);
1940                        
1941                 if (msginfo)
1942                         messageview_show(messageview, msginfo, 
1943                                          messageview->all_headers);
1944 #endif
1945         } else {
1946                 gtk_widget_destroy(messageview->window);
1947         }
1948 }
1949
1950 static void next_unread_cb(gpointer data, guint action, GtkWidget *widget)
1951 {
1952         MessageView *messageview = (MessageView *)data;
1953         messageview->updating = TRUE;
1954         summary_select_next_unread(messageview->mainwin->summaryview);
1955         messageview->updating = FALSE;
1956
1957         if (messageview->deferred_destroy) {
1958                 debug_print("messageview got away!\n");
1959                 messageview_destroy(messageview);
1960                 return;
1961         }
1962         if (messageview->mainwin->summaryview->selected) {
1963 #ifndef MAEMO
1964                 MsgInfo * msginfo = summary_get_selected_msg(messageview->mainwin->summaryview);
1965                        
1966                 if (msginfo)
1967                         messageview_show(messageview, msginfo, 
1968                                          messageview->all_headers);
1969 #endif
1970         } else {
1971                 gtk_widget_destroy(messageview->window);
1972         }
1973 }
1974
1975 static void prev_new_cb(gpointer data, guint action, GtkWidget *widget)
1976 {
1977         MessageView *messageview = (MessageView *)data;
1978         messageview->updating = TRUE;
1979         summary_select_prev_new(messageview->mainwin->summaryview);
1980         messageview->updating = FALSE;
1981
1982         if (messageview->deferred_destroy) {
1983                 debug_print("messageview got away!\n");
1984                 messageview_destroy(messageview);
1985                 return;
1986         }
1987         if (messageview->mainwin->summaryview->selected) {
1988 #ifndef MAEMO
1989                 MsgInfo * msginfo = summary_get_selected_msg(messageview->mainwin->summaryview);
1990                        
1991                 if (msginfo)
1992                         messageview_show(messageview, msginfo, 
1993                                          messageview->all_headers);
1994 #endif
1995         } else {
1996                 gtk_widget_destroy(messageview->window);
1997         }
1998 }
1999
2000 static void next_new_cb(gpointer data, guint action, GtkWidget *widget)
2001 {
2002         MessageView *messageview = (MessageView *)data;
2003         messageview->updating = TRUE;
2004         summary_select_next_new(messageview->mainwin->summaryview);
2005         messageview->updating = FALSE;
2006
2007         if (messageview->deferred_destroy) {
2008                 debug_print("messageview got away!\n");
2009                 messageview_destroy(messageview);
2010                 return;
2011         }
2012         if (messageview->mainwin->summaryview->selected) {
2013 #ifndef MAEMO
2014                 MsgInfo * msginfo = summary_get_selected_msg(messageview->mainwin->summaryview);
2015                        
2016                 if (msginfo)
2017                         messageview_show(messageview, msginfo, 
2018                                          messageview->all_headers);
2019 #endif
2020         } else {
2021                 gtk_widget_destroy(messageview->window);
2022         }
2023 }
2024
2025 static void prev_marked_cb(gpointer data, guint action, GtkWidget *widget)
2026 {
2027         MessageView *messageview = (MessageView *)data;
2028         messageview->updating = TRUE;
2029         summary_select_prev_marked(messageview->mainwin->summaryview);
2030         messageview->updating = FALSE;
2031
2032         if (messageview->deferred_destroy) {
2033                 debug_print("messageview got away!\n");
2034                 messageview_destroy(messageview);
2035                 return;
2036         }
2037         if (messageview->mainwin->summaryview->selected) {
2038 #ifndef MAEMO
2039                 MsgInfo * msginfo = summary_get_selected_msg(messageview->mainwin->summaryview);
2040                        
2041                 if (msginfo)
2042                         messageview_show(messageview, msginfo, 
2043                                          messageview->all_headers);
2044 #endif
2045         } else {
2046                 gtk_widget_destroy(messageview->window);
2047         }
2048 }
2049
2050 static void next_marked_cb(gpointer data, guint action, GtkWidget *widget)
2051 {
2052         MessageView *messageview = (MessageView *)data;
2053         messageview->updating = TRUE;
2054         summary_select_next_marked(messageview->mainwin->summaryview);
2055         messageview->updating = FALSE;
2056
2057         if (messageview->deferred_destroy) {
2058                 debug_print("messageview got away!\n");
2059                 messageview_destroy(messageview);
2060                 return;
2061         }
2062         if (messageview->mainwin->summaryview->selected) {
2063 #ifndef MAEMO
2064                 MsgInfo * msginfo = summary_get_selected_msg(messageview->mainwin->summaryview);
2065                        
2066                 if (msginfo)
2067                         messageview_show(messageview, msginfo, 
2068                                          messageview->all_headers);
2069 #endif
2070         } else {
2071                 gtk_widget_destroy(messageview->window);
2072         }
2073 }
2074
2075 static void prev_labeled_cb(gpointer data, guint action, GtkWidget *widget)
2076 {
2077         MessageView *messageview = (MessageView *)data;
2078         messageview->updating = TRUE;
2079         summary_select_prev_labeled(messageview->mainwin->summaryview);
2080         messageview->updating = FALSE;
2081
2082         if (messageview->deferred_destroy) {
2083                 debug_print("messageview got away!\n");
2084                 messageview_destroy(messageview);
2085                 return;
2086         }
2087         if (messageview->mainwin->summaryview->selected) {
2088 #ifndef MAEMO
2089                 MsgInfo * msginfo = summary_get_selected_msg(messageview->mainwin->summaryview);
2090                        
2091                 if (msginfo)
2092                         messageview_show(messageview, msginfo, 
2093                                          messageview->all_headers);
2094 #endif
2095         } else {
2096                 gtk_widget_destroy(messageview->window);
2097         }
2098 }
2099
2100 static void next_labeled_cb(gpointer data, guint action, GtkWidget *widget)
2101 {
2102         MessageView *messageview = (MessageView *)data;
2103         messageview->updating = TRUE;
2104         summary_select_next_labeled(messageview->mainwin->summaryview);
2105         messageview->updating = FALSE;
2106
2107         if (messageview->deferred_destroy) {
2108                 debug_print("messageview got away!\n");
2109                 messageview_destroy(messageview);
2110                 return;
2111         }
2112         if (messageview->mainwin->summaryview->selected) {
2113 #ifndef MAEMO
2114                 MsgInfo * msginfo = summary_get_selected_msg(messageview->mainwin->summaryview);
2115                        
2116                 if (msginfo)
2117                         messageview_show(messageview, msginfo, 
2118                                          messageview->all_headers);
2119 #endif
2120         } else {
2121                 gtk_widget_destroy(messageview->window);
2122         }
2123 }
2124
2125 static void last_read_cb(gpointer data, guint action, GtkWidget *widget)
2126 {
2127         MessageView *messageview = (MessageView *)data;
2128         messageview->updating = TRUE;
2129         summary_select_last_read(messageview->mainwin->summaryview);
2130         messageview->updating = FALSE;
2131
2132         if (messageview->deferred_destroy) {
2133                 debug_print("messageview got away!\n");
2134                 messageview_destroy(messageview);
2135                 return;
2136         }
2137         if (messageview->mainwin->summaryview->selected) {
2138 #ifndef MAEMO
2139                 MsgInfo * msginfo = summary_get_selected_msg(messageview->mainwin->summaryview);
2140                        
2141                 if (msginfo)
2142                         messageview_show(messageview, msginfo, 
2143                                          messageview->all_headers);
2144 #endif
2145         } else {
2146                 gtk_widget_destroy(messageview->window);
2147         }
2148 }
2149
2150 static void parent_cb(gpointer data, guint action, GtkWidget *widget)
2151 {
2152         MessageView *messageview = (MessageView *)data;
2153         messageview->updating = TRUE;
2154         summary_select_parent(messageview->mainwin->summaryview);
2155         messageview->updating = FALSE;
2156
2157         if (messageview->deferred_destroy) {
2158                 debug_print("messageview got away!\n");
2159                 messageview_destroy(messageview);
2160                 return;
2161         }
2162         if (messageview->mainwin->summaryview->selected) {
2163 #ifndef MAEMO
2164                 MsgInfo * msginfo = summary_get_selected_msg(messageview->mainwin->summaryview);
2165                        
2166                 if (msginfo)
2167                         messageview_show(messageview, msginfo, 
2168                                          messageview->all_headers);
2169 #endif
2170         } else {
2171                 gtk_widget_destroy(messageview->window);
2172         }
2173 }
2174
2175 static void goto_unread_folder_cb(gpointer data, guint action, GtkWidget *widget)
2176 {
2177         MessageView *messageview = (MessageView *)data;
2178         messageview->updating = TRUE;
2179         folderview_select_next_unread(messageview->mainwin->folderview, FALSE);
2180         messageview->updating = FALSE;
2181
2182         if (messageview->deferred_destroy) {
2183                 debug_print("messageview got away!\n");
2184                 messageview_destroy(messageview);
2185                 return;
2186         }
2187         if (messageview->mainwin->summaryview->selected) {
2188 #ifndef MAEMO
2189                 MsgInfo * msginfo = summary_get_selected_msg(messageview->mainwin->summaryview);
2190                        
2191                 if (msginfo)
2192                         messageview_show(messageview, msginfo, 
2193                                          messageview->all_headers);
2194 #endif
2195         } else {
2196                 gtk_widget_destroy(messageview->window);
2197         }
2198 }
2199
2200 static void goto_folder_cb(gpointer data, guint action, GtkWidget *widget)
2201 {
2202         MessageView *messageview = (MessageView *)data;
2203         messageview->updating = TRUE;
2204         FolderItem *to_folder;
2205         messageview->updating = FALSE;
2206
2207         to_folder = foldersel_folder_sel(NULL, FOLDER_SEL_ALL, NULL, FALSE);
2208
2209         if (to_folder) {
2210                 folderview_select(messageview->mainwin->folderview, to_folder);
2211
2212                 if (messageview->deferred_destroy) {
2213                         debug_print("messageview got away!\n");
2214                         messageview_destroy(messageview);
2215                         return;
2216                 }
2217                 if (messageview->mainwin->summaryview->selected) {
2218 #ifndef MAEMO
2219                         MsgInfo * msginfo = summary_get_selected_msg(messageview->mainwin->summaryview);
2220                        
2221                         if (msginfo)
2222                                 messageview_show(messageview, msginfo, 
2223                                                  messageview->all_headers);
2224 #endif
2225                 } else {
2226                         gtk_widget_destroy(messageview->window);
2227                 }
2228         }
2229 }
2230
2231 static void set_charset_cb(gpointer data, guint action, GtkWidget *widget)
2232 {
2233         MessageView *messageview = (MessageView *)data;
2234         const gchar *charset;
2235
2236         if (GTK_CHECK_MENU_ITEM(widget)->active) {
2237                 charset = conv_get_charset_str((CharSet)action);
2238                 g_free(messageview->forced_charset);
2239                 messageview->forced_charset = g_strdup(charset);
2240                 procmime_force_charset(charset);
2241                 
2242                 messageview_show(messageview, messageview->msginfo, FALSE);
2243         }
2244 }
2245
2246 static void set_decode_cb(gpointer data, guint action, GtkWidget *widget)
2247 {
2248         MessageView *messageview = (MessageView *)data;
2249         if (GTK_CHECK_MENU_ITEM(widget)->active) {
2250                 messageview->forced_encoding = (EncodingType)action;
2251
2252                 messageview_show(messageview, messageview->msginfo, FALSE);
2253                 
2254                 debug_print("forced encoding: %d\n", action);
2255         }
2256 }
2257
2258
2259 static void view_source_cb(gpointer data, guint action, GtkWidget *widget)
2260 {
2261         MessageView *messageview = (MessageView *)data;
2262         SourceWindow *srcwin;
2263
2264         if (!messageview->msginfo) return;
2265
2266         srcwin = source_window_create();
2267         source_window_show_msg(srcwin, messageview->msginfo);
2268         source_window_show(srcwin);
2269 }
2270
2271 static void show_all_header_cb(gpointer data, guint action, GtkWidget *widget)
2272 {
2273         MessageView *messageview = (MessageView *)data;
2274         MsgInfo *msginfo = messageview->msginfo;
2275
2276         if (messageview->mimeview->textview &&
2277             messageview->mimeview->textview->loading) {
2278                 return;
2279         }
2280         if (messageview->updating)
2281                 return;
2282
2283         messageview->all_headers = 
2284                         GTK_CHECK_MENU_ITEM(widget)->active;
2285         if (!msginfo) return;
2286         messageview->msginfo = NULL;
2287         messageview_show(messageview, msginfo,
2288                          GTK_CHECK_MENU_ITEM(widget)->active);
2289         procmsg_msginfo_free(msginfo);
2290         main_window_set_menu_sensitive(messageview->mainwin);
2291 }
2292
2293 #define SET_CHECK_MENU_ACTIVE(path, active) \
2294 { \
2295         menuitem = gtk_item_factory_get_widget(ifactory, path); \
2296         gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menuitem), active); \
2297 }
2298
2299 static void msg_hide_quotes_cb(gpointer data, guint action, GtkWidget *widget)
2300 {
2301         MessageView *messageview = (MessageView *)data;
2302         MsgInfo *msginfo = messageview->msginfo;
2303         static gboolean updating_menu = FALSE;
2304         GtkItemFactory *ifactory = gtk_item_factory_from_widget(messageview->menubar);
2305         GtkWidget *menuitem;
2306         if (updating_menu)
2307                 return;
2308
2309         prefs_common.hide_quotes = 
2310                         GTK_CHECK_MENU_ITEM(widget)->active ? action : 0;
2311         
2312         updating_menu=TRUE;
2313         SET_CHECK_MENU_ACTIVE("/View/Quotes/Fold all", FALSE);
2314         SET_CHECK_MENU_ACTIVE("/View/Quotes/Fold from level 2", FALSE);
2315         SET_CHECK_MENU_ACTIVE("/View/Quotes/Fold from level 3", FALSE);
2316         gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(widget), prefs_common.hide_quotes > 0);      
2317         updating_menu=FALSE;
2318         if (!msginfo) return;
2319         messageview->msginfo = NULL;
2320         messageview_show(messageview, msginfo,
2321                          messageview->all_headers);
2322         procmsg_msginfo_free(msginfo);
2323         
2324         /* update main window */
2325         main_window_set_menu_sensitive(messageview->mainwin);
2326         summary_redisplay_msg(messageview->mainwin->summaryview);
2327 }
2328 #undef SET_CHECK_MENU_ACTIVE
2329
2330 static void compose_cb(gpointer data, guint action, GtkWidget *widget)
2331 {
2332         MessageView *messageview = (MessageView *)data;
2333         PrefsAccount *ac = NULL;
2334         FolderItem *item = NULL;
2335
2336         if (messageview->msginfo)
2337                 item = messageview->msginfo->folder;
2338
2339         if (item) {
2340                 ac = account_find_from_item(item);
2341                 if (ac && ac->protocol == A_NNTP &&
2342                     item->stype == F_NEWS) {
2343                         compose_new(ac, item->path, NULL);
2344                         return;
2345                 }
2346         }
2347
2348         compose_new(ac, NULL, NULL);
2349 }
2350
2351 static void reply_cb(gpointer data, guint action, GtkWidget *widget)
2352 {
2353         MessageView *messageview = (MessageView *)data;
2354         GSList *msginfo_list = NULL;
2355
2356         g_return_if_fail(messageview->msginfo);
2357
2358         msginfo_list = g_slist_append(msginfo_list, messageview->msginfo);
2359         compose_reply_from_messageview(messageview, msginfo_list, action);
2360         g_slist_free(msginfo_list);
2361 }
2362
2363 static void addressbook_open_cb(gpointer data, guint action, GtkWidget *widget)
2364 {
2365         addressbook_open(NULL);
2366 }
2367
2368 static void add_address_cb(gpointer data, guint action, GtkWidget *widget)
2369 {
2370         MessageView *messageview = (MessageView *)data;
2371         MsgInfo *msginfo, *full_msginfo;
2372         gchar *from;
2373         GtkWidget *image = NULL;
2374         GdkPixbuf *picture = NULL;
2375
2376         if (!messageview->msginfo || !messageview->msginfo->from) 
2377                 return;
2378
2379         msginfo = messageview->msginfo;
2380         Xstrdup_a(from, msginfo->from, return);
2381         eliminate_address_comment(from);
2382         extract_address(from);
2383         
2384         full_msginfo = procmsg_msginfo_get_full_info(msginfo);
2385         if (full_msginfo &&
2386             full_msginfo->extradata &&
2387             full_msginfo->extradata->face) {
2388                 image = face_get_from_header(full_msginfo->extradata->face);
2389         } 
2390 #if HAVE_LIBCOMPFACE
2391         else if (full_msginfo &&
2392                  full_msginfo->extradata &&
2393                  full_msginfo->extradata->xface) {
2394                 image = xface_get_from_header(full_msginfo->extradata->xface,
2395                                 &messageview->mainwin->summaryview->ctree->style->white,
2396                                 messageview->window->window);   
2397         }
2398 #endif
2399         procmsg_msginfo_free(full_msginfo);
2400         if (image)
2401                 picture = gtk_image_get_pixbuf(GTK_IMAGE(image));
2402
2403         addressbook_add_contact(msginfo->fromname, from, NULL, picture);
2404
2405         if (image)
2406                 gtk_widget_destroy(image);
2407 }
2408
2409 static void create_filter_cb(gpointer data, guint action, GtkWidget *widget)
2410 {
2411         MessageView *messageview = (MessageView *)data;
2412         FolderItem * item;
2413         
2414         if (!messageview->msginfo) return;
2415         
2416         item = messageview->msginfo->folder;
2417         summary_msginfo_filter_open(item,  messageview->msginfo,
2418                                     (PrefsFilterType)action, 0);
2419 }
2420
2421 static void create_processing_cb(gpointer data, guint action,
2422                                  GtkWidget *widget)
2423 {
2424         MessageView *messageview = (MessageView *)data;
2425         FolderItem * item;
2426         
2427         if (!messageview->msginfo) return;
2428         
2429         item = messageview->msginfo->folder;
2430         summary_msginfo_filter_open(item,  messageview->msginfo,
2431                                     (PrefsFilterType)action, 1);
2432 }
2433
2434 static void open_urls_cb(gpointer data, guint action, GtkWidget *widget)
2435 {
2436         MessageView *messageview = (MessageView *)data;
2437         messageview_list_urls(messageview);
2438 }
2439
2440 static void about_cb(gpointer data, guint action, GtkWidget *widget)
2441 {
2442         about_show();
2443 }
2444
2445 static gboolean messageview_update_msg(gpointer source, gpointer data)
2446 {
2447         MsgInfoUpdate *msginfo_update = (MsgInfoUpdate *) source;
2448         MessageView *messageview = (MessageView *)data;
2449
2450         if (messageview->msginfo != msginfo_update->msginfo)
2451                 return FALSE;
2452
2453         if (msginfo_update->flags & MSGINFO_UPDATE_DELETED) {
2454                 MsgInfo *old_msginfo = messageview->msginfo;
2455                 messageview_clear(messageview);
2456                 messageview_update(messageview, old_msginfo);
2457         }
2458
2459         return FALSE;
2460 }
2461
2462 void messageview_set_menu_sensitive(MessageView *messageview)
2463 {
2464         GtkItemFactory *ifactory;
2465         GtkWidget *menuitem = NULL;
2466
2467         if (!messageview || !messageview->new_window) 
2468                 return;
2469         /* do some smart things */
2470         if (!messageview->menubar) return;
2471         ifactory = gtk_item_factory_from_widget(messageview->menubar);
2472         if (!ifactory) return;
2473
2474         if (prefs_common.hide_quotes) {
2475                 menuitem = NULL;
2476                 if (prefs_common.hide_quotes == 1)
2477                         menuitem = gtk_item_factory_get_widget(ifactory, 
2478                                         "/View/Quotes/Fold all");
2479                 if (prefs_common.hide_quotes == 2)
2480                         menuitem = gtk_item_factory_get_widget(ifactory, 
2481                                         "/View/Quotes/Fold from level 2");
2482                 if (prefs_common.hide_quotes == 3)
2483                         menuitem = gtk_item_factory_get_widget(ifactory, 
2484                                         "/View/Quotes/Fold from level 3");
2485                 gtk_check_menu_item_set_active
2486                         (GTK_CHECK_MENU_ITEM(menuitem),
2487                          TRUE);
2488         }
2489 }
2490
2491 void messageview_learn (MessageView *msgview, gboolean is_spam)
2492 {
2493         if (is_spam) {
2494                 if (procmsg_spam_learner_learn(msgview->msginfo, NULL, TRUE) == 0)
2495                         procmsg_msginfo_set_flags(msgview->msginfo, MSG_SPAM, 0);
2496                 else
2497                         log_error(LOG_PROTOCOL, _("An error happened while learning.\n"));
2498                 
2499         } else {
2500                 if (procmsg_spam_learner_learn(msgview->msginfo, NULL, FALSE) == 0)
2501                         procmsg_msginfo_unset_flags(msgview->msginfo, MSG_SPAM, 0);
2502                 else
2503                         log_error(LOG_PROTOCOL, _("An error happened while learning.\n"));
2504         }
2505         if (msgview->toolbar)
2506                 toolbar_set_learn_button
2507                         (msgview->toolbar,
2508                          MSG_IS_SPAM(msgview->msginfo->flags)?LEARN_HAM:LEARN_SPAM);
2509         else
2510                 toolbar_set_learn_button
2511                         (msgview->mainwin->toolbar,
2512                          MSG_IS_SPAM(msgview->msginfo->flags)?LEARN_HAM:LEARN_SPAM);
2513 }
2514
2515 void messageview_list_urls (MessageView *msgview)
2516 {
2517         GSList *cur = msgview->mimeview->textview->uri_list;
2518         GSList *newlist = NULL;
2519         GHashTable *uri_hashtable = g_hash_table_new(g_str_hash, g_str_equal); 
2520         for (; cur; cur = cur->next) {
2521                 ClickableText *uri = (ClickableText *)cur->data;
2522                 if (uri->uri &&
2523                     (!g_ascii_strncasecmp(uri->uri, "ftp.", 4) ||
2524                      !g_ascii_strncasecmp(uri->uri, "ftp:", 4) ||
2525                      !g_ascii_strncasecmp(uri->uri, "www.", 4) ||
2526                      !g_ascii_strncasecmp(uri->uri, "http:", 5) ||
2527                      !g_ascii_strncasecmp(uri->uri, "https:", 6)))
2528                 {
2529                         if(g_hash_table_lookup(uri_hashtable, uri->uri))
2530                                 continue;
2531                         
2532                         newlist = g_slist_prepend(newlist, uri);
2533                         g_hash_table_insert(uri_hashtable, uri->uri,
2534                                             GUINT_TO_POINTER(g_str_hash(uri->uri)));
2535                 }
2536         }
2537         newlist = g_slist_reverse(newlist);
2538         uri_opener_open(msgview, newlist);
2539         g_slist_free(newlist);
2540         g_hash_table_destroy(uri_hashtable);
2541 }