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