2007-08-19 [colin] 2.10.0cvs135
[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 "sourcewindow.h"
46 #include "addressbook.h"
47 #include "alertpanel.h"
48 #include "inputdialog.h"
49 #include "mainwindow.h"
50 #include "manage_window.h"
51 #include "procmsg.h"
52 #include "procheader.h"
53 #include "procmime.h"
54 #include "account.h"
55 #include "action.h"
56 #include "prefs_common.h"
57 #include "prefs_account.h"
58 #include "gtkutils.h"
59 #include "utils.h"
60 #include "send_message.h"
61 #include "stock_pixmap.h"
62 #include "hooks.h"
63 #include "filtering.h"
64 #include "partial_download.h"
65 #include "gedit-print.h"
66 #include "uri_opener.h"
67 #include "inc.h"
68 #include "log.h"
69 #include "combobox.h"
70
71 static GList *messageview_list = NULL;
72
73 static gint messageview_delete_cb       (GtkWidget              *widget,
74                                          GdkEventAny            *event,
75                                          MessageView            *messageview);
76 static void messageview_size_allocate_cb(GtkWidget      *widget,
77                                          GtkAllocation  *allocation);
78 static gboolean key_pressed             (GtkWidget      *widget,
79                                          GdkEventKey    *event,
80                                          MessageView    *messageview);
81
82 static void return_receipt_show         (NoticeView     *noticeview, 
83                                          MsgInfo        *msginfo);      
84 static void return_receipt_send_clicked (NoticeView     *noticeview, 
85                                          MsgInfo        *msginfo);
86 static void partial_recv_show           (NoticeView     *noticeview, 
87                                          MsgInfo        *msginfo);      
88 static void partial_recv_dload_clicked  (NoticeView     *noticeview, 
89                                          MsgInfo        *msginfo);
90 static void partial_recv_del_clicked    (NoticeView     *noticeview, 
91                                          MsgInfo        *msginfo);
92 static void partial_recv_unmark_clicked (NoticeView     *noticeview, 
93                                          MsgInfo        *msginfo);
94 static void save_as_cb                  (gpointer        data,
95                                          guint           action,
96                                          GtkWidget      *widget);
97 static void print_cb                    (gpointer        data,
98                                          guint           action,
99                                          GtkWidget      *widget);
100 static void close_cb                    (gpointer        data,
101                                          guint           action,
102                                          GtkWidget      *widget);
103 static void copy_cb                     (gpointer        data,
104                                          guint           action,
105                                          GtkWidget      *widget);
106 static void allsel_cb                   (gpointer        data,
107                                          guint           action,
108                                          GtkWidget      *widget);
109 static void search_cb                   (gpointer        data,
110                                          guint           action,
111                                          GtkWidget      *widget);
112
113 static void set_charset_cb              (gpointer        data,
114                                          guint           action,
115                                          GtkWidget      *widget);
116 static void set_decode_cb               (gpointer        data,
117                                          guint           action,
118                                          GtkWidget      *widget);
119 static void view_source_cb              (gpointer        data,
120                                          guint           action,
121                                          GtkWidget      *widget);
122 static void show_all_header_cb          (gpointer        data,
123                                          guint           action,
124                                          GtkWidget      *widget);
125 static void msg_hide_quotes_cb          (gpointer        data,
126                                          guint           action,
127                                          GtkWidget      *widget);
128
129 static void compose_cb                  (gpointer        data,
130                                          guint           action,
131                                          GtkWidget      *widget);
132 static void reply_cb                    (gpointer        data,
133                                          guint           action,
134                                          GtkWidget      *widget);
135
136 static PrefsAccount *select_account_from_list
137                                         (GList          *ac_list);
138 static void addressbook_open_cb         (gpointer        data,
139                                          guint           action,
140                                          GtkWidget      *widget);
141 static void add_address_cb              (gpointer        data,
142                                          guint           action,
143                                          GtkWidget      *widget);
144 static void create_filter_cb            (gpointer        data,
145                                          guint           action,
146                                          GtkWidget      *widget);
147 static void create_processing_cb        (gpointer        data,
148                                          guint           action,
149                                          GtkWidget      *widget);
150 static void open_urls_cb                (gpointer        data,
151                                          guint           action,
152                                          GtkWidget      *widget);
153
154 static void about_cb                    (gpointer        data,
155                                          guint           action,
156                                          GtkWidget      *widget);
157 static void messageview_update          (MessageView    *msgview,
158                                          MsgInfo        *old_msginfo);
159 static gboolean messageview_update_msg  (gpointer source, gpointer data);
160
161 static GList *msgview_list = NULL;
162 static GtkItemFactoryEntry msgview_entries[] =
163 {
164         {N_("/_File"),                  NULL, NULL, 0, "<Branch>"},
165         {N_("/_File/_Save as..."),      "<control>S", save_as_cb, 0, NULL},
166         {N_("/_File/_Print..."),        "<control>P", print_cb, 0, NULL},
167         {N_("/_File/---"),              NULL, NULL, 0, "<Separator>"},
168         {N_("/_File/_Close"),           "<control>W", close_cb, 0, NULL},
169
170         {N_("/_Edit"),                  NULL, NULL, 0, "<Branch>"},
171         {N_("/_Edit/_Copy"),            "<control>C", copy_cb, 0, NULL},
172         {N_("/_Edit/Select _all"),      "<control>A", allsel_cb, 0, NULL},
173         {N_("/_Edit/---"),              NULL, NULL, 0, "<Separator>"},
174         {N_("/_Edit/_Find in current message..."),
175                                         "<control>F", search_cb, 0, NULL},
176
177         {N_("/_View"),                  NULL, NULL, 0, "<Branch>"},
178
179 #define ENC_SEPARATOR \
180         {N_("/_View/Character _encoding/---"),  NULL, NULL, 0, "<Separator>"}
181 #define ENC_ACTION(action) \
182         NULL, set_charset_cb, action, "/View/Character encoding/Auto detect"
183
184         {N_("/_View/Character _encoding"),      NULL, NULL, 0, "<Branch>"},
185         {N_("/_View/Character _encoding/_Auto detect"),
186                                         NULL, set_charset_cb, C_AUTO, "<RadioItem>"},
187         ENC_SEPARATOR,
188         {N_("/_View/Character _encoding/7bit ascii (US-ASC_II)"),
189          ENC_ACTION(C_US_ASCII)},
190
191         {N_("/_View/Character _encoding/Unicode (_UTF-8)"),
192          ENC_ACTION(C_UTF_8)},
193         ENC_SEPARATOR,
194         {N_("/_View/Character _encoding/Western European (ISO-8859-_1)"),
195          ENC_ACTION(C_ISO_8859_1)},
196         {N_("/_View/Character _encoding/Western European (ISO-8859-15)"),
197          ENC_ACTION(C_ISO_8859_15)},
198         {N_("/_View/Character _encoding/Western European (Windows-1252)"),
199          ENC_ACTION(C_WINDOWS_1252)},
200         ENC_SEPARATOR,
201         {N_("/_View/Character _encoding/Central European (ISO-8859-_2)"),
202          ENC_ACTION(C_ISO_8859_2)},
203         ENC_SEPARATOR,
204         {N_("/_View/Character _encoding/_Baltic (ISO-8859-13)"),
205          ENC_ACTION(C_ISO_8859_13)},
206         {N_("/_View/Character _encoding/Baltic (ISO-8859-_4)"),
207          ENC_ACTION(C_ISO_8859_4)},
208         ENC_SEPARATOR,
209         {N_("/_View/Character _encoding/Greek (ISO-8859-_7)"),
210          ENC_ACTION(C_ISO_8859_7)},
211         ENC_SEPARATOR,
212         {N_("/_View/Character _encoding/Hebrew (ISO-8859-_8)"),
213          ENC_ACTION(C_ISO_8859_8)},
214         {N_("/_View/Character _encoding/Hebrew (Windows-1255)"),
215          ENC_ACTION(C_CP1255)},
216         ENC_SEPARATOR,
217         {N_("/_View/Character _encoding/Arabic (ISO-8859-_6)"),
218          ENC_ACTION(C_ISO_8859_6)},
219         {N_("/_View/Character _encoding/Arabic (Windows-1256)"),
220          ENC_ACTION(C_CP1256)},
221         ENC_SEPARATOR,
222         {N_("/_View/Character _encoding/Turkish (ISO-8859-_9)"),
223          ENC_ACTION(C_ISO_8859_9)},
224         ENC_SEPARATOR,
225         {N_("/_View/Character _encoding/Cyrillic (ISO-8859-_5)"),
226          ENC_ACTION(C_ISO_8859_5)},
227         {N_("/_View/Character _encoding/Cyrillic (KOI8-_R)"),
228          ENC_ACTION(C_KOI8_R)},
229         {N_("/_View/Character _encoding/Cyrillic (KOI8-U)"),
230          ENC_ACTION(C_KOI8_U)},
231         {N_("/_View/Character _encoding/Cyrillic (Windows-1251)"),
232          ENC_ACTION(C_CP1251)},
233         ENC_SEPARATOR,
234         {N_("/_View/Character _encoding/Japanese (ISO-2022-_JP)"),
235          ENC_ACTION(C_ISO_2022_JP)},
236         {N_("/_View/Character _encoding/Japanese (ISO-2022-JP-2)"),
237          ENC_ACTION(C_ISO_2022_JP_2)},
238         {N_("/_View/Character _encoding/Japanese (_EUC-JP)"),
239          ENC_ACTION(C_EUC_JP)},
240         {N_("/_View/Character _encoding/Japanese (_Shift__JIS)"),
241          ENC_ACTION(C_SHIFT_JIS)},
242         ENC_SEPARATOR,
243         {N_("/_View/Character _encoding/Simplified Chinese (_GB2312)"),
244          ENC_ACTION(C_GB2312)},
245         {N_("/_View/Character _encoding/Simplified Chinese (GBK)"),
246          ENC_ACTION(C_GBK)},
247         {N_("/_View/Character _encoding/Traditional Chinese (_Big5)"),
248          ENC_ACTION(C_BIG5)},
249         {N_("/_View/Character _encoding/Traditional Chinese (EUC-_TW)"),
250          ENC_ACTION(C_EUC_TW)},
251         {N_("/_View/Character _encoding/Chinese (ISO-2022-_CN)"),
252          ENC_ACTION(C_ISO_2022_CN)},
253         ENC_SEPARATOR,
254         {N_("/_View/Character _encoding/Korean (EUC-_KR)"),
255          ENC_ACTION(C_EUC_KR)},
256         {N_("/_View/Character _encoding/Korean (ISO-2022-KR)"),
257          ENC_ACTION(C_ISO_2022_KR)},
258         ENC_SEPARATOR,
259         {N_("/_View/Character _encoding/Thai (TIS-620)"),
260          ENC_ACTION(C_TIS_620)},
261         {N_("/_View/Character _encoding/Thai (Windows-874)"),
262          ENC_ACTION(C_WINDOWS_874)},
263
264 #undef ENC_SEPARATOR
265 #undef ENC_ACTION
266
267 #define DEC_SEPARATOR \
268         {N_("/_View/Decode/---"),               NULL, NULL, 0, "<Separator>"}
269 #define DEC_ACTION(action) \
270          NULL, set_decode_cb, action, "/View/Decode/Auto detect"
271         {N_("/_View/Decode"),           NULL, NULL, 0, "<Branch>"},
272         {N_("/_View/Decode/_Auto detect"),
273          NULL, set_decode_cb, 0, "<RadioItem>"},
274         {N_("/_View/Decode/---"),               NULL, NULL, 0, "<Separator>"},
275         {N_("/_View/Decode/_8bit"),             DEC_ACTION(ENC_8BIT)},
276         {N_("/_View/Decode/_Quoted printable"), DEC_ACTION(ENC_QUOTED_PRINTABLE)},
277         {N_("/_View/Decode/_Base64"),           DEC_ACTION(ENC_BASE64)},
278         {N_("/_View/Decode/_Uuencode"),         DEC_ACTION(ENC_X_UUENCODE)},
279
280 #undef DEC_SEPARATOR
281 #undef DEC_ACTION
282
283         {N_("/_View/---"),              NULL, NULL, 0, "<Separator>"},
284         {N_("/_View/Mess_age source"),  "<control>U", view_source_cb, 0, NULL},
285         {N_("/_View/Show all _headers"),"<control>H", show_all_header_cb, 0, "<ToggleItem>"},
286         {N_("/_View/Quotes"),                   NULL, NULL, 0, "<Branch>"},
287         {N_("/_View/Quotes/_Fold all"),         "<control><shift>Q", msg_hide_quotes_cb, 1, "<ToggleItem>"},
288         {N_("/_View/Quotes/Fold from level _2"),NULL, msg_hide_quotes_cb, 2, "<ToggleItem>"},
289         {N_("/_View/Quotes/Fold from level _3"),NULL, msg_hide_quotes_cb, 3, "<ToggleItem>"},
290
291         {N_("/_Message"),               NULL, NULL, 0, "<Branch>"},
292         {N_("/_Message/Compose _new message"),
293                                         "<control>M", compose_cb, 0, NULL},
294         {N_("/_Message/---"),           NULL, NULL, 0, "<Separator>"},
295         {N_("/_Message/_Reply"),        "<control>R", reply_cb, COMPOSE_REPLY, NULL},
296         {N_("/_Message/Repl_y to/_all"),
297                                         "<control><shift>R", reply_cb, COMPOSE_REPLY_TO_ALL, NULL},
298         {N_("/_Message/Repl_y to/_sender"),
299                                         NULL, reply_cb, COMPOSE_REPLY_TO_SENDER, NULL},
300         {N_("/_Message/Repl_y to/mailing _list"),
301                                         "<control>L", reply_cb, COMPOSE_REPLY_TO_LIST, NULL},
302         {N_("/_Message/---"),           NULL, NULL, 0, "<Separator>"},
303         {N_("/_Message/_Forward"),      "<control><alt>F", reply_cb, COMPOSE_FORWARD_INLINE, NULL},
304         {N_("/_Message/For_ward as attachment"),
305                                         NULL, reply_cb, COMPOSE_FORWARD_AS_ATTACH, NULL},
306         {N_("/_Message/Redirec_t"),     NULL, reply_cb, COMPOSE_REDIRECT, NULL},
307
308         {N_("/_Tools"),                 NULL, NULL, 0, "<Branch>"},
309         {N_("/_Tools/_Address book"),   "<control><shift>A", addressbook_open_cb, 0, NULL},
310         {N_("/_Tools/Add sender to address boo_k"),
311                                         NULL, add_address_cb, 0, NULL},
312         {N_("/_Tools/---"),             NULL, NULL, 0, "<Separator>"},
313         {N_("/_Tools/_Create filter rule"),
314                                         NULL, NULL, 0, "<Branch>"},
315         {N_("/_Tools/_Create filter rule/_Automatically"),
316                                         NULL, create_filter_cb, FILTER_BY_AUTO, NULL},
317         {N_("/_Tools/_Create filter rule/by _From"),
318                                         NULL, create_filter_cb, FILTER_BY_FROM, NULL},
319         {N_("/_Tools/_Create filter rule/by _To"),
320                                         NULL, create_filter_cb, FILTER_BY_TO, NULL},
321         {N_("/_Tools/_Create filter rule/by _Subject"),
322                                         NULL, create_filter_cb, FILTER_BY_SUBJECT, NULL},
323         {N_("/_Tools/Create processing rule"),
324                                         NULL, NULL, 0, "<Branch>"},
325         {N_("/_Tools/Create processing rule/_Automatically"),
326                                         NULL, create_processing_cb, FILTER_BY_AUTO, NULL},
327         {N_("/_Tools/Create processing rule/by _From"),
328                                         NULL, create_processing_cb, FILTER_BY_FROM, NULL},
329         {N_("/_Tools/Create processing rule/by _To"),
330                                         NULL, create_processing_cb, FILTER_BY_TO, NULL},
331         {N_("/_Tools/Create processing rule/by _Subject"),
332                                         NULL, create_processing_cb, FILTER_BY_SUBJECT, NULL},
333         {N_("/_Tools/---"),             NULL, NULL, 0, "<Separator>"},
334         {N_("/_Tools/List _URLs..."),   "<shift><control>U", open_urls_cb, 0, NULL},
335         {N_("/_Tools/---"),             NULL, NULL, 0, "<Separator>"},
336         {N_("/_Tools/Actio_ns"),        NULL, NULL, 0, "<Branch>"},
337
338         {N_("/_Help"),                  NULL, NULL, 0, "<Branch>"},
339         {N_("/_Help/_About"),           NULL, about_cb, 0, NULL}
340 };
341
342 MessageView *messageview_create(MainWindow *mainwin)
343 {
344         MessageView *messageview;
345         GtkWidget *vbox;
346         HeaderView *headerview;
347         MimeView *mimeview;
348         NoticeView *noticeview;
349
350         debug_print("Creating message view...\n");
351         messageview = g_new0(MessageView, 1);
352
353         headerview = headerview_create();
354
355         noticeview = noticeview_create(mainwin);
356
357         mimeview = mimeview_create(mainwin);
358         mimeview->textview = textview_create();
359         mimeview->textview->messageview = messageview;
360         mimeview->messageview = messageview;
361
362         vbox = gtk_vbox_new(FALSE, 0);
363         gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET_PTR(headerview),
364                            FALSE, FALSE, 0);
365         gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET_PTR(noticeview),
366                            FALSE, FALSE, 0);
367         gtk_box_pack_start(GTK_BOX(vbox),
368                            GTK_WIDGET_PTR(mimeview), TRUE, TRUE, 0);
369         gtk_widget_show(vbox);
370
371         messageview->vbox        = vbox;
372         messageview->new_window  = FALSE;
373         messageview->window      = NULL;
374         messageview->headerview  = headerview;
375         messageview->mimeview    = mimeview;
376         messageview->noticeview = noticeview;
377         messageview->mainwin    = mainwin;
378
379         messageview->statusbar     = NULL;
380         messageview->statusbar_cid = 0;
381
382         messageview->msginfo_update_callback_id =
383                 hooks_register_hook(MSGINFO_UPDATE_HOOKLIST, messageview_update_msg, (gpointer) messageview);
384
385         return messageview;
386 }
387
388 GList *messageview_get_msgview_list(void)
389 {
390         return msgview_list;
391 }
392
393 void messageview_update_actions_menu(MessageView *msgview)
394 {
395         GtkItemFactory *ifactory;
396
397         /* Messages opened in a new window do not have a menu bar */
398         if (msgview->menubar == NULL)
399                 return;
400         ifactory = gtk_item_factory_from_widget(msgview->menubar);
401         action_update_msgview_menu(ifactory, "/Tools/Actions", msgview);
402 }
403
404 void messageview_add_toolbar(MessageView *msgview, GtkWidget *window) 
405 {
406         GtkWidget *handlebox;
407         GtkWidget *vbox;
408         GtkWidget *menubar;
409         GtkWidget *statusbar = NULL;
410         guint n_menu_entries;
411
412         vbox = gtk_vbox_new(FALSE, 0);
413         gtk_widget_show(vbox);
414         gtk_container_add(GTK_CONTAINER(window), vbox); 
415
416         n_menu_entries = sizeof(msgview_entries) / sizeof(msgview_entries[0]);
417         menubar = menubar_create(window, msgview_entries,
418                                  n_menu_entries, "<MessageView>", msgview);
419         gtk_widget_show(menubar);
420         gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, TRUE, 0);
421
422         if (prefs_common.toolbar_detachable) {
423                 handlebox = gtk_handle_box_new();
424         } else {
425                 handlebox = gtk_hbox_new(FALSE, 0);
426         }
427         gtk_box_pack_start(GTK_BOX(vbox), handlebox, FALSE, FALSE, 0);
428         gtk_widget_realize(handlebox);
429 #ifdef MAEMO
430         msgview->toolbar = toolbar_create(TOOLBAR_MSGVIEW, window,
431                                           (gpointer)msgview);
432         msgview->statusbar = NULL;
433         msgview->statusbar_cid = 0;
434 #else
435         msgview->toolbar = toolbar_create(TOOLBAR_MSGVIEW, handlebox,
436                                           (gpointer)msgview);
437         statusbar = gtk_statusbar_new();
438         gtk_widget_show(statusbar);
439         gtk_box_pack_end(GTK_BOX(vbox), statusbar, FALSE, FALSE, 0);
440         msgview->statusbar = statusbar;
441         msgview->statusbar_cid = gtk_statusbar_get_context_id
442                 (GTK_STATUSBAR(statusbar), "Message View");
443 #endif
444
445
446         msgview->handlebox = handlebox;
447         msgview->menubar   = menubar;
448
449         gtk_container_add(GTK_CONTAINER(vbox),
450                           GTK_WIDGET_PTR(msgview));
451
452         messageview_update_actions_menu(msgview);
453
454         msgview_list = g_list_append(msgview_list, msgview);
455 }
456
457 static MessageView *messageview_create_with_new_window_visible(MainWindow *mainwin, gboolean show)
458 {
459         MessageView *msgview;
460         GtkWidget *window;
461         static GdkGeometry geometry;
462
463         window = gtkut_window_new(GTK_WINDOW_TOPLEVEL, "messageview");
464         gtk_window_set_title(GTK_WINDOW(window), _("Claws Mail - Message View"));
465         gtk_window_set_resizable(GTK_WINDOW(window), TRUE);
466
467         if (!geometry.min_height) {
468                 geometry.min_width = 320;
469                 geometry.min_height = 200;
470         }
471         gtk_window_set_geometry_hints(GTK_WINDOW(window), NULL, &geometry,
472                                       GDK_HINT_MIN_SIZE);
473
474         gtk_widget_set_size_request(window, prefs_common.msgwin_width,
475                                     prefs_common.msgwin_height);
476
477         msgview = messageview_create(mainwin);
478
479         g_signal_connect(G_OBJECT(window), "size_allocate",
480                          G_CALLBACK(messageview_size_allocate_cb),
481                          msgview);
482         g_signal_connect(G_OBJECT(window), "delete_event",
483                          G_CALLBACK(messageview_delete_cb), msgview);
484 #ifdef MAEMO
485         maemo_connect_key_press_to_mainwindow(GTK_WINDOW(window));
486 #else
487         g_signal_connect(G_OBJECT(window), "key_press_event",
488                          G_CALLBACK(key_pressed), msgview);
489 #endif
490         messageview_add_toolbar(msgview, window);
491
492         if (show) {
493                 gtk_widget_grab_focus(msgview->mimeview->textview->text);
494                 gtk_widget_show(window);
495         } else {
496                 gtk_widget_realize(window);
497         }
498
499         msgview->new_window = TRUE;
500         msgview->window = window;
501         msgview->visible = TRUE;
502
503         toolbar_set_style(msgview->toolbar->toolbar, msgview->handlebox, 
504                           prefs_common.toolbar_style);
505         messageview_init(msgview);
506
507         return msgview;
508 }
509
510 MessageView *messageview_create_with_new_window(MainWindow *mainwin)
511 {
512         return messageview_create_with_new_window_visible(mainwin, TRUE);
513 }
514 void messageview_init(MessageView *messageview)
515 {
516         headerview_init(messageview->headerview);
517         mimeview_init(messageview->mimeview);
518         /*messageview_set_font(messageview);*/
519
520         noticeview_hide(messageview->noticeview);
521 }
522
523 static void notification_convert_header(gchar *dest, gint len, 
524                                         const gchar *src_,
525                                         gint header_len)
526 {
527         char *src;
528
529         g_return_if_fail(src_ != NULL);
530         g_return_if_fail(dest != NULL);
531
532         if (len < 1) return;
533
534         Xstrndup_a(src, src_, len, return);
535
536         remove_return(src);
537
538         if (is_ascii_str(src)) {
539                 strncpy2(dest, src, len);
540                 dest[len - 1] = '\0';
541                 return;
542         } else
543                 conv_encode_header(dest, len, src, header_len, FALSE);
544 }
545
546 static gint disposition_notification_send(MsgInfo *msginfo)
547 {
548         gchar buf[BUFFSIZE];
549         gchar tmp[MAXPATHLEN + 1];
550         FILE *fp;
551         GList *ac_list;
552         PrefsAccount *account = NULL;
553         gint ok;
554         gchar *to;
555         FolderItem *queue, *outbox;
556         gint num;
557         gchar *path;
558         gchar *addr;
559         gchar *addrp;
560         gchar *foo = NULL;
561         gboolean queued_removed = FALSE;
562         
563         if (!msginfo->extradata)
564                 return -1;
565         if (!msginfo->extradata->returnreceiptto && 
566             !msginfo->extradata->dispositionnotificationto) 
567                 return -1;
568
569         /* RFC2298: Test for Return-Path */
570         if (msginfo->extradata->dispositionnotificationto)
571                 to = msginfo->extradata->dispositionnotificationto;
572         else
573                 to = msginfo->extradata->returnreceiptto;
574
575         ok = procheader_get_header_from_msginfo(msginfo, buf, sizeof(buf),
576                                 "Return-Path:");
577         if (ok == 0) {
578                 gchar *to_addr = g_strdup(to);
579                 extract_address(to_addr);
580                 extract_address(buf);
581                 ok = strcasecmp(to_addr, buf);
582                 g_free(to_addr);
583         } else {
584                 strncpy(buf, _("<No Return-Path found>"), 
585                                 sizeof(buf));
586         }
587         
588         if (ok != 0) {
589                 AlertValue val;
590                 gchar *message;
591                 message = g_markup_printf_escaped(
592                   _("The notification address to which the return receipt is\n"
593                     "to be sent does not correspond to the return path:\n"
594                     "Notification address: %s\n"
595                     "Return path: %s\n"
596                     "It is advised to not to send the return receipt."),
597                   to, buf);
598                 val = alertpanel_full(_("Warning"), message,
599                                 _("_Don't Send"), _("_Send"), NULL, FALSE,
600                                 NULL, ALERT_WARNING, G_ALERTDEFAULT);
601                 g_free(message);                                
602                 if (val != G_ALERTALTERNATE)
603                         return -1;
604         }
605
606         ac_list = account_find_all_from_address(NULL, msginfo->to);
607         ac_list = account_find_all_from_address(ac_list, msginfo->cc);
608
609         if (ac_list == NULL) {
610                 AlertValue val = 
611                 alertpanel_full(_("Warning"),
612                   _("This message is asking for a return receipt notification\n"
613                     "but according to its 'To:' and 'CC:' headers it was not\n"
614                     "officially addressed to you.\n"
615                     "It is advised to not to send the return receipt."),
616                   _("_Don't Send"), _("_Send"), NULL, FALSE,
617                   NULL, ALERT_WARNING, G_ALERTDEFAULT);
618                 if (val != G_ALERTALTERNATE)
619                         return -1;
620         }
621
622         if (g_list_length(ac_list) > 1) {
623                 if ((account = select_account_from_list(ac_list)) == NULL)
624                         return -1;
625         }
626         else if (ac_list != NULL)
627                 account = (PrefsAccount *) ac_list->data;
628         g_list_free(ac_list);
629
630         if (account == NULL)
631                 account = account_get_default();
632         if (!account || account->protocol == A_NNTP) {
633                 alertpanel_error(_("Account for sending mail is not specified.\n"
634                                    "Please select a mail account before sending."));
635                 return -1;
636         }
637
638         /* write to temporary file */
639         g_snprintf(tmp, sizeof(tmp), "%s%ctmpmsg%p",
640                    get_rc_dir(), G_DIR_SEPARATOR, msginfo);
641
642         if ((fp = g_fopen(tmp, "wb")) == NULL) {
643                 FILE_OP_ERROR(tmp, "fopen");
644                 return -1;
645         }
646
647         /* chmod for security */
648         if (change_file_mode_rw(fp, tmp) < 0) {
649                 FILE_OP_ERROR(tmp, "chmod");
650                 g_warning("can't change file mode\n");
651         }
652         
653         addr = g_strdup(to);
654         
655         extract_address(addr);
656         addrp = addr;
657         
658         /* write queue headers */
659         fprintf(fp, "AF:\n");
660         fprintf(fp, "NF:0\n");
661         fprintf(fp, "PS:10\n");
662         fprintf(fp, "SRH:1\n");
663         fprintf(fp, "SFN:\n");
664         fprintf(fp, "DSR:\n");
665         fprintf(fp, "MID:\n");
666         fprintf(fp, "CFG:\n");
667         fprintf(fp, "PT:0\n");
668         fprintf(fp, "S:%s\n", account->address);
669         fprintf(fp, "RQ:\n");
670         if (account->smtp_server)
671                 fprintf(fp, "SSV:%s\n", account->smtp_server);
672         else
673                 fprintf(fp, "SSV:\n");
674         fprintf(fp, "SSH:\n");
675         fprintf(fp, "R:<%s>\n", addrp);
676         
677         g_free(addrp);
678         
679         /* check whether we need to save the message */
680         outbox = account_get_special_folder(account, F_OUTBOX); 
681         if (folder_get_default_outbox() == outbox && !prefs_common.savemsg)
682                 outbox = NULL;
683         if (outbox) {
684                 path = folder_item_get_identifier(outbox);
685                 fprintf(fp, "SCF:%s\n", path);
686                 g_free(path);
687         }               
688
689         fprintf(fp, "X-Claws-End-Special-Headers: 1\n");
690         
691         /* Date */
692         get_rfc822_date(buf, sizeof(buf));
693         fprintf(fp, "Date: %s\n", buf);
694
695         /* From */
696         if (account->name && *account->name) {
697                 notification_convert_header
698                         (buf, sizeof(buf), account->name,
699                          strlen("From: "));
700                 fprintf(fp, "From: %s <%s>\n", buf, account->address);
701         } else
702                 fprintf(fp, "From: %s\n", account->address);
703
704         fprintf(fp, "To: %s\n", to);
705
706         /* Subject */
707         notification_convert_header(buf, sizeof(buf), msginfo->subject,
708                                     strlen("Subject: "));
709         fprintf(fp, "Subject: Disposition notification: %s\n", buf);
710
711         /* Message ID */
712         generate_msgid(buf, sizeof(buf));
713         fprintf(fp, "Message-ID: <%s>\n", buf);
714
715         if (fclose(fp) == EOF) {
716                 FILE_OP_ERROR(tmp, "fclose");
717                 g_unlink(tmp);
718                 return -1;
719         }
720
721         /* put it in queue */
722         queue = account_get_special_folder(account, F_QUEUE);
723         if (!queue) queue = folder_get_default_queue();
724         if (!queue) {
725                 g_warning("can't find queue folder\n");
726                 g_unlink(tmp);
727                 return -1;
728         }
729         folder_item_scan(queue);
730         if ((num = folder_item_add_msg(queue, tmp, NULL, TRUE)) < 0) {
731                 g_warning("can't queue the message\n");
732                 g_unlink(tmp);
733                 return -1;
734         }
735                 
736         if (prefs_common.work_offline && 
737             !inc_offline_should_override(TRUE,
738                 _("Claws Mail needs network access in order "
739                   "to send this email.")))
740                 return 0;
741
742         /* send it */
743         path = folder_item_fetch_msg(queue, num);
744         ok = procmsg_send_message_queue(path, &foo, queue, num, &queued_removed);
745         g_free(path);
746         g_free(foo);
747         if (ok == 0 && !queued_removed)
748                 folder_item_remove_msg(queue, num);
749
750         return ok;
751 }
752
753 static gboolean find_encrypted_func(GNode *node, gpointer data)
754 {
755         MimeInfo *mimeinfo = (MimeInfo *) node->data;
756         MimeInfo **encinfo = (MimeInfo **) data;
757         
758         if (privacy_mimeinfo_is_encrypted(mimeinfo)) {
759                 *encinfo = mimeinfo;
760                 return TRUE;
761         }
762         
763         return FALSE;
764 }
765
766 static MimeInfo *find_encrypted_part(MimeInfo *rootinfo)
767 {
768         MimeInfo *encinfo = NULL;
769
770         g_node_traverse(rootinfo->node, G_IN_ORDER, G_TRAVERSE_ALL, -1,
771                 find_encrypted_func, &encinfo);
772         
773         return encinfo;
774 }
775
776 gint messageview_show(MessageView *messageview, MsgInfo *msginfo,
777                       gboolean all_headers)
778 {
779         gchar *file;
780         MimeInfo *mimeinfo, *encinfo;
781         gchar *subject = NULL;
782         g_return_val_if_fail(msginfo != NULL, -1);
783
784         if (messageview->mimeview->textview &&
785             messageview->mimeview->textview->loading) {
786                 messageview->mimeview->textview->stop_loading = TRUE;
787                 return 0;
788         }
789
790         if (messageview->toolbar)
791                 toolbar_set_learn_button
792                         (messageview->toolbar,
793                          MSG_IS_SPAM(msginfo->flags)?LEARN_HAM:LEARN_SPAM);
794         else
795                 toolbar_set_learn_button
796                         (messageview->mainwin->toolbar,
797                          MSG_IS_SPAM(msginfo->flags)?LEARN_HAM:LEARN_SPAM);
798
799         if (messageview->toolbar) {
800                 if (messageview->toolbar->learn_spam_btn)
801                         gtk_widget_set_sensitive(
802                                 messageview->toolbar->learn_spam_btn, 
803                                 procmsg_spam_can_learn());
804         }
805         messageview->updating = TRUE;
806         mimeinfo = procmime_scan_message(msginfo);
807         messageview->updating = FALSE;
808         
809         if (messageview->deferred_destroy) {
810                 messageview_destroy(messageview);
811                 return 0;
812         }
813
814         if (!mimeinfo) {
815                 textview_show_error(messageview->mimeview->textview);
816                 return -1;
817         }
818
819         while ((encinfo = find_encrypted_part(mimeinfo)) != NULL) {
820                 debug_print("decrypting message part\n");
821                 if (privacy_mimeinfo_decrypt(encinfo) < 0) {
822                         alertpanel_error(_("Couldn't decrypt: %s"),
823                                 privacy_get_error());
824                         break;
825                 }
826         }
827         
828         messageview->updating = TRUE;
829         file = procmsg_get_message_file_path(msginfo);
830         messageview->updating = FALSE;
831         
832         if (messageview->deferred_destroy) {
833                 g_free(file);
834                 messageview_destroy(messageview);
835                 return 0;
836         }
837
838         if (!file) {
839                 g_warning("can't get message file path.\n");
840                 procmime_mimeinfo_free_all(mimeinfo);
841                 textview_show_error(messageview->mimeview->textview);
842                 return -1;
843         }
844         
845         if (messageview->msginfo != msginfo) {
846                 procmsg_msginfo_free(messageview->msginfo);
847                 messageview->msginfo = NULL;
848                 messageview_set_menu_sensitive(messageview);
849                 messageview->msginfo = procmsg_msginfo_get_full_info(msginfo);
850                 if (!messageview->msginfo)
851                         messageview->msginfo = procmsg_msginfo_copy(msginfo);
852         } else {
853                 messageview->msginfo = NULL;
854                 messageview_set_menu_sensitive(messageview);
855                 messageview->msginfo = msginfo;
856         }
857         headerview_show(messageview->headerview, messageview->msginfo);
858
859         messageview_set_position(messageview, 0);
860
861         textview_set_all_headers(messageview->mimeview->textview, 
862                         messageview->all_headers);
863
864 #ifdef MAEMO
865         maemo_window_full_screen_if_needed(GTK_WINDOW(messageview->window));
866 #endif
867         if (messageview->window) {
868                 gtk_window_set_title(GTK_WINDOW(messageview->window), 
869                                 _("Claws Mail - Message View"));
870                 GTK_EVENTS_FLUSH();
871         }
872         mimeview_show_message(messageview->mimeview, mimeinfo, file);
873         
874         messageview_set_position(messageview, 0);
875
876         if (messageview->window && msginfo->subject) {
877                 subject = g_strdup(msginfo->subject);
878                 if (!g_utf8_validate(subject, -1, NULL)) {
879                         g_free(subject);
880                         subject = g_malloc(strlen(msginfo->subject)*2 +1);
881                         conv_localetodisp(subject, strlen(msginfo->subject)*2 +1, 
882                                 msginfo->subject);
883                 }
884                 if (g_utf8_validate(subject, -1, NULL))
885                         gtk_window_set_title(GTK_WINDOW(messageview->window), 
886                                 subject);
887                 g_free(subject);
888         }
889
890         if (msginfo && msginfo->folder) {
891                 msginfo->folder->last_seen = msginfo->msgnum;   
892         }
893
894         main_create_mailing_list_menu(messageview->mainwin, messageview->msginfo);
895
896         if (messageview->msginfo && messageview->msginfo->extradata
897             && messageview->msginfo->extradata->partial_recv)
898                 partial_recv_show(messageview->noticeview, 
899                                   messageview->msginfo);
900         else if (messageview->msginfo && messageview->msginfo->extradata &&
901             (messageview->msginfo->extradata->dispositionnotificationto || 
902              messageview->msginfo->extradata->returnreceiptto) &&
903             !MSG_IS_RETRCPT_SENT(messageview->msginfo->flags) &&
904             !prefs_common.never_send_retrcpt)
905                 return_receipt_show(messageview->noticeview, 
906                                     messageview->msginfo);
907         else 
908                 noticeview_hide(messageview->noticeview);
909
910         mimeinfo = procmime_mimeinfo_next(mimeinfo);
911         if (!all_headers && mimeinfo 
912                         && (mimeinfo->type != MIMETYPE_TEXT || 
913             strcasecmp(mimeinfo->subtype, "plain")) 
914                         && (mimeinfo->type != MIMETYPE_MULTIPART || 
915             strcasecmp(mimeinfo->subtype, "signed"))) {
916                 if (strcasecmp(mimeinfo->subtype, "html"))
917                         mimeview_show_part(messageview->mimeview,mimeinfo);
918                 else if (prefs_common.invoke_plugin_on_html)
919                         mimeview_select_mimepart_icon(messageview->mimeview,mimeinfo);
920         }
921
922         g_free(file);
923
924         return 0;
925 }
926
927 void messageview_reflect_prefs_pixmap_theme(void)
928 {
929         GList *cur;
930         MessageView *msgview;
931
932         for (cur = msgview_list; cur != NULL; cur = cur->next) {
933                 msgview = (MessageView*)cur->data;
934                 toolbar_update(TOOLBAR_MSGVIEW, msgview);
935                 mimeview_update(msgview->mimeview);
936         }
937 }
938
939 void messageview_clear(MessageView *messageview)
940 {
941         if (!messageview)
942                 return;
943         procmsg_msginfo_free(messageview->msginfo);
944         messageview->msginfo = NULL;
945         messageview->filtered = FALSE;
946         mimeview_clear(messageview->mimeview);
947         headerview_clear(messageview->headerview);
948         noticeview_hide(messageview->noticeview);
949 }
950
951 void messageview_destroy(MessageView *messageview)
952 {
953         debug_print("destroy messageview\n");
954         messageview_list = g_list_remove(messageview_list, messageview);
955
956         if (messageview->mainwin->summaryview->messageview == messageview)
957                 messageview->mainwin->summaryview->messageview = NULL;
958
959         if (messageview->mainwin->summaryview->ext_messageview == messageview)
960                 messageview->mainwin->summaryview->ext_messageview = NULL;
961
962         if (!messageview->deferred_destroy) {
963                 hooks_unregister_hook(MSGINFO_UPDATE_HOOKLIST,
964                               messageview->msginfo_update_callback_id);
965         }
966
967         if (messageview->updating) {
968                 debug_print("uh oh, better not touch that now (fetching)\n");
969                 messageview->deferred_destroy = TRUE;
970                 gtk_widget_hide(messageview->window);
971                 return;
972         }
973         
974         if (messageview->mimeview->textview
975         &&  messageview->mimeview->textview->loading) {
976                 debug_print("uh oh, better not touch that now (loading text)\n");
977                 messageview->deferred_destroy = TRUE;
978                 messageview->mimeview->textview->stop_loading = TRUE;
979                 gtk_widget_hide(messageview->window);
980                 return;
981         }
982
983         headerview_destroy(messageview->headerview);
984         mimeview_destroy(messageview->mimeview);
985         noticeview_destroy(messageview->noticeview);
986
987         procmsg_msginfo_free(messageview->msginfo);
988         toolbar_clear_list(TOOLBAR_MSGVIEW);
989         if (messageview->toolbar) {
990                 toolbar_destroy(messageview->toolbar);
991                 g_free(messageview->toolbar);
992         }
993         
994         msgview_list = g_list_remove(msgview_list, messageview); 
995
996         if (messageview->window)
997                 gtk_widget_destroy(messageview->window);
998         g_free(messageview);
999 }
1000
1001 void messageview_delete(MessageView *msgview)
1002 {
1003         MsgInfo *msginfo = NULL;
1004         FolderItem *trash = NULL;
1005         PrefsAccount *ac = NULL;
1006
1007         if (msgview->msginfo && msgview->mainwin && msgview->mainwin->summaryview)
1008                 msginfo = summary_get_selected_msg(msgview->mainwin->summaryview);
1009         
1010         /* need a procmsg_msginfo_equal() */
1011         if (msginfo && msgview->msginfo && 
1012             msginfo->msgnum == msgview->msginfo->msgnum && 
1013             msginfo->folder == msgview->msginfo->folder) {
1014                 summary_delete_trash(msgview->mainwin->summaryview);
1015         } else {                
1016                 msginfo = msgview->msginfo;
1017
1018                 g_return_if_fail(msginfo != NULL);
1019
1020                 /* to get the trash folder, we have to choose either
1021                  * the folder's or account's trash default - we prefer
1022                  * the one in the account prefs */
1023                 if (msginfo->folder) {
1024                         if (NULL != (ac = account_find_from_item(msginfo->folder)))
1025                                 trash = account_get_special_folder(ac, F_TRASH);
1026                         if (!trash && msginfo->folder->folder)  
1027                                 trash = msginfo->folder->folder->trash;
1028                         /* if still not found, use the default */
1029                         if (!trash) 
1030                                 trash = folder_get_default_trash();
1031                 }       
1032
1033                 g_return_if_fail(trash != NULL);
1034
1035                 if (prefs_common.immediate_exec)
1036                         /* TODO: Delete from trash */
1037                         folder_item_move_msg(trash, msginfo);
1038                 else {
1039                         procmsg_msginfo_set_to_folder(msginfo, trash);
1040                         procmsg_msginfo_set_flags(msginfo, MSG_DELETED, 0);
1041                         /* NOTE: does not update to next message in summaryview */
1042                 }
1043         }
1044 #ifdef MAEMO
1045         if (msgview->window) {
1046                 messageview_destroy(msgview);
1047         }
1048 #endif
1049 }
1050
1051 /* 
1052  * \brief update messageview with currently selected message in summaryview
1053  *        leave unchanged if summaryview is empty
1054  * \param pointer to MessageView
1055  */     
1056 static void messageview_update(MessageView *msgview, MsgInfo *old_msginfo)
1057 {
1058         SummaryView *summaryview = (SummaryView*)msgview->mainwin->summaryview;
1059
1060         g_return_if_fail(summaryview != NULL);
1061         
1062         if (summaryview->selected) {
1063                 MsgInfo *msginfo = summary_get_selected_msg(summaryview);
1064                 if (msginfo == NULL || msginfo == old_msginfo)
1065                         return;
1066
1067                 messageview_show(msgview, msginfo, 
1068                                  msgview->all_headers);
1069         } 
1070 }
1071
1072 void messageview_quote_color_set(void)
1073 {
1074 }
1075
1076 void messageview_set_font(MessageView *messageview)
1077 {
1078 }
1079
1080 TextView *messageview_get_current_textview(MessageView *messageview)
1081 {
1082         TextView *text = NULL;
1083
1084         text = messageview->mimeview->textview;
1085
1086         return text;
1087 }
1088
1089 MimeInfo *messageview_get_selected_mime_part(MessageView *messageview)
1090 {
1091         return mimeview_get_selected_part(messageview->mimeview);
1092 }
1093
1094 void messageview_copy_clipboard(MessageView *messageview)
1095 {
1096         gchar *text = messageview_get_selection(messageview);
1097         if (text) {
1098                 gtk_clipboard_set_text(
1099                         gtk_clipboard_get(GDK_SELECTION_CLIPBOARD),
1100                         text, -1);
1101         }
1102         g_free(text);
1103 }
1104
1105 void messageview_select_all(MessageView *messageview)
1106 {
1107         TextView *text;
1108
1109         text = messageview_get_current_textview(messageview);
1110         if (text) {
1111                 GtkTextView *textview = GTK_TEXT_VIEW(text->text);
1112                 GtkTextBuffer *buffer;
1113                 GtkTextIter start, end;
1114
1115                 buffer = gtk_text_view_get_buffer(textview);
1116                 gtk_text_buffer_get_bounds(buffer, &start, &end);
1117                 gtk_text_buffer_select_range(buffer, &start, &end);
1118         }
1119 }
1120
1121 void messageview_set_position(MessageView *messageview, gint pos)
1122 {
1123         TextView *text;
1124
1125         text = messageview_get_current_textview(messageview);
1126         if (text)
1127                 textview_set_position(text, pos);
1128 }
1129
1130 gboolean messageview_search_string(MessageView *messageview, const gchar *str,
1131                                    gboolean case_sens)
1132 {
1133         TextView *text;
1134
1135         if (messageview->mimeview->type == MIMEVIEW_VIEWER) {
1136                 MimeViewer *viewer = messageview->mimeview->mimeviewer;
1137                 if (viewer && viewer->text_search) {
1138                         return viewer->text_search(viewer, FALSE, str, case_sens);
1139                 }
1140         }
1141
1142         text = messageview_get_current_textview(messageview);
1143         if (text)
1144                 return textview_search_string(text, str, case_sens);
1145         return FALSE;
1146 }
1147
1148 gboolean messageview_search_string_backward(MessageView *messageview,
1149                                             const gchar *str,
1150                                             gboolean case_sens)
1151 {
1152         TextView *text;
1153
1154         if (messageview->mimeview->type == MIMEVIEW_VIEWER) {
1155                 MimeViewer *viewer = messageview->mimeview->mimeviewer;
1156                 if (viewer && viewer->text_search) {
1157                         return viewer->text_search(viewer, TRUE, str, case_sens);
1158                 }
1159         }
1160
1161         text = messageview_get_current_textview(messageview);
1162         if (text)       
1163                 return textview_search_string_backward(text,
1164                                                        str, case_sens);
1165         return FALSE;
1166 }
1167
1168 gboolean messageview_is_visible(MessageView *messageview)
1169 {
1170         if (messageview == NULL)
1171                 return FALSE;
1172         return messageview->visible;
1173 }
1174
1175 static void messageview_save_as(MessageView *messageview)
1176 {
1177         gchar *filename = NULL;
1178         MsgInfo *msginfo;
1179         gchar *src, *dest, *tmp;
1180
1181         if (!messageview->msginfo) return;
1182         msginfo = messageview->msginfo;
1183
1184         if (msginfo->subject) {
1185                 Xstrdup_a(filename, msginfo->subject, return);
1186                 subst_for_filename(filename);
1187         }
1188         if (filename && !g_utf8_validate(filename, -1, NULL)) {
1189                 gchar *oldstr = filename;
1190                 filename = conv_codeset_strdup(filename,
1191                                                conv_get_locale_charset_str(),
1192                                                CS_UTF_8);
1193                 if (!filename) {
1194                         g_warning("messageview_save_as(): failed to convert character set.");
1195                         filename = g_strdup(oldstr);
1196                 }
1197                 dest = filesel_select_file_save(_("Save as"), filename);
1198                 g_free(filename);
1199         } else
1200                 dest = filesel_select_file_save(_("Save as"), filename);
1201         if (!dest) return;
1202         if (is_file_exist(dest)) {
1203                 AlertValue aval;
1204
1205                 aval = alertpanel(_("Overwrite"),
1206                                   _("Overwrite existing file?"),
1207                                   GTK_STOCK_CANCEL, GTK_STOCK_OK, NULL);
1208                 if (G_ALERTALTERNATE != aval) return;
1209         }
1210
1211         src = procmsg_get_message_file(msginfo);
1212         if (copy_file(src, dest, TRUE) < 0) {
1213                 tmp =  g_path_get_basename(dest);
1214                 alertpanel_error(_("Couldn't save the file '%s'."), tmp);
1215                 g_free(tmp);
1216         }
1217         g_free(dest);
1218         g_free(src);
1219 }
1220
1221 static gint messageview_delete_cb(GtkWidget *widget, GdkEventAny *event,
1222                                   MessageView *messageview)
1223 {
1224         messageview_destroy(messageview);
1225         return TRUE;
1226 }
1227
1228 static void messageview_size_allocate_cb(GtkWidget *widget,
1229                                          GtkAllocation *allocation)
1230 {
1231         g_return_if_fail(allocation != NULL);
1232
1233         prefs_common.msgwin_width  = allocation->width;
1234         prefs_common.msgwin_height = allocation->height;
1235 }
1236
1237 static gboolean key_pressed(GtkWidget *widget, GdkEventKey *event,
1238                         MessageView *messageview)
1239 {
1240         if (event && event->keyval == GDK_Escape && messageview->window) {
1241                 messageview_destroy(messageview);
1242                 return TRUE;
1243         }
1244
1245         if ((event->state & (GDK_MOD1_MASK|GDK_CONTROL_MASK)) != 0)
1246                 return FALSE;
1247
1248         g_signal_stop_emission_by_name(G_OBJECT(widget),
1249                                         "key_press_event");
1250         mimeview_pass_key_press_event(messageview->mimeview, event);
1251         return FALSE;
1252 }
1253
1254 static void return_receipt_show(NoticeView *noticeview, MsgInfo *msginfo)
1255 {
1256         gchar *addr = NULL;
1257         gboolean from_me = FALSE;
1258         if (msginfo->folder 
1259                 && (folder_has_parent_of_type(msginfo->folder, F_QUEUE)
1260                  || folder_has_parent_of_type(msginfo->folder, F_DRAFT)))
1261                 return;
1262
1263         addr = g_strdup(msginfo->from);
1264         if (addr) {
1265                 extract_address(addr);
1266                 if (account_find_from_address(addr)) {
1267                         from_me = TRUE;
1268                 }
1269                 g_free(addr);
1270         }
1271
1272         if (from_me) {
1273                 noticeview_set_icon(noticeview, STOCK_PIXMAP_NOTICE_WARN);
1274                 noticeview_set_text(noticeview, _("You asked for a return receipt in this message."));
1275                 noticeview_set_button_text(noticeview, NULL);
1276                 noticeview_set_button_press_callback(noticeview, NULL, NULL);
1277         } else {
1278                 noticeview_set_icon(noticeview, STOCK_PIXMAP_NOTICE_WARN);
1279                 noticeview_set_text(noticeview, _("This message asks for a return receipt."));
1280                 noticeview_set_button_text(noticeview, _("Send receipt"));
1281                 noticeview_set_button_press_callback(noticeview,
1282                                                      G_CALLBACK(return_receipt_send_clicked),
1283                                                      (gpointer) msginfo);
1284         }
1285         noticeview_show(noticeview);
1286 }
1287
1288 static void return_receipt_send_clicked(NoticeView *noticeview, MsgInfo *msginfo)
1289 {
1290         MsgInfo *tmpmsginfo;
1291         gchar *file;
1292
1293         file = procmsg_get_message_file_path(msginfo);
1294         if (!file) {
1295                 g_warning("can't get message file path.\n");
1296                 return;
1297         }
1298
1299         tmpmsginfo = procheader_parse_file(file, msginfo->flags, TRUE, TRUE);
1300         tmpmsginfo->folder = msginfo->folder;
1301         tmpmsginfo->msgnum = msginfo->msgnum;
1302
1303         if (disposition_notification_send(tmpmsginfo) >= 0) {
1304                 procmsg_msginfo_set_flags(msginfo, MSG_RETRCPT_SENT, 0);
1305                 noticeview_hide(noticeview);
1306         }               
1307
1308         procmsg_msginfo_free(tmpmsginfo);
1309         g_free(file);
1310 }
1311
1312 static void partial_recv_show(NoticeView *noticeview, MsgInfo *msginfo)
1313 {
1314         gchar *text = NULL;
1315         gchar *button1 = NULL;
1316         gchar *button2 = NULL;
1317         void  *button1_cb = NULL;
1318         void  *button2_cb = NULL;
1319
1320         if (!msginfo->extradata)
1321                 return;
1322         if (!partial_msg_in_uidl_list(msginfo)) {
1323                 text = g_strdup_printf(_("This message has been partially "
1324                                 "retrieved,\nand has been deleted from the "
1325                                 "server."));
1326         } else {
1327                 switch (msginfo->planned_download) {
1328                 case POP3_PARTIAL_DLOAD_UNKN:
1329                         text = g_strdup_printf(_("This message has been "
1330                                         "partially retrieved;\nit is %s."),
1331                                         to_human_readable(
1332                                                 (off_t)(msginfo->total_size)));
1333                         button1 = _("Mark for download");
1334                         button2 = _("Mark for deletion");
1335                         button1_cb = partial_recv_dload_clicked;
1336                         button2_cb = partial_recv_del_clicked;
1337                         break;
1338                 case POP3_PARTIAL_DLOAD_DLOAD:
1339                         text = g_strdup_printf(_("This message has been "
1340                                         "partially retrieved;\nit is %s and "
1341                                         "will be downloaded."),
1342                                         to_human_readable(
1343                                                 (off_t)(msginfo->total_size)));
1344                         button1 = _("Unmark");
1345                         button1_cb = partial_recv_unmark_clicked;
1346                         button2 = _("Mark for deletion");
1347                         button2_cb = partial_recv_del_clicked;
1348                         break;
1349                 case POP3_PARTIAL_DLOAD_DELE:
1350                         text = g_strdup_printf(_("This message has been "
1351                                         "partially retrieved;\nit is %s and "
1352                                         "will be deleted."),
1353                                         to_human_readable(
1354                                                 (off_t)(msginfo->total_size)));
1355                         button1 = _("Mark for download");
1356                         button1_cb = partial_recv_dload_clicked;
1357                         button2 = _("Unmark");
1358                         button2_cb = partial_recv_unmark_clicked;
1359                         break;
1360                 default:
1361                         return;
1362                 }
1363         }
1364         
1365         noticeview_set_icon(noticeview, STOCK_PIXMAP_NOTICE_WARN);
1366         noticeview_set_text(noticeview, text);
1367         g_free(text);
1368         noticeview_set_button_text(noticeview, button1);
1369         noticeview_set_button_press_callback(noticeview,
1370                      G_CALLBACK(button1_cb), (gpointer) msginfo);
1371
1372         noticeview_set_2ndbutton_text(noticeview, button2);
1373         noticeview_set_2ndbutton_press_callback(noticeview,
1374                      G_CALLBACK(button2_cb), (gpointer) msginfo);
1375
1376         noticeview_show(noticeview);
1377 }
1378
1379 static void partial_recv_dload_clicked(NoticeView *noticeview, 
1380                                        MsgInfo *msginfo)
1381 {
1382         if (partial_mark_for_download(msginfo) == 0) {
1383                 partial_recv_show(noticeview, msginfo);
1384         }
1385 }
1386
1387 static void partial_recv_del_clicked(NoticeView *noticeview, 
1388                                        MsgInfo *msginfo)
1389 {
1390         if (partial_mark_for_delete(msginfo) == 0) {
1391                 partial_recv_show(noticeview, msginfo);
1392         }
1393 }
1394
1395 static void partial_recv_unmark_clicked(NoticeView *noticeview, 
1396                                        MsgInfo *msginfo)
1397 {
1398         if (partial_unmark(msginfo) == 0) {
1399                 partial_recv_show(noticeview, msginfo);
1400         }
1401 }
1402
1403 static void select_account_cb(GtkWidget *w, gpointer data)
1404 {
1405         *(gint*)data = combobox_get_active_data(GTK_COMBO_BOX(w));
1406 }
1407
1408 static PrefsAccount *select_account_from_list(GList *ac_list)
1409 {
1410         GtkWidget *optmenu;
1411         gint account_id;
1412
1413         g_return_val_if_fail(ac_list != NULL, NULL);
1414         g_return_val_if_fail(ac_list->data != NULL, NULL);
1415         
1416         optmenu = gtkut_account_menu_new(ac_list,
1417                         G_CALLBACK(select_account_cb),
1418                         &account_id);
1419         if (!optmenu)
1420                 return NULL;
1421         account_id = ((PrefsAccount *) ac_list->data)->account_id;
1422         if (alertpanel_with_widget(
1423                                 _("Return Receipt Notification"),
1424                                 _("The message was sent to several of your "
1425                                   "accounts.\n"
1426                                   "Please choose which account do you want to "
1427                                   "use for sending the receipt notification:"),
1428                                 _("_Cancel"), _("_Send Notification"), NULL,
1429                                 FALSE, G_ALERTDEFAULT, optmenu) != G_ALERTALTERNATE)
1430                 return NULL;
1431         return account_find_from_id(account_id);
1432 }
1433
1434 /* 
1435  * \brief return selected messageview text, when nothing is 
1436  *        selected and message was filtered, return complete text
1437  *
1438  * \param  pointer to Messageview 
1439  *
1440  * \return pointer to text (needs to be free'd by calling func)
1441  */
1442 gchar *messageview_get_selection(MessageView *msgview)
1443 {
1444         TextView *textview;
1445         gchar *text = NULL;
1446         GtkTextView *edit = NULL;
1447         GtkTextBuffer *textbuf;
1448         gint body_pos = 0;
1449         
1450         g_return_val_if_fail(msgview != NULL, NULL);
1451
1452         if (msgview->mimeview->type == MIMEVIEW_VIEWER) {
1453                 MimeViewer *viewer = msgview->mimeview->mimeviewer;
1454                 if (viewer && viewer->get_selection) {
1455                         text = viewer->get_selection(viewer);
1456                         if (text)
1457                                 return text;
1458                 }
1459         }
1460
1461         textview = messageview_get_current_textview(msgview);
1462         g_return_val_if_fail(textview != NULL, NULL);
1463
1464         edit = GTK_TEXT_VIEW(textview->text);
1465         g_return_val_if_fail(edit != NULL, NULL);
1466         body_pos = textview->body_pos;
1467
1468         textbuf = gtk_text_view_get_buffer(edit);
1469
1470         if (gtk_text_buffer_get_selection_bounds(textbuf, NULL, NULL))
1471                 return gtkut_text_view_get_selection(edit);
1472         else if (msgview->filtered) {
1473                 GtkTextIter start_iter, end_iter;
1474                 gtk_text_buffer_get_iter_at_offset(textbuf, &start_iter, body_pos);
1475                 gtk_text_buffer_get_end_iter(textbuf, &end_iter);
1476                 gtk_text_buffer_get_text(textbuf, &start_iter, &end_iter, FALSE);
1477         } else
1478                 text = NULL;
1479
1480         return text;
1481 }
1482
1483 static void save_as_cb(gpointer data, guint action, GtkWidget *widget)
1484 {
1485         MessageView *messageview = (MessageView *)data;
1486         messageview_save_as(messageview);
1487 }
1488
1489 #ifdef USE_GNOMEPRINT
1490 static void print_mimeview(MimeView *mimeview, gint sel_start, gint sel_end, gint partnum) 
1491 {
1492         if (!mimeview 
1493         ||  !mimeview->textview
1494         ||  !mimeview->textview->text)
1495                 alertpanel_warning(_("Cannot print: the message doesn't "
1496                                      "contain text."));
1497         else {
1498                 gtk_widget_realize(mimeview->textview->text);
1499                 if (partnum > 0) {
1500                         mimeview_select_part_num(mimeview, partnum);
1501                 }
1502                 if (mimeview->type == MIMEVIEW_VIEWER) {
1503                         MimeViewer *viewer = mimeview->mimeviewer;
1504                         if (viewer && viewer->print) {
1505                                 viewer->print(viewer);
1506                                 return;
1507                         }
1508                 }
1509                 if (sel_start != -1 && sel_end != -1) {
1510                         GtkTextIter start, end;
1511                         GtkTextView *text = GTK_TEXT_VIEW(mimeview->textview->text);
1512                         GtkTextBuffer *buffer = gtk_text_view_get_buffer(text);
1513
1514                         gtk_text_buffer_get_iter_at_offset(buffer, &start, sel_start);
1515                         gtk_text_buffer_get_iter_at_offset(buffer, &end, sel_end);
1516                         gtk_text_buffer_select_range(buffer, &start, &end);
1517                 }
1518
1519                 gedit_print(GTK_TEXT_VIEW(mimeview->textview->text));
1520         }
1521 }
1522
1523 void messageview_print(MsgInfo *msginfo, gboolean all_headers, 
1524                         gint sel_start, gint sel_end, gint partnum) 
1525 {
1526         PangoFontDescription *font_desc = NULL;
1527         MessageView *tmpview = messageview_create_with_new_window_visible(
1528                                 mainwindow_get_mainwindow(), FALSE);
1529
1530         if (prefs_common.use_different_print_font) {
1531                 font_desc = pango_font_description_from_string
1532                                                 (prefs_common.printfont);
1533         } else {
1534                 font_desc = pango_font_description_from_string
1535                                                 (prefs_common.textfont);
1536         }
1537         if (font_desc) {
1538                 gtk_widget_modify_font(tmpview->mimeview->textview->text, 
1539                         font_desc);
1540                 pango_font_description_free(font_desc);
1541         }
1542
1543         tmpview->all_headers = all_headers;
1544         if (msginfo && messageview_show(tmpview, msginfo, 
1545                 tmpview->all_headers) >= 0) {
1546                         print_mimeview(tmpview->mimeview, 
1547                                 sel_start, sel_end, partnum);
1548         }
1549         messageview_destroy(tmpview);
1550 }
1551 #endif
1552
1553 static void print_cb(gpointer data, guint action, GtkWidget *widget)
1554 {
1555         MessageView *messageview = (MessageView *)data;
1556 #ifndef USE_GNOMEPRINT
1557         gchar *cmdline = NULL;
1558         gchar *p;
1559 #else
1560         gint sel_start = -1, sel_end = -1, partnum = 0;
1561 #endif
1562
1563         if (!messageview->msginfo) return;
1564 #ifndef USE_GNOMEPRINT
1565         cmdline = input_dialog(_("Print"),
1566                                _("Enter the print command line:\n"
1567                                  "('%s' will be replaced with file name)"),
1568                                prefs_common.print_cmd);
1569         if (!cmdline) return;
1570         if (!(p = strchr(cmdline, '%')) || *(p + 1) != 's' ||
1571             strchr(p + 2, '%')) {
1572                 alertpanel_error(_("Print command line is invalid:\n'%s'"),
1573                                  cmdline);
1574                 g_free(cmdline);
1575                 return;
1576         }
1577         procmsg_print_message(messageview->msginfo, cmdline);
1578         g_free(cmdline);
1579 #else
1580         partnum = mimeview_get_selected_part_num(messageview->mimeview);
1581         textview_get_selection_offsets(messageview->mimeview->textview,
1582                 &sel_start, &sel_end);
1583         messageview_print(messageview->msginfo, messageview->all_headers, 
1584                 sel_start, sel_end, partnum);
1585 #endif
1586 }
1587
1588 static void close_cb(gpointer data, guint action, GtkWidget *widget)
1589 {
1590         MessageView *messageview = (MessageView *)data;
1591         messageview_destroy(messageview);
1592 }
1593
1594 static void copy_cb(gpointer data, guint action, GtkWidget *widget)
1595 {
1596         MessageView *messageview = (MessageView *)data;
1597         messageview_copy_clipboard(messageview);
1598 }
1599
1600 static void allsel_cb(gpointer data, guint action, GtkWidget *widget)
1601 {
1602         MessageView *messageview = (MessageView *)data;
1603         messageview_select_all(messageview);
1604 }
1605
1606 static void search_cb(gpointer data, guint action, GtkWidget *widget)
1607 {
1608         MessageView *messageview = (MessageView *)data;
1609         message_search(messageview);
1610 }
1611
1612 static void set_charset_cb(gpointer data, guint action, GtkWidget *widget)
1613 {
1614         MessageView *messageview = (MessageView *)data;
1615         const gchar *charset;
1616
1617         if (GTK_CHECK_MENU_ITEM(widget)->active) {
1618                 charset = conv_get_charset_str((CharSet)action);
1619                 g_free(messageview->forced_charset);
1620                 messageview->forced_charset = g_strdup(charset);
1621                 procmime_force_charset(charset);
1622                 
1623                 messageview_show(messageview, messageview->msginfo, FALSE);
1624         }
1625 }
1626
1627 static void set_decode_cb(gpointer data, guint action, GtkWidget *widget)
1628 {
1629         MessageView *messageview = (MessageView *)data;
1630         if (GTK_CHECK_MENU_ITEM(widget)->active) {
1631                 messageview->forced_encoding = (EncodingType)action;
1632
1633                 messageview_show(messageview, messageview->msginfo, FALSE);
1634                 
1635                 debug_print("forced encoding: %d\n", action);
1636         }
1637 }
1638
1639
1640 static void view_source_cb(gpointer data, guint action, GtkWidget *widget)
1641 {
1642         MessageView *messageview = (MessageView *)data;
1643         SourceWindow *srcwin;
1644
1645         if (!messageview->msginfo) return;
1646
1647         srcwin = source_window_create();
1648         source_window_show_msg(srcwin, messageview->msginfo);
1649         source_window_show(srcwin);
1650 }
1651
1652 static void show_all_header_cb(gpointer data, guint action, GtkWidget *widget)
1653 {
1654         MessageView *messageview = (MessageView *)data;
1655         MsgInfo *msginfo = messageview->msginfo;
1656
1657         if (messageview->mimeview->textview &&
1658             messageview->mimeview->textview->loading) {
1659                 return;
1660         }
1661         if (messageview->updating)
1662                 return;
1663
1664         messageview->all_headers = 
1665                         GTK_CHECK_MENU_ITEM(widget)->active;
1666         if (!msginfo) return;
1667         messageview->msginfo = NULL;
1668         messageview_show(messageview, msginfo,
1669                          GTK_CHECK_MENU_ITEM(widget)->active);
1670         procmsg_msginfo_free(msginfo);
1671         main_window_set_menu_sensitive(messageview->mainwin);
1672 }
1673
1674 #define SET_CHECK_MENU_ACTIVE(path, active) \
1675 { \
1676         menuitem = gtk_item_factory_get_widget(ifactory, path); \
1677         gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menuitem), active); \
1678 }
1679
1680 static void msg_hide_quotes_cb(gpointer data, guint action, GtkWidget *widget)
1681 {
1682         MessageView *messageview = (MessageView *)data;
1683         MsgInfo *msginfo = messageview->msginfo;
1684         static gboolean updating_menu = FALSE;
1685         GtkItemFactory *ifactory = gtk_item_factory_from_widget(messageview->menubar);
1686         GtkWidget *menuitem;
1687         if (updating_menu)
1688                 return;
1689
1690         prefs_common.hide_quotes = 
1691                         GTK_CHECK_MENU_ITEM(widget)->active ? action : 0;
1692         
1693         updating_menu=TRUE;
1694         SET_CHECK_MENU_ACTIVE("/View/Quotes/Fold all", FALSE);
1695         SET_CHECK_MENU_ACTIVE("/View/Quotes/Fold from level 2", FALSE);
1696         SET_CHECK_MENU_ACTIVE("/View/Quotes/Fold from level 3", FALSE);
1697         gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(widget), prefs_common.hide_quotes > 0);      
1698         updating_menu=FALSE;
1699         if (!msginfo) return;
1700         messageview->msginfo = NULL;
1701         messageview_show(messageview, msginfo,
1702                          messageview->all_headers);
1703         procmsg_msginfo_free(msginfo);
1704         
1705         /* update main window */
1706         main_window_set_menu_sensitive(messageview->mainwin);
1707         summary_redisplay_msg(messageview->mainwin->summaryview);
1708 }
1709 #undef SET_CHECK_MENU_ACTIVE
1710
1711 static void compose_cb(gpointer data, guint action, GtkWidget *widget)
1712 {
1713         MessageView *messageview = (MessageView *)data;
1714         PrefsAccount *ac = NULL;
1715         FolderItem *item = NULL;
1716
1717         if (messageview->msginfo)
1718                 item = messageview->msginfo->folder;
1719
1720         if (item) {
1721                 ac = account_find_from_item(item);
1722                 if (ac && ac->protocol == A_NNTP &&
1723                     item->stype == F_NEWS) {
1724                         compose_new(ac, item->path, NULL);
1725                         return;
1726                 }
1727         }
1728
1729         compose_new(ac, NULL, NULL);
1730 }
1731
1732 static void reply_cb(gpointer data, guint action, GtkWidget *widget)
1733 {
1734         MessageView *messageview = (MessageView *)data;
1735         GSList *msginfo_list = NULL;
1736
1737         g_return_if_fail(messageview->msginfo);
1738
1739         msginfo_list = g_slist_append(msginfo_list, messageview->msginfo);
1740         compose_reply_from_messageview(messageview, msginfo_list, action);
1741         g_slist_free(msginfo_list);
1742 }
1743
1744 static void addressbook_open_cb(gpointer data, guint action, GtkWidget *widget)
1745 {
1746         addressbook_open(NULL);
1747 }
1748
1749 static void add_address_cb(gpointer data, guint action, GtkWidget *widget)
1750 {
1751         MessageView *messageview = (MessageView *)data;
1752         MsgInfo *msginfo;
1753         gchar *from;
1754
1755         if (!messageview->msginfo) return;
1756         msginfo = messageview->msginfo;
1757         Xstrdup_a(from, msginfo->from, return);
1758         eliminate_address_comment(from);
1759         extract_address(from);
1760         addressbook_add_contact(msginfo->fromname, from, NULL);
1761 }
1762
1763 static void create_filter_cb(gpointer data, guint action, GtkWidget *widget)
1764 {
1765         MessageView *messageview = (MessageView *)data;
1766         FolderItem * item;
1767         
1768         if (!messageview->msginfo) return;
1769         
1770         item = messageview->msginfo->folder;
1771         summary_msginfo_filter_open(item,  messageview->msginfo,
1772                                     (PrefsFilterType)action, 0);
1773 }
1774
1775 static void create_processing_cb(gpointer data, guint action,
1776                                  GtkWidget *widget)
1777 {
1778         MessageView *messageview = (MessageView *)data;
1779         FolderItem * item;
1780         
1781         if (!messageview->msginfo) return;
1782         
1783         item = messageview->msginfo->folder;
1784         summary_msginfo_filter_open(item,  messageview->msginfo,
1785                                     (PrefsFilterType)action, 1);
1786 }
1787
1788 static void open_urls_cb(gpointer data, guint action, GtkWidget *widget)
1789 {
1790         MessageView *messageview = (MessageView *)data;
1791         messageview_list_urls(messageview);
1792 }
1793
1794 static void about_cb(gpointer data, guint action, GtkWidget *widget)
1795 {
1796         about_show();
1797 }
1798
1799 static gboolean messageview_update_msg(gpointer source, gpointer data)
1800 {
1801         MsgInfoUpdate *msginfo_update = (MsgInfoUpdate *) source;
1802         MessageView *messageview = (MessageView *)data;
1803
1804         if (messageview->msginfo != msginfo_update->msginfo)
1805                 return FALSE;
1806
1807         if (msginfo_update->flags & MSGINFO_UPDATE_DELETED) {
1808                 MsgInfo *old_msginfo = messageview->msginfo;
1809                 messageview_clear(messageview);
1810                 messageview_update(messageview, old_msginfo);
1811         }
1812
1813         return FALSE;
1814 }
1815
1816 void messageview_set_menu_sensitive(MessageView *messageview)
1817 {
1818         GtkItemFactory *ifactory;
1819         GtkWidget *menuitem = NULL;
1820
1821         if (!messageview || !messageview->new_window) 
1822                 return;
1823         /* do some smart things */
1824         if (!messageview->menubar) return;
1825         ifactory = gtk_item_factory_from_widget(messageview->menubar);
1826         if (!ifactory) return;
1827
1828         if (prefs_common.hide_quotes) {
1829                 menuitem = NULL;
1830                 if (prefs_common.hide_quotes == 1)
1831                         menuitem = gtk_item_factory_get_widget(ifactory, 
1832                                         "/View/Quotes/Fold all");
1833                 if (prefs_common.hide_quotes == 2)
1834                         menuitem = gtk_item_factory_get_widget(ifactory, 
1835                                         "/View/Quotes/Fold from level 2");
1836                 if (prefs_common.hide_quotes == 3)
1837                         menuitem = gtk_item_factory_get_widget(ifactory, 
1838                                         "/View/Quotes/Fold from level 3");
1839                 gtk_check_menu_item_set_active
1840                         (GTK_CHECK_MENU_ITEM(menuitem),
1841                          TRUE);
1842         }
1843 }
1844
1845 void messageview_learn (MessageView *msgview, gboolean is_spam)
1846 {
1847         if (is_spam) {
1848                 if (procmsg_spam_learner_learn(msgview->msginfo, NULL, TRUE) == 0)
1849                         procmsg_msginfo_set_flags(msgview->msginfo, MSG_SPAM, 0);
1850                 else
1851                         log_error(LOG_PROTOCOL, _("An error happened while learning.\n"));
1852                 
1853         } else {
1854                 if (procmsg_spam_learner_learn(msgview->msginfo, NULL, FALSE) == 0)
1855                         procmsg_msginfo_unset_flags(msgview->msginfo, MSG_SPAM, 0);
1856                 else
1857                         log_error(LOG_PROTOCOL, _("An error happened while learning.\n"));
1858         }
1859         if (msgview->toolbar)
1860                 toolbar_set_learn_button
1861                         (msgview->toolbar,
1862                          MSG_IS_SPAM(msgview->msginfo->flags)?LEARN_HAM:LEARN_SPAM);
1863         else
1864                 toolbar_set_learn_button
1865                         (msgview->mainwin->toolbar,
1866                          MSG_IS_SPAM(msgview->msginfo->flags)?LEARN_HAM:LEARN_SPAM);
1867 }
1868
1869 void messageview_list_urls (MessageView *msgview)
1870 {
1871         GSList *cur = msgview->mimeview->textview->uri_list;
1872         GSList *newlist = NULL;
1873         for (; cur; cur = cur->next) {
1874                 ClickableText *uri = (ClickableText *)cur->data;
1875                 if (!uri->uri || !g_ascii_strncasecmp(uri->uri, "mailto:", 7) 
1876                 ||  uri->is_quote)
1877                         continue;
1878                 newlist = g_slist_prepend(newlist, uri);
1879         }
1880         newlist = g_slist_reverse(newlist);
1881         uri_opener_open(msgview, newlist);
1882         g_slist_free(newlist);
1883 }