2007-08-30 [colin] 2.10.0cvs186
[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 #ifndef MAEMO
875         messageview_set_position(messageview, 0);
876 #endif
877
878         if (messageview->window && msginfo->subject) {
879                 subject = g_strdup(msginfo->subject);
880                 if (!g_utf8_validate(subject, -1, NULL)) {
881                         g_free(subject);
882                         subject = g_malloc(strlen(msginfo->subject)*2 +1);
883                         conv_localetodisp(subject, strlen(msginfo->subject)*2 +1, 
884                                 msginfo->subject);
885                 }
886                 if (g_utf8_validate(subject, -1, NULL))
887                         gtk_window_set_title(GTK_WINDOW(messageview->window), 
888                                 subject);
889                 g_free(subject);
890         }
891
892         if (msginfo && msginfo->folder) {
893                 msginfo->folder->last_seen = msginfo->msgnum;   
894         }
895
896         main_create_mailing_list_menu(messageview->mainwin, messageview->msginfo);
897
898         if (messageview->msginfo && messageview->msginfo->extradata
899             && messageview->msginfo->extradata->partial_recv)
900                 partial_recv_show(messageview->noticeview, 
901                                   messageview->msginfo);
902         else if (messageview->msginfo && messageview->msginfo->extradata &&
903             (messageview->msginfo->extradata->dispositionnotificationto || 
904              messageview->msginfo->extradata->returnreceiptto) &&
905             !MSG_IS_RETRCPT_SENT(messageview->msginfo->flags) &&
906             !prefs_common.never_send_retrcpt)
907                 return_receipt_show(messageview->noticeview, 
908                                     messageview->msginfo);
909         else 
910                 noticeview_hide(messageview->noticeview);
911
912         mimeinfo = procmime_mimeinfo_next(mimeinfo);
913         if (!all_headers && mimeinfo 
914                         && (mimeinfo->type != MIMETYPE_TEXT || 
915             strcasecmp(mimeinfo->subtype, "plain")) 
916                         && (mimeinfo->type != MIMETYPE_MULTIPART || 
917             strcasecmp(mimeinfo->subtype, "signed"))) {
918                 if (strcasecmp(mimeinfo->subtype, "html"))
919                         mimeview_show_part(messageview->mimeview,mimeinfo);
920                 else if (prefs_common.invoke_plugin_on_html)
921                         mimeview_select_mimepart_icon(messageview->mimeview,mimeinfo);
922         }
923
924         g_free(file);
925
926         return 0;
927 }
928
929 void messageview_reflect_prefs_pixmap_theme(void)
930 {
931         GList *cur;
932         MessageView *msgview;
933
934         for (cur = msgview_list; cur != NULL; cur = cur->next) {
935                 msgview = (MessageView*)cur->data;
936                 toolbar_update(TOOLBAR_MSGVIEW, msgview);
937                 mimeview_update(msgview->mimeview);
938         }
939 }
940
941 void messageview_clear(MessageView *messageview)
942 {
943         if (!messageview)
944                 return;
945         procmsg_msginfo_free(messageview->msginfo);
946         messageview->msginfo = NULL;
947         messageview->filtered = FALSE;
948         mimeview_clear(messageview->mimeview);
949         headerview_clear(messageview->headerview);
950         noticeview_hide(messageview->noticeview);
951 }
952
953 void messageview_destroy(MessageView *messageview)
954 {
955         debug_print("destroy messageview\n");
956         messageview_list = g_list_remove(messageview_list, messageview);
957
958         if (messageview->mainwin->summaryview->messageview == messageview) {
959                 messageview->mainwin->summaryview->displayed = NULL;
960                 messageview->mainwin->summaryview->messageview = NULL;
961         }
962         if (messageview->mainwin->summaryview->ext_messageview == messageview) {
963                 messageview->mainwin->summaryview->displayed = NULL;
964                 messageview->mainwin->summaryview->ext_messageview = NULL;
965         }
966         if (!messageview->deferred_destroy) {
967                 hooks_unregister_hook(MSGINFO_UPDATE_HOOKLIST,
968                               messageview->msginfo_update_callback_id);
969         }
970
971         if (messageview->updating) {
972                 debug_print("uh oh, better not touch that now (fetching)\n");
973                 messageview->deferred_destroy = TRUE;
974                 gtk_widget_hide(messageview->window);
975                 return;
976         }
977         
978         if (messageview->mimeview->textview
979         &&  messageview->mimeview->textview->loading) {
980                 debug_print("uh oh, better not touch that now (loading text)\n");
981                 messageview->deferred_destroy = TRUE;
982                 messageview->mimeview->textview->stop_loading = TRUE;
983                 gtk_widget_hide(messageview->window);
984                 return;
985         }
986
987         headerview_destroy(messageview->headerview);
988         mimeview_destroy(messageview->mimeview);
989         noticeview_destroy(messageview->noticeview);
990
991         procmsg_msginfo_free(messageview->msginfo);
992         toolbar_clear_list(TOOLBAR_MSGVIEW);
993         if (messageview->toolbar) {
994                 toolbar_destroy(messageview->toolbar);
995                 g_free(messageview->toolbar);
996         }
997         
998         msgview_list = g_list_remove(msgview_list, messageview); 
999
1000         if (messageview->window)
1001                 gtk_widget_destroy(messageview->window);
1002         g_free(messageview);
1003 }
1004
1005 void messageview_delete(MessageView *msgview)
1006 {
1007         MsgInfo *msginfo = NULL;
1008         FolderItem *trash = NULL;
1009         PrefsAccount *ac = NULL;
1010
1011         if (msgview->msginfo && msgview->mainwin && msgview->mainwin->summaryview)
1012                 msginfo = summary_get_selected_msg(msgview->mainwin->summaryview);
1013         
1014         /* need a procmsg_msginfo_equal() */
1015         if (msginfo && msgview->msginfo && 
1016             msginfo->msgnum == msgview->msginfo->msgnum && 
1017             msginfo->folder == msgview->msginfo->folder) {
1018                 summary_delete_trash(msgview->mainwin->summaryview);
1019         } else {                
1020                 msginfo = msgview->msginfo;
1021
1022                 g_return_if_fail(msginfo != NULL);
1023
1024                 /* to get the trash folder, we have to choose either
1025                  * the folder's or account's trash default - we prefer
1026                  * the one in the account prefs */
1027                 if (msginfo->folder) {
1028                         if (NULL != (ac = account_find_from_item(msginfo->folder)))
1029                                 trash = account_get_special_folder(ac, F_TRASH);
1030                         if (!trash && msginfo->folder->folder)  
1031                                 trash = msginfo->folder->folder->trash;
1032                         /* if still not found, use the default */
1033                         if (!trash) 
1034                                 trash = folder_get_default_trash();
1035                 }       
1036
1037                 g_return_if_fail(trash != NULL);
1038
1039                 if (prefs_common.immediate_exec)
1040                         /* TODO: Delete from trash */
1041                         folder_item_move_msg(trash, msginfo);
1042                 else {
1043                         procmsg_msginfo_set_to_folder(msginfo, trash);
1044                         procmsg_msginfo_set_flags(msginfo, MSG_DELETED, 0);
1045                         /* NOTE: does not update to next message in summaryview */
1046                 }
1047         }
1048 #ifdef MAEMO
1049         if (msgview->window) {
1050                 messageview_destroy(msgview);
1051         }
1052 #endif
1053 }
1054
1055 /* 
1056  * \brief update messageview with currently selected message in summaryview
1057  *        leave unchanged if summaryview is empty
1058  * \param pointer to MessageView
1059  */     
1060 static void messageview_update(MessageView *msgview, MsgInfo *old_msginfo)
1061 {
1062         SummaryView *summaryview = (SummaryView*)msgview->mainwin->summaryview;
1063
1064         g_return_if_fail(summaryview != NULL);
1065         
1066         if (summaryview->selected) {
1067                 MsgInfo *msginfo = summary_get_selected_msg(summaryview);
1068                 if (msginfo == NULL || msginfo == old_msginfo)
1069                         return;
1070
1071                 messageview_show(msgview, msginfo, 
1072                                  msgview->all_headers);
1073         } 
1074 }
1075
1076 void messageview_quote_color_set(void)
1077 {
1078 }
1079
1080 void messageview_set_font(MessageView *messageview)
1081 {
1082 }
1083
1084 TextView *messageview_get_current_textview(MessageView *messageview)
1085 {
1086         TextView *text = NULL;
1087
1088         text = messageview->mimeview->textview;
1089
1090         return text;
1091 }
1092
1093 MimeInfo *messageview_get_selected_mime_part(MessageView *messageview)
1094 {
1095         return mimeview_get_selected_part(messageview->mimeview);
1096 }
1097
1098 void messageview_copy_clipboard(MessageView *messageview)
1099 {
1100         gchar *text = messageview_get_selection(messageview);
1101         if (text) {
1102                 gtk_clipboard_set_text(
1103                         gtk_clipboard_get(GDK_SELECTION_CLIPBOARD),
1104                         text, -1);
1105         }
1106         g_free(text);
1107 }
1108
1109 void messageview_select_all(MessageView *messageview)
1110 {
1111         TextView *text;
1112
1113         text = messageview_get_current_textview(messageview);
1114         if (text) {
1115                 GtkTextView *textview = GTK_TEXT_VIEW(text->text);
1116                 GtkTextBuffer *buffer;
1117                 GtkTextIter start, end;
1118
1119                 buffer = gtk_text_view_get_buffer(textview);
1120                 gtk_text_buffer_get_bounds(buffer, &start, &end);
1121                 gtk_text_buffer_select_range(buffer, &start, &end);
1122         }
1123 }
1124
1125 void messageview_set_position(MessageView *messageview, gint pos)
1126 {
1127         TextView *text;
1128
1129         text = messageview_get_current_textview(messageview);
1130         if (text)
1131                 textview_set_position(text, pos);
1132 }
1133
1134 gboolean messageview_search_string(MessageView *messageview, const gchar *str,
1135                                    gboolean case_sens)
1136 {
1137         TextView *text;
1138
1139         if (messageview->mimeview->type == MIMEVIEW_VIEWER) {
1140                 MimeViewer *viewer = messageview->mimeview->mimeviewer;
1141                 if (viewer && viewer->text_search) {
1142                         return viewer->text_search(viewer, FALSE, str, case_sens);
1143                 }
1144         }
1145
1146         text = messageview_get_current_textview(messageview);
1147         if (text)
1148                 return textview_search_string(text, str, case_sens);
1149         return FALSE;
1150 }
1151
1152 gboolean messageview_search_string_backward(MessageView *messageview,
1153                                             const gchar *str,
1154                                             gboolean case_sens)
1155 {
1156         TextView *text;
1157
1158         if (messageview->mimeview->type == MIMEVIEW_VIEWER) {
1159                 MimeViewer *viewer = messageview->mimeview->mimeviewer;
1160                 if (viewer && viewer->text_search) {
1161                         return viewer->text_search(viewer, TRUE, str, case_sens);
1162                 }
1163         }
1164
1165         text = messageview_get_current_textview(messageview);
1166         if (text)       
1167                 return textview_search_string_backward(text,
1168                                                        str, case_sens);
1169         return FALSE;
1170 }
1171
1172 gboolean messageview_is_visible(MessageView *messageview)
1173 {
1174         if (messageview == NULL)
1175                 return FALSE;
1176         return messageview->visible;
1177 }
1178
1179 static void messageview_save_as(MessageView *messageview)
1180 {
1181         gchar *filename = NULL;
1182         MsgInfo *msginfo;
1183         gchar *src, *dest, *tmp;
1184
1185         if (!messageview->msginfo) return;
1186         msginfo = messageview->msginfo;
1187
1188         if (msginfo->subject) {
1189                 Xstrdup_a(filename, msginfo->subject, return);
1190                 subst_for_filename(filename);
1191         }
1192         if (filename && !g_utf8_validate(filename, -1, NULL)) {
1193                 gchar *oldstr = filename;
1194                 filename = conv_codeset_strdup(filename,
1195                                                conv_get_locale_charset_str(),
1196                                                CS_UTF_8);
1197                 if (!filename) {
1198                         g_warning("messageview_save_as(): failed to convert character set.");
1199                         filename = g_strdup(oldstr);
1200                 }
1201                 dest = filesel_select_file_save(_("Save as"), filename);
1202                 g_free(filename);
1203         } else
1204                 dest = filesel_select_file_save(_("Save as"), filename);
1205         if (!dest) return;
1206         if (is_file_exist(dest)) {
1207                 AlertValue aval;
1208
1209                 aval = alertpanel(_("Overwrite"),
1210                                   _("Overwrite existing file?"),
1211                                   GTK_STOCK_CANCEL, GTK_STOCK_OK, NULL);
1212                 if (G_ALERTALTERNATE != aval) return;
1213         }
1214
1215         src = procmsg_get_message_file(msginfo);
1216         if (copy_file(src, dest, TRUE) < 0) {
1217                 tmp =  g_path_get_basename(dest);
1218                 alertpanel_error(_("Couldn't save the file '%s'."), tmp);
1219                 g_free(tmp);
1220         }
1221         g_free(dest);
1222         g_free(src);
1223 }
1224
1225 static gint messageview_delete_cb(GtkWidget *widget, GdkEventAny *event,
1226                                   MessageView *messageview)
1227 {
1228         messageview_destroy(messageview);
1229         return TRUE;
1230 }
1231
1232 static void messageview_size_allocate_cb(GtkWidget *widget,
1233                                          GtkAllocation *allocation)
1234 {
1235         g_return_if_fail(allocation != NULL);
1236
1237         prefs_common.msgwin_width  = allocation->width;
1238         prefs_common.msgwin_height = allocation->height;
1239 }
1240
1241 static gboolean key_pressed(GtkWidget *widget, GdkEventKey *event,
1242                         MessageView *messageview)
1243 {
1244         if (event && event->keyval == GDK_Escape && messageview->window) {
1245                 messageview_destroy(messageview);
1246                 return TRUE;
1247         }
1248
1249         if ((event->state & (GDK_MOD1_MASK|GDK_CONTROL_MASK)) != 0)
1250                 return FALSE;
1251
1252         g_signal_stop_emission_by_name(G_OBJECT(widget),
1253                                         "key_press_event");
1254         mimeview_pass_key_press_event(messageview->mimeview, event);
1255         return FALSE;
1256 }
1257
1258 static void return_receipt_show(NoticeView *noticeview, MsgInfo *msginfo)
1259 {
1260         gchar *addr = NULL;
1261         gboolean from_me = FALSE;
1262         if (msginfo->folder 
1263                 && (folder_has_parent_of_type(msginfo->folder, F_QUEUE)
1264                  || folder_has_parent_of_type(msginfo->folder, F_DRAFT)))
1265                 return;
1266
1267         addr = g_strdup(msginfo->from);
1268         if (addr) {
1269                 extract_address(addr);
1270                 if (account_find_from_address(addr)) {
1271                         from_me = TRUE;
1272                 }
1273                 g_free(addr);
1274         }
1275
1276         if (from_me) {
1277                 noticeview_set_icon(noticeview, STOCK_PIXMAP_NOTICE_WARN);
1278                 noticeview_set_text(noticeview, _("You asked for a return receipt in this message."));
1279                 noticeview_set_button_text(noticeview, NULL);
1280                 noticeview_set_button_press_callback(noticeview, NULL, NULL);
1281         } else {
1282                 noticeview_set_icon(noticeview, STOCK_PIXMAP_NOTICE_WARN);
1283                 noticeview_set_text(noticeview, _("This message asks for a return receipt."));
1284                 noticeview_set_button_text(noticeview, _("Send receipt"));
1285                 noticeview_set_button_press_callback(noticeview,
1286                                                      G_CALLBACK(return_receipt_send_clicked),
1287                                                      (gpointer) msginfo);
1288         }
1289         noticeview_show(noticeview);
1290 }
1291
1292 static void return_receipt_send_clicked(NoticeView *noticeview, MsgInfo *msginfo)
1293 {
1294         MsgInfo *tmpmsginfo;
1295         gchar *file;
1296
1297         file = procmsg_get_message_file_path(msginfo);
1298         if (!file) {
1299                 g_warning("can't get message file path.\n");
1300                 return;
1301         }
1302
1303         tmpmsginfo = procheader_parse_file(file, msginfo->flags, TRUE, TRUE);
1304         tmpmsginfo->folder = msginfo->folder;
1305         tmpmsginfo->msgnum = msginfo->msgnum;
1306
1307         if (disposition_notification_send(tmpmsginfo) >= 0) {
1308                 procmsg_msginfo_set_flags(msginfo, MSG_RETRCPT_SENT, 0);
1309                 noticeview_hide(noticeview);
1310         }               
1311
1312         procmsg_msginfo_free(tmpmsginfo);
1313         g_free(file);
1314 }
1315
1316 static void partial_recv_show(NoticeView *noticeview, MsgInfo *msginfo)
1317 {
1318         gchar *text = NULL;
1319         gchar *button1 = NULL;
1320         gchar *button2 = NULL;
1321         void  *button1_cb = NULL;
1322         void  *button2_cb = NULL;
1323
1324         if (!msginfo->extradata)
1325                 return;
1326         if (!partial_msg_in_uidl_list(msginfo)) {
1327                 text = g_strdup_printf(_("This message has been partially "
1328                                 "retrieved,\nand has been deleted from the "
1329                                 "server."));
1330         } else {
1331                 switch (msginfo->planned_download) {
1332                 case POP3_PARTIAL_DLOAD_UNKN:
1333                         text = g_strdup_printf(_("This message has been "
1334                                         "partially retrieved;\nit is %s."),
1335                                         to_human_readable(
1336                                                 (off_t)(msginfo->total_size)));
1337                         button1 = _("Mark for download");
1338                         button2 = _("Mark for deletion");
1339                         button1_cb = partial_recv_dload_clicked;
1340                         button2_cb = partial_recv_del_clicked;
1341                         break;
1342                 case POP3_PARTIAL_DLOAD_DLOAD:
1343                         text = g_strdup_printf(_("This message has been "
1344                                         "partially retrieved;\nit is %s and "
1345                                         "will be downloaded."),
1346                                         to_human_readable(
1347                                                 (off_t)(msginfo->total_size)));
1348                         button1 = _("Unmark");
1349                         button1_cb = partial_recv_unmark_clicked;
1350                         button2 = _("Mark for deletion");
1351                         button2_cb = partial_recv_del_clicked;
1352                         break;
1353                 case POP3_PARTIAL_DLOAD_DELE:
1354                         text = g_strdup_printf(_("This message has been "
1355                                         "partially retrieved;\nit is %s and "
1356                                         "will be deleted."),
1357                                         to_human_readable(
1358                                                 (off_t)(msginfo->total_size)));
1359                         button1 = _("Mark for download");
1360                         button1_cb = partial_recv_dload_clicked;
1361                         button2 = _("Unmark");
1362                         button2_cb = partial_recv_unmark_clicked;
1363                         break;
1364                 default:
1365                         return;
1366                 }
1367         }
1368         
1369         noticeview_set_icon(noticeview, STOCK_PIXMAP_NOTICE_WARN);
1370         noticeview_set_text(noticeview, text);
1371         g_free(text);
1372         noticeview_set_button_text(noticeview, button1);
1373         noticeview_set_button_press_callback(noticeview,
1374                      G_CALLBACK(button1_cb), (gpointer) msginfo);
1375
1376         noticeview_set_2ndbutton_text(noticeview, button2);
1377         noticeview_set_2ndbutton_press_callback(noticeview,
1378                      G_CALLBACK(button2_cb), (gpointer) msginfo);
1379
1380         noticeview_show(noticeview);
1381 }
1382
1383 static void partial_recv_dload_clicked(NoticeView *noticeview, 
1384                                        MsgInfo *msginfo)
1385 {
1386         if (partial_mark_for_download(msginfo) == 0) {
1387                 partial_recv_show(noticeview, msginfo);
1388         }
1389 }
1390
1391 static void partial_recv_del_clicked(NoticeView *noticeview, 
1392                                        MsgInfo *msginfo)
1393 {
1394         if (partial_mark_for_delete(msginfo) == 0) {
1395                 partial_recv_show(noticeview, msginfo);
1396         }
1397 }
1398
1399 static void partial_recv_unmark_clicked(NoticeView *noticeview, 
1400                                        MsgInfo *msginfo)
1401 {
1402         if (partial_unmark(msginfo) == 0) {
1403                 partial_recv_show(noticeview, msginfo);
1404         }
1405 }
1406
1407 static void select_account_cb(GtkWidget *w, gpointer data)
1408 {
1409         *(gint*)data = combobox_get_active_data(GTK_COMBO_BOX(w));
1410 }
1411
1412 static PrefsAccount *select_account_from_list(GList *ac_list)
1413 {
1414         GtkWidget *optmenu;
1415         gint account_id;
1416
1417         g_return_val_if_fail(ac_list != NULL, NULL);
1418         g_return_val_if_fail(ac_list->data != NULL, NULL);
1419         
1420         optmenu = gtkut_account_menu_new(ac_list,
1421                         G_CALLBACK(select_account_cb),
1422                         &account_id);
1423         if (!optmenu)
1424                 return NULL;
1425         account_id = ((PrefsAccount *) ac_list->data)->account_id;
1426         if (alertpanel_with_widget(
1427                                 _("Return Receipt Notification"),
1428                                 _("The message was sent to several of your "
1429                                   "accounts.\n"
1430                                   "Please choose which account do you want to "
1431                                   "use for sending the receipt notification:"),
1432                                 _("_Cancel"), _("_Send Notification"), NULL,
1433                                 FALSE, G_ALERTDEFAULT, optmenu) != G_ALERTALTERNATE)
1434                 return NULL;
1435         return account_find_from_id(account_id);
1436 }
1437
1438 /* 
1439  * \brief return selected messageview text, when nothing is 
1440  *        selected and message was filtered, return complete text
1441  *
1442  * \param  pointer to Messageview 
1443  *
1444  * \return pointer to text (needs to be free'd by calling func)
1445  */
1446 gchar *messageview_get_selection(MessageView *msgview)
1447 {
1448         TextView *textview;
1449         gchar *text = NULL;
1450         GtkTextView *edit = NULL;
1451         GtkTextBuffer *textbuf;
1452         gint body_pos = 0;
1453         
1454         g_return_val_if_fail(msgview != NULL, NULL);
1455
1456         if (msgview->mimeview->type == MIMEVIEW_VIEWER) {
1457                 MimeViewer *viewer = msgview->mimeview->mimeviewer;
1458                 if (viewer && viewer->get_selection) {
1459                         text = viewer->get_selection(viewer);
1460                         if (text)
1461                                 return text;
1462                 }
1463         }
1464
1465         textview = messageview_get_current_textview(msgview);
1466         g_return_val_if_fail(textview != NULL, NULL);
1467
1468         edit = GTK_TEXT_VIEW(textview->text);
1469         g_return_val_if_fail(edit != NULL, NULL);
1470         body_pos = textview->body_pos;
1471
1472         textbuf = gtk_text_view_get_buffer(edit);
1473
1474         if (gtk_text_buffer_get_selection_bounds(textbuf, NULL, NULL))
1475                 return gtkut_text_view_get_selection(edit);
1476         else if (msgview->filtered) {
1477                 GtkTextIter start_iter, end_iter;
1478                 gtk_text_buffer_get_iter_at_offset(textbuf, &start_iter, body_pos);
1479                 gtk_text_buffer_get_end_iter(textbuf, &end_iter);
1480                 gtk_text_buffer_get_text(textbuf, &start_iter, &end_iter, FALSE);
1481         } else
1482                 text = NULL;
1483
1484         return text;
1485 }
1486
1487 static void save_as_cb(gpointer data, guint action, GtkWidget *widget)
1488 {
1489         MessageView *messageview = (MessageView *)data;
1490         messageview_save_as(messageview);
1491 }
1492
1493 #ifdef USE_GNOMEPRINT
1494 static void print_mimeview(MimeView *mimeview, gint sel_start, gint sel_end, gint partnum) 
1495 {
1496         if (!mimeview 
1497         ||  !mimeview->textview
1498         ||  !mimeview->textview->text)
1499                 alertpanel_warning(_("Cannot print: the message doesn't "
1500                                      "contain text."));
1501         else {
1502                 gtk_widget_realize(mimeview->textview->text);
1503                 if (partnum > 0) {
1504                         mimeview_select_part_num(mimeview, partnum);
1505                 }
1506                 if (mimeview->type == MIMEVIEW_VIEWER) {
1507                         MimeViewer *viewer = mimeview->mimeviewer;
1508                         if (viewer && viewer->print) {
1509                                 viewer->print(viewer);
1510                                 return;
1511                         }
1512                 }
1513                 if (sel_start != -1 && sel_end != -1) {
1514                         GtkTextIter start, end;
1515                         GtkTextView *text = GTK_TEXT_VIEW(mimeview->textview->text);
1516                         GtkTextBuffer *buffer = gtk_text_view_get_buffer(text);
1517
1518                         gtk_text_buffer_get_iter_at_offset(buffer, &start, sel_start);
1519                         gtk_text_buffer_get_iter_at_offset(buffer, &end, sel_end);
1520                         gtk_text_buffer_select_range(buffer, &start, &end);
1521                 }
1522
1523                 gedit_print(GTK_TEXT_VIEW(mimeview->textview->text));
1524         }
1525 }
1526
1527 void messageview_print(MsgInfo *msginfo, gboolean all_headers, 
1528                         gint sel_start, gint sel_end, gint partnum) 
1529 {
1530         PangoFontDescription *font_desc = NULL;
1531         MessageView *tmpview = messageview_create_with_new_window_visible(
1532                                 mainwindow_get_mainwindow(), FALSE);
1533
1534         if (prefs_common.use_different_print_font) {
1535                 font_desc = pango_font_description_from_string
1536                                                 (prefs_common.printfont);
1537         } else {
1538                 font_desc = pango_font_description_from_string
1539                                                 (prefs_common.textfont);
1540         }
1541         if (font_desc) {
1542                 gtk_widget_modify_font(tmpview->mimeview->textview->text, 
1543                         font_desc);
1544                 pango_font_description_free(font_desc);
1545         }
1546
1547         tmpview->all_headers = all_headers;
1548         if (msginfo && messageview_show(tmpview, msginfo, 
1549                 tmpview->all_headers) >= 0) {
1550                         print_mimeview(tmpview->mimeview, 
1551                                 sel_start, sel_end, partnum);
1552         }
1553         messageview_destroy(tmpview);
1554 }
1555 #endif
1556
1557 static void print_cb(gpointer data, guint action, GtkWidget *widget)
1558 {
1559         MessageView *messageview = (MessageView *)data;
1560 #ifndef USE_GNOMEPRINT
1561         gchar *cmdline = NULL;
1562         gchar *p;
1563 #else
1564         gint sel_start = -1, sel_end = -1, partnum = 0;
1565 #endif
1566
1567         if (!messageview->msginfo) return;
1568 #ifndef USE_GNOMEPRINT
1569         cmdline = input_dialog(_("Print"),
1570                                _("Enter the print command line:\n"
1571                                  "('%s' will be replaced with file name)"),
1572                                prefs_common.print_cmd);
1573         if (!cmdline) return;
1574         if (!(p = strchr(cmdline, '%')) || *(p + 1) != 's' ||
1575             strchr(p + 2, '%')) {
1576                 alertpanel_error(_("Print command line is invalid:\n'%s'"),
1577                                  cmdline);
1578                 g_free(cmdline);
1579                 return;
1580         }
1581         procmsg_print_message(messageview->msginfo, cmdline);
1582         g_free(cmdline);
1583 #else
1584         partnum = mimeview_get_selected_part_num(messageview->mimeview);
1585         textview_get_selection_offsets(messageview->mimeview->textview,
1586                 &sel_start, &sel_end);
1587         messageview_print(messageview->msginfo, messageview->all_headers, 
1588                 sel_start, sel_end, partnum);
1589 #endif
1590 }
1591
1592 static void close_cb(gpointer data, guint action, GtkWidget *widget)
1593 {
1594         MessageView *messageview = (MessageView *)data;
1595         messageview_destroy(messageview);
1596 }
1597
1598 static void copy_cb(gpointer data, guint action, GtkWidget *widget)
1599 {
1600         MessageView *messageview = (MessageView *)data;
1601         messageview_copy_clipboard(messageview);
1602 }
1603
1604 static void allsel_cb(gpointer data, guint action, GtkWidget *widget)
1605 {
1606         MessageView *messageview = (MessageView *)data;
1607         messageview_select_all(messageview);
1608 }
1609
1610 static void search_cb(gpointer data, guint action, GtkWidget *widget)
1611 {
1612         MessageView *messageview = (MessageView *)data;
1613         message_search(messageview);
1614 }
1615
1616 static void set_charset_cb(gpointer data, guint action, GtkWidget *widget)
1617 {
1618         MessageView *messageview = (MessageView *)data;
1619         const gchar *charset;
1620
1621         if (GTK_CHECK_MENU_ITEM(widget)->active) {
1622                 charset = conv_get_charset_str((CharSet)action);
1623                 g_free(messageview->forced_charset);
1624                 messageview->forced_charset = g_strdup(charset);
1625                 procmime_force_charset(charset);
1626                 
1627                 messageview_show(messageview, messageview->msginfo, FALSE);
1628         }
1629 }
1630
1631 static void set_decode_cb(gpointer data, guint action, GtkWidget *widget)
1632 {
1633         MessageView *messageview = (MessageView *)data;
1634         if (GTK_CHECK_MENU_ITEM(widget)->active) {
1635                 messageview->forced_encoding = (EncodingType)action;
1636
1637                 messageview_show(messageview, messageview->msginfo, FALSE);
1638                 
1639                 debug_print("forced encoding: %d\n", action);
1640         }
1641 }
1642
1643
1644 static void view_source_cb(gpointer data, guint action, GtkWidget *widget)
1645 {
1646         MessageView *messageview = (MessageView *)data;
1647         SourceWindow *srcwin;
1648
1649         if (!messageview->msginfo) return;
1650
1651         srcwin = source_window_create();
1652         source_window_show_msg(srcwin, messageview->msginfo);
1653         source_window_show(srcwin);
1654 }
1655
1656 static void show_all_header_cb(gpointer data, guint action, GtkWidget *widget)
1657 {
1658         MessageView *messageview = (MessageView *)data;
1659         MsgInfo *msginfo = messageview->msginfo;
1660
1661         if (messageview->mimeview->textview &&
1662             messageview->mimeview->textview->loading) {
1663                 return;
1664         }
1665         if (messageview->updating)
1666                 return;
1667
1668         messageview->all_headers = 
1669                         GTK_CHECK_MENU_ITEM(widget)->active;
1670         if (!msginfo) return;
1671         messageview->msginfo = NULL;
1672         messageview_show(messageview, msginfo,
1673                          GTK_CHECK_MENU_ITEM(widget)->active);
1674         procmsg_msginfo_free(msginfo);
1675         main_window_set_menu_sensitive(messageview->mainwin);
1676 }
1677
1678 #define SET_CHECK_MENU_ACTIVE(path, active) \
1679 { \
1680         menuitem = gtk_item_factory_get_widget(ifactory, path); \
1681         gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menuitem), active); \
1682 }
1683
1684 static void msg_hide_quotes_cb(gpointer data, guint action, GtkWidget *widget)
1685 {
1686         MessageView *messageview = (MessageView *)data;
1687         MsgInfo *msginfo = messageview->msginfo;
1688         static gboolean updating_menu = FALSE;
1689         GtkItemFactory *ifactory = gtk_item_factory_from_widget(messageview->menubar);
1690         GtkWidget *menuitem;
1691         if (updating_menu)
1692                 return;
1693
1694         prefs_common.hide_quotes = 
1695                         GTK_CHECK_MENU_ITEM(widget)->active ? action : 0;
1696         
1697         updating_menu=TRUE;
1698         SET_CHECK_MENU_ACTIVE("/View/Quotes/Fold all", FALSE);
1699         SET_CHECK_MENU_ACTIVE("/View/Quotes/Fold from level 2", FALSE);
1700         SET_CHECK_MENU_ACTIVE("/View/Quotes/Fold from level 3", FALSE);
1701         gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(widget), prefs_common.hide_quotes > 0);      
1702         updating_menu=FALSE;
1703         if (!msginfo) return;
1704         messageview->msginfo = NULL;
1705         messageview_show(messageview, msginfo,
1706                          messageview->all_headers);
1707         procmsg_msginfo_free(msginfo);
1708         
1709         /* update main window */
1710         main_window_set_menu_sensitive(messageview->mainwin);
1711         summary_redisplay_msg(messageview->mainwin->summaryview);
1712 }
1713 #undef SET_CHECK_MENU_ACTIVE
1714
1715 static void compose_cb(gpointer data, guint action, GtkWidget *widget)
1716 {
1717         MessageView *messageview = (MessageView *)data;
1718         PrefsAccount *ac = NULL;
1719         FolderItem *item = NULL;
1720
1721         if (messageview->msginfo)
1722                 item = messageview->msginfo->folder;
1723
1724         if (item) {
1725                 ac = account_find_from_item(item);
1726                 if (ac && ac->protocol == A_NNTP &&
1727                     item->stype == F_NEWS) {
1728                         compose_new(ac, item->path, NULL);
1729                         return;
1730                 }
1731         }
1732
1733         compose_new(ac, NULL, NULL);
1734 }
1735
1736 static void reply_cb(gpointer data, guint action, GtkWidget *widget)
1737 {
1738         MessageView *messageview = (MessageView *)data;
1739         GSList *msginfo_list = NULL;
1740
1741         g_return_if_fail(messageview->msginfo);
1742
1743         msginfo_list = g_slist_append(msginfo_list, messageview->msginfo);
1744         compose_reply_from_messageview(messageview, msginfo_list, action);
1745         g_slist_free(msginfo_list);
1746 }
1747
1748 static void addressbook_open_cb(gpointer data, guint action, GtkWidget *widget)
1749 {
1750         addressbook_open(NULL);
1751 }
1752
1753 static void add_address_cb(gpointer data, guint action, GtkWidget *widget)
1754 {
1755         MessageView *messageview = (MessageView *)data;
1756         MsgInfo *msginfo;
1757         gchar *from;
1758
1759         if (!messageview->msginfo) return;
1760         msginfo = messageview->msginfo;
1761         Xstrdup_a(from, msginfo->from, return);
1762         eliminate_address_comment(from);
1763         extract_address(from);
1764         addressbook_add_contact(msginfo->fromname, from, NULL);
1765 }
1766
1767 static void create_filter_cb(gpointer data, guint action, GtkWidget *widget)
1768 {
1769         MessageView *messageview = (MessageView *)data;
1770         FolderItem * item;
1771         
1772         if (!messageview->msginfo) return;
1773         
1774         item = messageview->msginfo->folder;
1775         summary_msginfo_filter_open(item,  messageview->msginfo,
1776                                     (PrefsFilterType)action, 0);
1777 }
1778
1779 static void create_processing_cb(gpointer data, guint action,
1780                                  GtkWidget *widget)
1781 {
1782         MessageView *messageview = (MessageView *)data;
1783         FolderItem * item;
1784         
1785         if (!messageview->msginfo) return;
1786         
1787         item = messageview->msginfo->folder;
1788         summary_msginfo_filter_open(item,  messageview->msginfo,
1789                                     (PrefsFilterType)action, 1);
1790 }
1791
1792 static void open_urls_cb(gpointer data, guint action, GtkWidget *widget)
1793 {
1794         MessageView *messageview = (MessageView *)data;
1795         messageview_list_urls(messageview);
1796 }
1797
1798 static void about_cb(gpointer data, guint action, GtkWidget *widget)
1799 {
1800         about_show();
1801 }
1802
1803 static gboolean messageview_update_msg(gpointer source, gpointer data)
1804 {
1805         MsgInfoUpdate *msginfo_update = (MsgInfoUpdate *) source;
1806         MessageView *messageview = (MessageView *)data;
1807
1808         if (messageview->msginfo != msginfo_update->msginfo)
1809                 return FALSE;
1810
1811         if (msginfo_update->flags & MSGINFO_UPDATE_DELETED) {
1812                 MsgInfo *old_msginfo = messageview->msginfo;
1813                 messageview_clear(messageview);
1814                 messageview_update(messageview, old_msginfo);
1815         }
1816
1817         return FALSE;
1818 }
1819
1820 void messageview_set_menu_sensitive(MessageView *messageview)
1821 {
1822         GtkItemFactory *ifactory;
1823         GtkWidget *menuitem = NULL;
1824
1825         if (!messageview || !messageview->new_window) 
1826                 return;
1827         /* do some smart things */
1828         if (!messageview->menubar) return;
1829         ifactory = gtk_item_factory_from_widget(messageview->menubar);
1830         if (!ifactory) return;
1831
1832         if (prefs_common.hide_quotes) {
1833                 menuitem = NULL;
1834                 if (prefs_common.hide_quotes == 1)
1835                         menuitem = gtk_item_factory_get_widget(ifactory, 
1836                                         "/View/Quotes/Fold all");
1837                 if (prefs_common.hide_quotes == 2)
1838                         menuitem = gtk_item_factory_get_widget(ifactory, 
1839                                         "/View/Quotes/Fold from level 2");
1840                 if (prefs_common.hide_quotes == 3)
1841                         menuitem = gtk_item_factory_get_widget(ifactory, 
1842                                         "/View/Quotes/Fold from level 3");
1843                 gtk_check_menu_item_set_active
1844                         (GTK_CHECK_MENU_ITEM(menuitem),
1845                          TRUE);
1846         }
1847 }
1848
1849 void messageview_learn (MessageView *msgview, gboolean is_spam)
1850 {
1851         if (is_spam) {
1852                 if (procmsg_spam_learner_learn(msgview->msginfo, NULL, TRUE) == 0)
1853                         procmsg_msginfo_set_flags(msgview->msginfo, MSG_SPAM, 0);
1854                 else
1855                         log_error(LOG_PROTOCOL, _("An error happened while learning.\n"));
1856                 
1857         } else {
1858                 if (procmsg_spam_learner_learn(msgview->msginfo, NULL, FALSE) == 0)
1859                         procmsg_msginfo_unset_flags(msgview->msginfo, MSG_SPAM, 0);
1860                 else
1861                         log_error(LOG_PROTOCOL, _("An error happened while learning.\n"));
1862         }
1863         if (msgview->toolbar)
1864                 toolbar_set_learn_button
1865                         (msgview->toolbar,
1866                          MSG_IS_SPAM(msgview->msginfo->flags)?LEARN_HAM:LEARN_SPAM);
1867         else
1868                 toolbar_set_learn_button
1869                         (msgview->mainwin->toolbar,
1870                          MSG_IS_SPAM(msgview->msginfo->flags)?LEARN_HAM:LEARN_SPAM);
1871 }
1872
1873 void messageview_list_urls (MessageView *msgview)
1874 {
1875         GSList *cur = msgview->mimeview->textview->uri_list;
1876         GSList *newlist = NULL;
1877         for (; cur; cur = cur->next) {
1878                 ClickableText *uri = (ClickableText *)cur->data;
1879                 if (uri->uri &&
1880                     (!g_ascii_strncasecmp(uri->uri, "ftp.", 4) ||
1881                      !g_ascii_strncasecmp(uri->uri, "ftp:", 4) ||
1882                      !g_ascii_strncasecmp(uri->uri, "www.", 4) ||
1883                      !g_ascii_strncasecmp(uri->uri, "http:", 5) ||
1884                      !g_ascii_strncasecmp(uri->uri, "https:", 6)))
1885                         newlist = g_slist_prepend(newlist, uri);
1886         }
1887         newlist = g_slist_reverse(newlist);
1888         uri_opener_open(msgview, newlist);
1889         g_slist_free(newlist);
1890 }