Fix untranslatable concatenated strings (i.e. "Default "+"To:"),
[claws.git] / src / messageview.c
1 /*
2  * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 1999-2016 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 #include "defs.h"
20
21 #include <glib.h>
22 #include <glib/gi18n.h>
23 #include <gdk/gdkkeysyms.h>
24 #include <gtk/gtk.h>
25 #include <stdio.h>
26 #include <ctype.h>
27 #include <string.h>
28
29 #include "main.h"
30 #include "messageview.h"
31 #include "message_search.h"
32 #include "headerview.h"
33 #include "summaryview.h"
34 #include "textview.h"
35 #include "mimeview.h"
36 #include "menu.h"
37 #include "about.h"
38 #include "filesel.h"
39 #include "foldersel.h"
40 #include "sourcewindow.h"
41 #include "alertpanel.h"
42 #include "inputdialog.h"
43 #include "mainwindow.h"
44 #include "manage_window.h"
45 #include "procmsg.h"
46 #include "procheader.h"
47 #include "procmime.h"
48 #include "account.h"
49 #include "action.h"
50 #include "prefs_common.h"
51 #include "prefs_account.h"
52 #include "gtkutils.h"
53 #include "utils.h"
54 #include "send_message.h"
55 #include "stock_pixmap.h"
56 #include "hooks.h"
57 #include "filtering.h"
58 #include "partial_download.h"
59 #include "uri_opener.h"
60 #include "inc.h"
61 #include "log.h"
62 #include "privacy.h"
63 #include "combobox.h"
64 #include "printing.h"
65 #include "quoted-printable.h"
66 #include "version.h"
67 #include "statusbar.h"
68 #include "folder_item_prefs.h"
69 #include "avatars.h"
70 #ifndef USE_ALT_ADDRBOOK
71         #include "addressbook.h"
72 #else
73         #include "addressadd.h"
74         #include "addressbook-dbus.h"
75 #endif
76 static GList *messageview_list = NULL;
77
78 static gint messageview_delete_cb       (GtkWidget              *widget,
79                                          GdkEventAny            *event,
80                                          MessageView            *messageview);
81 static void messageview_size_allocate_cb(GtkWidget      *widget,
82                                          GtkAllocation  *allocation);
83 static gboolean key_pressed             (GtkWidget      *widget,
84                                          GdkEventKey    *event,
85                                          MessageView    *messageview);
86 static void return_receipt_show         (NoticeView     *noticeview, 
87                                          MsgInfo        *msginfo);      
88 static void return_receipt_send_clicked (NoticeView     *noticeview, 
89                                          MsgInfo        *msginfo);
90 static void partial_recv_show           (NoticeView     *noticeview, 
91                                          MsgInfo        *msginfo);      
92 static void partial_recv_dload_clicked  (NoticeView     *noticeview, 
93                                          MsgInfo        *msginfo);
94 static void partial_recv_del_clicked    (NoticeView     *noticeview, 
95                                          MsgInfo        *msginfo);
96 static void partial_recv_unmark_clicked (NoticeView     *noticeview, 
97                                          MsgInfo        *msginfo);
98 static void save_as_cb                  (GtkAction      *action,
99                                          gpointer        data);
100 static void page_setup_cb               (GtkAction      *action,
101                                          gpointer        data);
102 static void print_cb                    (GtkAction      *action,
103                                          gpointer        data);
104 static void close_cb                    (GtkAction      *action,
105                                          gpointer        data);
106 static void copy_cb                     (GtkAction      *action,
107                                          gpointer        data);
108 static void allsel_cb                   (GtkAction      *action,
109                                          gpointer        data);
110 static void search_cb                   (GtkAction      *action,
111                                          gpointer        data);
112
113 static void prev_cb                     (GtkAction      *action,
114                                          gpointer        data);
115 static void next_cb                     (GtkAction      *action,
116                                          gpointer        data);
117 static void prev_unread_cb              (GtkAction      *action,
118                                          gpointer        data);
119 static void next_unread_cb              (GtkAction      *action,
120                                          gpointer        data);
121 static void prev_new_cb                 (GtkAction      *action,
122                                          gpointer        data);
123 static void next_new_cb                 (GtkAction      *action,
124                                          gpointer        data);
125 static void prev_marked_cb              (GtkAction      *action,
126                                          gpointer        data);
127 static void next_marked_cb              (GtkAction      *action,
128                                          gpointer        data);
129 static void prev_labeled_cb             (GtkAction      *action,
130                                          gpointer        data);
131 static void next_labeled_cb             (GtkAction      *action,
132                                          gpointer        data);
133 static void prev_history_cb             (GtkAction      *action,
134                                          gpointer        data);
135 static void next_history_cb             (GtkAction      *action,
136                                          gpointer        data);
137 static void parent_cb                   (GtkAction      *action,
138                                          gpointer        data);
139 static void goto_unread_folder_cb       (GtkAction      *action,
140                                          gpointer        data);
141 static void goto_folder_cb              (GtkAction      *action,
142                                          gpointer        data);
143
144 static void scroll_prev_line_cb         (GtkAction      *action,
145                                          gpointer        data);
146 static void scroll_next_line_cb         (GtkAction      *action,
147                                           gpointer        data);
148 static void scroll_next_page_cb         (GtkAction      *action,
149                                          gpointer        data);
150 static void scroll_prev_page_cb         (GtkAction      *action,
151                                          gpointer        data);
152
153 static void set_charset_cb              (GtkAction *action, GtkRadioAction *current, gpointer data);
154 static void set_decode_cb               (GtkAction *action, GtkRadioAction *current, gpointer data);
155
156 static void view_source_cb              (GtkAction      *action,
157                                          gpointer        data);
158
159 static void show_all_header_cb          (GtkToggleAction        *action,
160                                          gpointer        data);
161 static void msg_hide_quotes_cb          (GtkToggleAction        *action,
162                                          gpointer        data);
163
164 static void compose_cb                  (GtkAction      *action,
165                                          gpointer        data);
166 static void reply_cb                    (GtkAction      *action,
167                                          gpointer        data);
168
169 static PrefsAccount *select_account_from_list
170                                         (GList          *ac_list);
171 static void addressbook_open_cb         (GtkAction      *action,
172                                          gpointer        data);
173 static void add_address_cb              (GtkAction      *action,
174                                          gpointer        data);
175 static void create_filter_cb            (GtkAction      *action,
176                                          gpointer        data);
177 static void create_processing_cb        (GtkAction      *action,
178                                          gpointer        data);
179 static void open_urls_cb                (GtkAction      *action,
180                                          gpointer        data);
181
182 static void about_cb                    (GtkAction      *action,
183                                          gpointer        data);
184 static void messageview_update          (MessageView    *msgview,
185                                          MsgInfo        *old_msginfo);
186 static gboolean messageview_update_msg  (gpointer source, gpointer data);
187
188 static void save_part_as_cb(GtkAction *action, gpointer data);
189 static void view_part_as_text_cb(GtkAction *action, gpointer data);
190 static void open_part_cb(GtkAction *action, gpointer data);
191 #ifndef G_OS_WIN32
192 static void open_part_with_cb(GtkAction *action, gpointer data);
193 #endif
194 static void check_signature_cb(GtkAction *action, gpointer data);
195 static void goto_next_part_cb(GtkAction *action, gpointer data);
196 static void goto_prev_part_cb(GtkAction *action, gpointer data);
197
198 static void messageview_nothing_cb         (GtkAction *action, gpointer data)
199 {
200
201 }
202
203 static GList *msgview_list = NULL;
204 static GtkActionEntry msgview_entries[] =
205 {
206         {"Menu",                        NULL, "Menu" },
207 /* menus */
208         {"File",                        NULL, N_("_File") },
209         {"Edit",                        NULL, N_("_Edit") },
210         {"View",                        NULL, N_("_View") },
211         {"Message",                     NULL, N_("_Message") },
212         {"Tools",                       NULL, N_("_Tools") },
213         {"Help",                        NULL, N_("_Help") },
214         {"PlaceHolder",                 NULL, "Placeholder", NULL, NULL, G_CALLBACK(messageview_nothing_cb) },
215
216 /* File menu */
217         {"File/SaveAs",                 NULL, N_("_Save email as..."), "<control>S", NULL, G_CALLBACK(save_as_cb) },
218         {"File/SavePartAs",             NULL, N_("_Save part as..."), "Y", NULL, G_CALLBACK(save_part_as_cb) },
219         {"File/PageSetup",              NULL, N_("Page setup..."), NULL, NULL, G_CALLBACK(page_setup_cb) },
220         {"File/Print",                  NULL, N_("_Print..."), "<control>P", NULL, G_CALLBACK(print_cb) },
221         {"File/---",                    NULL, "---", NULL, NULL, NULL },
222         {"File/Close",                  NULL, N_("_Close"), "<control>W", NULL, G_CALLBACK(close_cb) },
223
224 /* Edit menu */
225         {"Edit/Copy",                   NULL, N_("_Copy"), "<control>C", NULL, G_CALLBACK(copy_cb) },
226         {"Edit/SelectAll",              NULL, N_("_Select all"), "<control>A", NULL, G_CALLBACK(allsel_cb) },
227         {"Edit/---",                    NULL, "---", NULL, NULL, NULL },
228         {"Edit/Find",                   NULL, N_("_Find"), "<control>F", NULL, G_CALLBACK(search_cb) },
229         
230 /* View menu */
231         {"View/Goto",                   NULL, N_("_Go to") },
232         {"View/Goto/Prev",              NULL, N_("_Previous message"), "P", NULL, G_CALLBACK(prev_cb) },
233         {"View/Goto/Next",              NULL, N_("_Next message"), "N", NULL, G_CALLBACK(next_cb) },
234         {"View/Goto/---",               NULL, "---", NULL, NULL, NULL },
235         {"View/Goto/PrevUnread",        NULL, N_("P_revious unread message"), "<shift>P", NULL, G_CALLBACK(prev_unread_cb) },
236         {"View/Goto/NextUnread",        NULL, N_("N_ext unread message"), "<shift>N", NULL, G_CALLBACK(next_unread_cb) },
237         /* {"View/Goto/---",            NULL, "---", NULL, NULL, NULL }, */
238         {"View/Goto/PrevNew",           NULL, N_("Previous ne_w message"), NULL, NULL, G_CALLBACK(prev_new_cb) },
239         {"View/Goto/NextNew",           NULL, N_("Ne_xt new message"), NULL, NULL, G_CALLBACK(next_new_cb) },
240         /* {"View/Goto/---",            NULL, "---", NULL, NULL, NULL }, */
241         {"View/Goto/PrevMarked",        NULL, N_("Previous _marked message"), NULL, NULL, G_CALLBACK(prev_marked_cb) },
242         {"View/Goto/NextMarked",        NULL, N_("Next m_arked message"), NULL, NULL, G_CALLBACK(next_marked_cb) },
243         /* {"View/Goto/---",            NULL, "---", NULL, NULL, NULL }, */
244         {"View/Goto/PrevLabeled",       NULL, N_("Previous _labeled message"), NULL, NULL, G_CALLBACK(prev_labeled_cb) },
245         {"View/Goto/NextLabeled",       NULL, N_("Next la_beled message"), NULL, NULL, G_CALLBACK(next_labeled_cb) },
246         /* {"View/Goto/---",                    NULL, "---", NULL, NULL, NULL }, */
247         {"View/Goto/PrevHistory",       NULL, N_("Previous opened message"), "<alt>Left", NULL, G_CALLBACK(prev_history_cb) },
248         {"View/Goto/NextHistory",       NULL, N_("Next opened message"), "<alt>Right", NULL, G_CALLBACK(next_history_cb) },
249         /* {"View/Goto/---",            NULL, "---", NULL, NULL, NULL }, */
250         {"View/Goto/ParentMessage",     NULL, N_("Parent message"), "<control>Up", NULL, G_CALLBACK(parent_cb) },
251         /* {"View/Goto/---",            NULL, "---", NULL, NULL, NULL }, */
252         {"View/Goto/NextUnreadFolder",  NULL, N_("Next unread _folder"), "<shift>G", NULL, G_CALLBACK(goto_unread_folder_cb) },
253         {"View/Goto/Folder",            NULL, N_("F_older..."), "G", NULL, G_CALLBACK(goto_folder_cb) },
254         /* {"View/Goto/---",            NULL, "---", NULL, NULL, NULL }, */
255         {"View/Goto/NextPart",          NULL, N_("Next part"), "A", NULL, G_CALLBACK(goto_next_part_cb) },
256         {"View/Goto/PrevPart",          NULL, N_("Previous part"), "Z", NULL, G_CALLBACK(goto_prev_part_cb) },
257         {"View/Scroll",                 NULL, N_("Message scroll") },
258         {"View/Scroll/PrevLine",        NULL, N_("Previous line"), NULL, NULL, G_CALLBACK(scroll_prev_line_cb) },
259         {"View/Scroll/NextLine",        NULL, N_("Next line"), NULL, NULL, G_CALLBACK(scroll_next_line_cb) },
260         {"View/Scroll/PrevPage",        NULL, N_("Previous page"), NULL, NULL, G_CALLBACK(scroll_prev_page_cb) },
261         {"View/Scroll/NextPage",        NULL, N_("Next page"), NULL, NULL, G_CALLBACK(scroll_next_page_cb) },
262         /* {"View/Scroll/---",          NULL, "---", NULL, NULL, NULL }, */
263
264         {"View/Encoding",               NULL, N_("Character _encoding") }, /* set_charset_cb */
265         {"View/Encoding/---",           NULL, "---" },
266 #define ENC_ACTION(cs_char,c_char,string) \
267         { "View/Encoding/" cs_char, NULL, N_(string), NULL, NULL, c_char }
268
269         {"View/Encoding/Western",       NULL, N_("Western European") },
270         {"View/Encoding/Baltic",        NULL, N_("Baltic") },
271         {"View/Encoding/Hebrew",        NULL, N_("Hebrew") },
272         {"View/Encoding/Arabic",        NULL, N_("Arabic") },
273         {"View/Encoding/Cyrillic",      NULL, N_("Cyrillic") },
274         {"View/Encoding/Japanese",      NULL, N_("Japanese") },
275         {"View/Encoding/Chinese",       NULL, N_("Chinese") },
276         {"View/Encoding/Korean",        NULL, N_("Korean") },
277         {"View/Encoding/Thai",          NULL, N_("Thai") },
278
279         {"View/Decode",                 NULL, N_("Decode") }, /* set_decode_cb */
280         {"View/Decode/---",             NULL, "---" },
281
282 #define DEC_ACTION(cs_type,c_type,string) \
283         { "View/Decode/" cs_type, NULL, N_(string), NULL, NULL, c_type }
284
285         {"View/---",                    NULL, "---", NULL, NULL, NULL },
286         {"View/MessageSource",          NULL, N_("Mess_age source"), "<control>U", NULL, G_CALLBACK(view_source_cb) },
287         {"View/Part",                   NULL, N_("Message part") },
288         {"View/Part/AsText",            NULL, N_("View as text"), "T", NULL, G_CALLBACK(view_part_as_text_cb) },
289         {"View/Part/Open",              NULL, N_("Open"), "L", NULL, G_CALLBACK(open_part_cb) },
290 #ifndef G_OS_WIN32
291         {"View/Part/OpenWith",          NULL, N_("Open with..."), "O", NULL, G_CALLBACK(open_part_with_cb) },
292 #endif
293
294         {"View/Quotes",                 NULL, N_("Quotes") }, 
295
296 /* Message menu */
297         {"Message/Compose",             NULL, N_("Compose _new message"), "<control>M", NULL, G_CALLBACK(compose_cb) },
298         {"Message/---",                 NULL, "---", NULL, NULL, NULL },
299
300         {"Message/Reply",               NULL, N_("_Reply"), "<control>R", NULL, G_CALLBACK(reply_cb) }, /* COMPOSE_REPLY */
301         {"Message/ReplyTo",             NULL, N_("Repl_y to") }, 
302         {"Message/ReplyTo/All",         NULL, N_("_All"), "<control><shift>R", NULL, G_CALLBACK(reply_cb) }, /* COMPOSE_REPLY_TO_ALL */
303         {"Message/ReplyTo/Sender",      NULL, N_("_Sender"), NULL, NULL, G_CALLBACK(reply_cb) }, /* COMPOSE_REPLY_TO_SENDER */
304         {"Message/ReplyTo/List",        NULL, N_("Mailing _list"), "<control>L", NULL, G_CALLBACK(reply_cb) }, /* COMPOSE_REPLY_TO_LIST */
305         /* {"Message/---",                      NULL, "---", NULL, NULL, NULL }, */
306
307         {"Message/Forward",             NULL, N_("_Forward"), "<control><alt>F", NULL, G_CALLBACK(reply_cb) }, /* COMPOSE_FORWARD_INLINE */
308         {"Message/ForwardAtt",          NULL, N_("For_ward as attachment"), NULL, NULL, G_CALLBACK(reply_cb) }, /* COMPOSE_FORWARD_AS_ATTACH */
309         {"Message/Redirect",            NULL, N_("Redirec_t"), NULL, NULL, G_CALLBACK(reply_cb) }, /* COMPOSE_REDIRECT */
310         {"Message/CheckSignature",              NULL, N_("Check signature"), "C", NULL, G_CALLBACK(check_signature_cb) },
311
312 /* Tools menu */        
313         {"Tools/AddressBook",           NULL, N_("_Address book"), "<control><shift>A", NULL, G_CALLBACK(addressbook_open_cb) }, 
314         {"Tools/AddSenderToAB",         NULL, N_("Add sender to address boo_k"), NULL, NULL, G_CALLBACK(add_address_cb) }, 
315         {"Tools/---",                   NULL, "---", NULL, NULL, NULL },
316
317         {"Tools/CreateFilterRule",                      NULL, N_("_Create filter rule") },
318         {"Tools/CreateFilterRule/Automatically",        NULL, N_("_Automatically"), NULL, NULL, G_CALLBACK(create_filter_cb) }, /* FILTER_BY_AUTO */
319         {"Tools/CreateFilterRule/ByFrom",               NULL, N_("By _From"), NULL, NULL, G_CALLBACK(create_filter_cb) }, /* FILTER_BY_FROM */
320         {"Tools/CreateFilterRule/ByTo",                 NULL, N_("By _To"), NULL, NULL, G_CALLBACK(create_filter_cb) }, /* FILTER_BY_TO     */
321         {"Tools/CreateFilterRule/BySubject",            NULL, N_("By _Subject"), NULL, NULL, G_CALLBACK(create_filter_cb) }, /* FILTER_BY_SUBJECT */
322
323         {"Tools/CreateProcessingRule",                  NULL, N_("Create processing rule") },
324         {"Tools/CreateProcessingRule/Automatically",    NULL, N_("_Automatically"), NULL, NULL, G_CALLBACK(create_processing_cb) }, 
325         {"Tools/CreateProcessingRule/ByFrom",           NULL, N_("By _From"), NULL, NULL, G_CALLBACK(create_processing_cb) }, 
326         {"Tools/CreateProcessingRule/ByTo",             NULL, N_("By _To"), NULL, NULL, G_CALLBACK(create_processing_cb) }, 
327         {"Tools/CreateProcessingRule/BySubject",                NULL, N_("By _Subject"), NULL, NULL, G_CALLBACK(create_processing_cb) }, 
328
329         /* {"Tools/---",                        NULL, "---", NULL, NULL, NULL }, */
330
331         {"Tools/ListUrls",              NULL, N_("List _URLs..."), "<control><shift>U", NULL, G_CALLBACK(open_urls_cb) }, 
332
333         /* {"Tools/---",                        NULL, "---", NULL, NULL, NULL }, */
334         {"Tools/Actions",       NULL, N_("Actio_ns") },
335         {"Tools/Actions/PlaceHolder",   NULL, "Placeholder", NULL, NULL, G_CALLBACK(messageview_nothing_cb) },
336
337 /* Help menu */
338         {"Help/About",          NULL, N_("_About"), NULL, NULL, G_CALLBACK(about_cb) }, 
339 };
340
341 static GtkToggleActionEntry msgview_toggle_entries[] =
342 {
343         {"View/AllHeaders",             NULL, N_("Show all _headers"), "<control>H", NULL, G_CALLBACK(show_all_header_cb) }, /* toggle */
344         {"View/Quotes/CollapseAll",     NULL, N_("_Collapse all"), "<control><shift>Q", NULL, G_CALLBACK(msg_hide_quotes_cb) }, /* 1 toggle */
345         {"View/Quotes/Collapse2",               NULL, N_("Collapse from level _2"), NULL, NULL, G_CALLBACK(msg_hide_quotes_cb) }, /* 2 toggle */
346         {"View/Quotes/Collapse3",               NULL, N_("Collapse from level _3"), NULL, NULL, G_CALLBACK(msg_hide_quotes_cb) }, /* 3 toggle */
347 };
348
349 static GtkRadioActionEntry msgview_radio_enc_entries[] =
350 {
351         ENC_ACTION(CS_AUTO, C_AUTO, N_("_Automatic")), /* RADIO set_charset_cb */
352         ENC_ACTION(CS_US_ASCII, C_US_ASCII, N_("7bit ASCII (US-ASC_II)")), /* RADIO set_charset_cb */
353         ENC_ACTION(CS_UTF_8, C_UTF_8, N_("Unicode (_UTF-8)")), /* RADIO set_charset_cb */
354         ENC_ACTION("Western/"CS_ISO_8859_1, C_ISO_8859_1, "ISO-8859-_1"), /* RADIO set_charset_cb */
355         ENC_ACTION("Western/"CS_ISO_8859_15, C_ISO_8859_15, "ISO-8859-15"), /* RADIO set_charset_cb */
356         ENC_ACTION("Western/"CS_WINDOWS_1252, C_WINDOWS_1252, "Windows-1252"), /* RADIO set_charset_cb */
357         ENC_ACTION(CS_ISO_8859_2, C_ISO_8859_2, N_("Central European (ISO-8859-_2)")), /* RADIO set_charset_cb */
358         ENC_ACTION("Baltic/"CS_ISO_8859_13, C_ISO_8859_13, "ISO-8859-13"), /* RADIO set_charset_cb */
359         ENC_ACTION("Baltic/"CS_ISO_8859_4, C_ISO_8859_14, "ISO-8859-_4"), /* RADIO set_charset_cb */
360         ENC_ACTION(CS_ISO_8859_7, C_ISO_8859_7, N_("Greek (ISO-8859-_7)")), /* RADIO set_charset_cb */
361         ENC_ACTION("Hebrew/"CS_ISO_8859_8, C_ISO_8859_8, "ISO-8859-_8"), /* RADIO set_charset_cb */
362         ENC_ACTION("Hebrew/"CS_WINDOWS_1255, C_WINDOWS_1255, "Windows-1255"), /* RADIO set_charset_cb */
363         ENC_ACTION("Arabic/"CS_ISO_8859_6, C_ISO_8859_6, "ISO-8859-_6"), /* RADIO set_charset_cb */
364         ENC_ACTION("Arabic/"CS_WINDOWS_1256, C_WINDOWS_1256, "Windows-1256"), /* RADIO set_charset_cb */
365         ENC_ACTION(CS_ISO_8859_9, C_ISO_8859_9, N_("Turkish (ISO-8859-_9)")), /* RADIO set_charset_cb */
366         ENC_ACTION("Cyrillic/"CS_ISO_8859_5, C_ISO_8859_5, "ISO-8859-_5"), /* RADIO set_charset_cb */
367         ENC_ACTION("Cyrillic/"CS_KOI8_R, C_KOI8_R, "KOI8-_R"), /* RADIO set_charset_cb */
368         ENC_ACTION("Cyrillic/"CS_MACCYR, C_MACCYR, "MAC_CYR"), /* RADIO set_charset_cb */
369         ENC_ACTION("Cyrillic/"CS_KOI8_U, C_KOI8_U, "KOI8-_U"), /* RADIO set_charset_cb */
370         ENC_ACTION("Cyrillic/"CS_WINDOWS_1251, C_WINDOWS_1251, "Windows-1251"), /* RADIO set_charset_cb */
371         ENC_ACTION("Japanese/"CS_ISO_2022_JP, C_ISO_2022_JP, "ISO-2022-_JP"), /* RADIO set_charset_cb */
372         ENC_ACTION("Japanese/"CS_ISO_2022_JP_2, C_ISO_2022_JP_2, "ISO-2022-JP-_2"), /* RADIO set_charset_cb */
373         ENC_ACTION("Japanese/"CS_EUC_JP, C_EUC_JP, "_EUC-JP"), /* RADIO set_charset_cb */
374         ENC_ACTION("Japanese/"CS_SHIFT_JIS, C_SHIFT_JIS, "_Shift-JIS"), /* RADIO set_charset_cb */
375         ENC_ACTION("Chinese/"CS_GB18030, C_GB18030, "_GB18030"), /* RADIO set_charset_cb */
376         ENC_ACTION("Chinese/"CS_GB2312, C_GB2312, "_GB2312"), /* RADIO set_charset_cb */
377         ENC_ACTION("Chinese/"CS_GBK, C_GBK, "GB_K"), /* RADIO set_charset_cb */
378         ENC_ACTION("Chinese/"CS_BIG5, C_BIG5, "_Big5-JP"), /* RADIO set_charset_cb */
379         ENC_ACTION("Chinese/"CS_EUC_TW, C_EUC_TW, "EUC-_TW"), /* RADIO set_charset_cb */
380         ENC_ACTION("Korean/"CS_EUC_KR, C_EUC_KR, "_EUC-KR"), /* RADIO set_charset_cb */
381         ENC_ACTION("Korean/"CS_ISO_2022_KR, C_ISO_2022_KR, "_ISO-2022-KR"), /* RADIO set_charset_cb */
382         ENC_ACTION("Thai/"CS_TIS_620, C_TIS_620, "_TIS-620-KR"), /* RADIO set_charset_cb */
383         ENC_ACTION("Thai/"CS_WINDOWS_874, C_WINDOWS_874, "_Windows-874"), /* RADIO set_charset_cb */
384 };
385
386 static GtkRadioActionEntry msgview_radio_dec_entries[] =
387 {
388         DEC_ACTION("AutoDetect", 0, N_("_Auto detect")),        /* set_decode_cb */
389         /* --- */
390         DEC_ACTION("8bit", ENC_8BIT, "_8bit"),
391         DEC_ACTION("QP", ENC_QUOTED_PRINTABLE, "_Quoted printable"),
392         DEC_ACTION("B64", ENC_BASE64, "_Base64"),
393         DEC_ACTION("Uuencode", ENC_X_UUENCODE, "_Uuencode"),
394 };
395
396 MessageView *messageview_create(MainWindow *mainwin)
397 {
398         MessageView *messageview;
399         GtkWidget *vbox;
400         HeaderView *headerview;
401         MimeView *mimeview;
402         NoticeView *noticeview;
403
404         debug_print("Creating message view...\n");
405         messageview = g_new0(MessageView, 1);
406
407         headerview = headerview_create();
408
409         noticeview = noticeview_create(mainwin);
410
411         mimeview = mimeview_create(mainwin);
412         mimeview->textview = textview_create();
413         mimeview->textview->messageview = messageview;
414         mimeview->messageview = messageview;
415
416         vbox = gtk_vbox_new(FALSE, 0);
417         gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET_PTR(headerview),
418                            FALSE, FALSE, 0);
419         gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET_PTR(noticeview),
420                            FALSE, FALSE, 0);
421         gtk_box_pack_start(GTK_BOX(vbox),
422                            GTK_WIDGET_PTR(mimeview), TRUE, TRUE, 0);
423         gtk_widget_show(vbox);
424
425         messageview->vbox        = vbox;
426         messageview->new_window  = FALSE;
427         messageview->window      = NULL;
428         messageview->headerview  = headerview;
429         messageview->mimeview    = mimeview;
430         messageview->noticeview = noticeview;
431         messageview->mainwin    = mainwin;
432
433         messageview->statusbar     = NULL;
434         messageview->statusbar_cid = 0;
435
436         messageview->show_full_text= FALSE;
437         messageview->update_needed = FALSE;
438
439         messageview->msginfo_update_callback_id =
440                 hooks_register_hook(MSGINFO_UPDATE_HOOKLIST, messageview_update_msg, (gpointer) messageview);
441
442         return messageview;
443 }
444
445 const GList *messageview_get_msgview_list(void)
446 {
447         return msgview_list;
448 }
449
450 void messageview_update_actions_menu(MessageView *msgview)
451 {
452         /* Messages opened in a new window do not have a menu bar */
453         if (msgview->menubar == NULL)
454                 return;
455         action_update_msgview_menu(msgview->ui_manager, "/Menu/Tools/Actions", msgview);
456 }
457
458 static void messageview_add_toolbar(MessageView *msgview, GtkWidget *window) 
459 {
460         GtkWidget *handlebox;
461         GtkWidget *vbox;
462         GtkWidget *menubar;
463 #ifndef GENERIC_UMPC
464         GtkWidget *statusbar = NULL;
465 #endif
466         GtkActionGroup *action_group;
467
468
469         vbox = gtk_vbox_new(FALSE, 0);
470         gtk_widget_show(vbox);
471         gtk_container_add(GTK_CONTAINER(window), vbox); 
472
473         msgview->ui_manager = gtk_ui_manager_new();
474         action_group = cm_menu_create_action_group_full(msgview->ui_manager,"Menu", msgview_entries,
475                         G_N_ELEMENTS(msgview_entries), (gpointer)msgview);
476         gtk_action_group_add_toggle_actions(action_group, msgview_toggle_entries,
477                         G_N_ELEMENTS(msgview_toggle_entries), (gpointer)msgview);
478         gtk_action_group_add_radio_actions(action_group, msgview_radio_enc_entries,
479                         G_N_ELEMENTS(msgview_radio_enc_entries), C_AUTO, G_CALLBACK(set_charset_cb), (gpointer)msgview);
480         gtk_action_group_add_radio_actions(action_group, msgview_radio_dec_entries,
481                         G_N_ELEMENTS(msgview_radio_dec_entries), C_AUTO, G_CALLBACK(set_decode_cb), (gpointer)msgview);
482
483         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/", "Menu", NULL, GTK_UI_MANAGER_MENUBAR)
484         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu", "File", "File", GTK_UI_MANAGER_MENU)
485         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu", "Edit", "Edit", GTK_UI_MANAGER_MENU)
486         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu", "View", "View", GTK_UI_MANAGER_MENU)
487         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu", "Message", "Message", GTK_UI_MANAGER_MENU)
488         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu", "Tools", "Tools", GTK_UI_MANAGER_MENU)
489         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu", "Help", "Help", GTK_UI_MANAGER_MENU)
490
491 /* File menu */
492         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/File", "SaveAs", "File/SaveAs", GTK_UI_MANAGER_MENUITEM)
493         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/File", "SavePartAs", "File/SavePartAs", GTK_UI_MANAGER_MENUITEM)
494         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/File", "Separator1", "File/---", GTK_UI_MANAGER_SEPARATOR)
495         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/File", "PageSetup", "File/PageSetup", GTK_UI_MANAGER_MENUITEM)
496         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/File", "Print", "File/Print", GTK_UI_MANAGER_MENUITEM)
497         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/File", "Separator2", "File/---", GTK_UI_MANAGER_SEPARATOR)
498         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/File", "Close", "File/Close", GTK_UI_MANAGER_MENUITEM)
499
500 /* Edit menu */
501         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/Edit", "Copy", "Edit/Copy", GTK_UI_MANAGER_MENUITEM)
502         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/Edit", "SelectAll", "Edit/SelectAll", GTK_UI_MANAGER_MENUITEM)
503         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/Edit", "Separator1", "Edit/---", GTK_UI_MANAGER_SEPARATOR)
504         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/Edit", "Find", "Edit/Find", GTK_UI_MANAGER_MENUITEM)
505
506 /* View menu */
507         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View", "Goto", "View/Goto", GTK_UI_MANAGER_MENU)
508         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Goto", "Prev", "View/Goto/Prev", GTK_UI_MANAGER_MENUITEM)
509         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Goto", "Next", "View/Goto/Next", GTK_UI_MANAGER_MENUITEM)
510         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Goto", "Separator1", "View/Goto/---", GTK_UI_MANAGER_SEPARATOR)
511         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Goto", "PrevUnread", "View/Goto/PrevUnread", GTK_UI_MANAGER_MENUITEM)
512         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Goto", "NextUnread", "View/Goto/NextUnread", GTK_UI_MANAGER_MENUITEM)
513         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Goto", "Separator2", "View/Goto/---", GTK_UI_MANAGER_SEPARATOR)
514         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Goto", "PrevNew", "View/Goto/PrevNew", GTK_UI_MANAGER_MENUITEM)
515         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Goto", "NextNew", "View/Goto/NextNew", GTK_UI_MANAGER_MENUITEM)
516         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Goto", "Separator3", "View/Goto/---", GTK_UI_MANAGER_SEPARATOR)
517         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Goto", "PrevMarked", "View/Goto/PrevMarked", GTK_UI_MANAGER_MENUITEM)
518         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Goto", "NextMarked", "View/Goto/NextMarked", GTK_UI_MANAGER_MENUITEM)
519         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Goto", "Separator4", "View/Goto/---", GTK_UI_MANAGER_SEPARATOR)
520         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Goto", "PrevLabeled", "View/Goto/PrevLabeled", GTK_UI_MANAGER_MENUITEM)
521         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Goto", "NextLabeled", "View/Goto/NextLabeled", GTK_UI_MANAGER_MENUITEM)
522         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Goto", "Separator5", "View/Goto/---", GTK_UI_MANAGER_SEPARATOR)
523         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Goto", "PrevHistory", "View/Goto/PrevHistory", GTK_UI_MANAGER_MENUITEM)
524         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Goto", "NextHistory", "View/Goto/NextHistory", GTK_UI_MANAGER_MENUITEM)
525         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Goto", "Separator6", "View/Goto/---", GTK_UI_MANAGER_SEPARATOR)
526         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Goto", "ParentMessage", "View/Goto/ParentMessage", GTK_UI_MANAGER_MENUITEM)
527         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Goto", "Separator7", "View/Goto/---", GTK_UI_MANAGER_SEPARATOR)
528         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Goto", "NextUnreadFolder", "View/Goto/NextUnreadFolder", GTK_UI_MANAGER_MENUITEM)
529         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Goto", "Folder", "View/Goto/Folder", GTK_UI_MANAGER_MENUITEM)
530         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Goto", "Separator8", "View/Goto/---", GTK_UI_MANAGER_SEPARATOR)
531         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Goto", "NextPart", "View/Goto/NextPart", GTK_UI_MANAGER_MENUITEM)
532         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Goto", "PrevPart", "View/Goto/PrevPart", GTK_UI_MANAGER_MENUITEM)
533
534         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View", "Scroll", "View/Scroll", GTK_UI_MANAGER_MENU)
535         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Scroll", "PrevLine", "View/Scroll/PrevLine", GTK_UI_MANAGER_MENUITEM)
536         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Scroll", "NextLine", "View/Scroll/NextLine", GTK_UI_MANAGER_MENUITEM)
537         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Scroll", "PrevPage", "View/Scroll/PrevPage", GTK_UI_MANAGER_MENUITEM)
538         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Scroll", "NextPage", "View/Scroll/NextPage", GTK_UI_MANAGER_MENUITEM)
539
540         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View", "Separator1", "View/---", GTK_UI_MANAGER_SEPARATOR)
541
542         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View", "Encoding", "View/Encoding", GTK_UI_MANAGER_MENU)
543         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Encoding", CS_AUTO, "View/Encoding/"CS_AUTO, GTK_UI_MANAGER_MENUITEM)
544         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Encoding", "Separator1", "View/Encoding/---", GTK_UI_MANAGER_SEPARATOR)
545         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Encoding", CS_US_ASCII, "View/Encoding/"CS_US_ASCII, GTK_UI_MANAGER_MENUITEM)
546         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Encoding", CS_UTF_8, "View/Encoding/"CS_UTF_8, GTK_UI_MANAGER_MENUITEM)
547         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Encoding", "Separator2", "View/Encoding/---", GTK_UI_MANAGER_SEPARATOR)
548
549         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Encoding", "Western", "View/Encoding/Western", GTK_UI_MANAGER_MENU)
550         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Encoding/Western", CS_ISO_8859_1, "View/Encoding/Western/"CS_ISO_8859_1, GTK_UI_MANAGER_MENUITEM)
551         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Encoding/Western", CS_ISO_8859_15, "View/Encoding/Western/"CS_ISO_8859_15, GTK_UI_MANAGER_MENUITEM)
552         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Encoding/Western", CS_WINDOWS_1252, "View/Encoding/Western/"CS_WINDOWS_1252, GTK_UI_MANAGER_MENUITEM)
553
554         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Encoding", CS_ISO_8859_2, "View/Encoding/"CS_ISO_8859_2, GTK_UI_MANAGER_MENUITEM)
555
556         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Encoding", "Baltic", "View/Encoding/Baltic", GTK_UI_MANAGER_MENU)
557         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Encoding/Baltic", CS_ISO_8859_13, "View/Encoding/Baltic/"CS_ISO_8859_13, GTK_UI_MANAGER_MENUITEM)
558         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Encoding/Baltic", CS_ISO_8859_4, "View/Encoding/Baltic/"CS_ISO_8859_4, GTK_UI_MANAGER_MENUITEM)
559
560         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Encoding", CS_ISO_8859_7, "View/Encoding/"CS_ISO_8859_7, GTK_UI_MANAGER_MENUITEM)
561
562         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Encoding", "Hebrew", "View/Encoding/Hebrew", GTK_UI_MANAGER_MENU)
563         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Encoding/Hebrew", CS_ISO_8859_8, "View/Encoding/Hebrew/"CS_ISO_8859_8, GTK_UI_MANAGER_MENUITEM)
564         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Encoding/Hebrew", CS_WINDOWS_1255, "View/Encoding/Hebrew/"CS_WINDOWS_1255, GTK_UI_MANAGER_MENUITEM)
565
566         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Encoding", "Arabic", "View/Encoding/Arabic", GTK_UI_MANAGER_MENU)
567         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Encoding/Arabic", CS_ISO_8859_6, "View/Encoding/Arabic/"CS_ISO_8859_6, GTK_UI_MANAGER_MENUITEM)
568         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Encoding/Arabic", CS_WINDOWS_1256, "View/Encoding/Arabic/"CS_WINDOWS_1256, GTK_UI_MANAGER_MENUITEM)
569
570         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Encoding", CS_ISO_8859_9, "View/Encoding/"CS_ISO_8859_9, GTK_UI_MANAGER_MENUITEM)
571
572         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Encoding", "Cyrillic", "View/Encoding/Cyrillic", GTK_UI_MANAGER_MENU)
573         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Encoding/Cyrillic", CS_ISO_8859_5, "View/Encoding/Cyrillic/"CS_ISO_8859_5, GTK_UI_MANAGER_MENUITEM)
574         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Encoding/Cyrillic", CS_KOI8_R, "View/Encoding/Cyrillic/"CS_KOI8_R, GTK_UI_MANAGER_MENUITEM)
575         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Encoding/Cyrillic", CS_MACCYR, "View/Encoding/Cyrillic/"CS_MACCYR, GTK_UI_MANAGER_MENUITEM)
576         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Encoding/Cyrillic", CS_KOI8_U, "View/Encoding/Cyrillic/"CS_KOI8_U, GTK_UI_MANAGER_MENUITEM)
577         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Encoding/Cyrillic", CS_WINDOWS_1251, "View/Encoding/Cyrillic/"CS_WINDOWS_1251, GTK_UI_MANAGER_MENUITEM)
578
579         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Encoding", "Japanese", "View/Encoding/Japanese", GTK_UI_MANAGER_MENU)
580         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Encoding/Japanese", CS_ISO_2022_JP, "View/Encoding/Japanese/"CS_ISO_2022_JP, GTK_UI_MANAGER_MENUITEM)
581         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Encoding/Japanese", CS_ISO_2022_JP_2, "View/Encoding/Japanese/"CS_ISO_2022_JP_2, GTK_UI_MANAGER_MENUITEM)
582         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Encoding/Japanese", CS_EUC_JP, "View/Encoding/Japanese/"CS_EUC_JP, GTK_UI_MANAGER_MENUITEM)
583         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Encoding/Japanese", CS_SHIFT_JIS, "View/Encoding/Japanese/"CS_SHIFT_JIS, GTK_UI_MANAGER_MENUITEM)
584
585         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Encoding", "Chinese", "View/Encoding/Chinese", GTK_UI_MANAGER_MENU)
586         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Encoding/Chinese", CS_GB18030, "View/Encoding/Chinese/"CS_GB18030, GTK_UI_MANAGER_MENUITEM)
587         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Encoding/Chinese", CS_GB2312, "View/Encoding/Chinese/"CS_GB2312, GTK_UI_MANAGER_MENUITEM)
588         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Encoding/Chinese", CS_GBK, "View/Encoding/Chinese/"CS_GBK, GTK_UI_MANAGER_MENUITEM)
589         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Encoding/Chinese", CS_BIG5, "View/Encoding/Chinese/"CS_BIG5, GTK_UI_MANAGER_MENUITEM)
590         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Encoding/Chinese", CS_EUC_TW, "View/Encoding/Chinese/"CS_EUC_TW, GTK_UI_MANAGER_MENUITEM)
591
592         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Encoding", "Korean", "View/Encoding/Korean", GTK_UI_MANAGER_MENU)
593         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Encoding/Korean", CS_EUC_KR, "View/Encoding/Korean/"CS_EUC_KR, GTK_UI_MANAGER_MENUITEM)
594         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Encoding/Korean", CS_ISO_2022_KR, "View/Encoding/Korean/"CS_ISO_2022_KR, GTK_UI_MANAGER_MENUITEM)
595
596         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Encoding", "Thai", "View/Encoding/Thai", GTK_UI_MANAGER_MENU)
597         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Encoding/Thai", CS_TIS_620, "View/Encoding/Thai/"CS_TIS_620, GTK_UI_MANAGER_MENUITEM)
598         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Encoding/Thai", CS_WINDOWS_874, "View/Encoding/Thai/"CS_WINDOWS_874, GTK_UI_MANAGER_MENUITEM)
599
600         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View", "Decode", "View/Decode", GTK_UI_MANAGER_MENU)
601         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Decode", "AutoDetect", "View/Decode/AutoDetect", GTK_UI_MANAGER_MENUITEM)
602         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Decode", "Separator1", "View/Decode/---", GTK_UI_MANAGER_SEPARATOR)
603         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Decode", "8bit", "View/Decode/8bit", GTK_UI_MANAGER_MENUITEM)
604         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Decode", "QP", "View/Decode/QP", GTK_UI_MANAGER_MENUITEM)
605         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Decode", "B64", "View/Decode/B64", GTK_UI_MANAGER_MENUITEM)
606         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Decode", "Uuencode", "View/Decode/Uuencode", GTK_UI_MANAGER_MENUITEM)
607
608         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View", "Separator2", "View/---", GTK_UI_MANAGER_SEPARATOR)
609
610         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View", "MessageSource", "View/MessageSource", GTK_UI_MANAGER_MENUITEM)
611         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View", "AllHeaders", "View/AllHeaders", GTK_UI_MANAGER_MENUITEM)
612         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View", "Quotes", "View/Quotes", GTK_UI_MANAGER_MENU)
613         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Quotes", "CollapseAll", "View/Quotes/CollapseAll", GTK_UI_MANAGER_MENUITEM)
614         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Quotes", "Collapse2", "View/Quotes/Collapse2", GTK_UI_MANAGER_MENUITEM)
615         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Quotes", "Collapse3", "View/Quotes/Collapse3", GTK_UI_MANAGER_MENUITEM)
616         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View", "Part", "View/Part", GTK_UI_MANAGER_MENU)
617         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Part", "AsText", "View/Part/AsText", GTK_UI_MANAGER_MENUITEM)
618         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Part", "Open", "View/Part/Open", GTK_UI_MANAGER_MENUITEM)
619 #ifndef G_OS_WIN32
620         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Part", "OpenWith", "View/Part/OpenWith", GTK_UI_MANAGER_MENUITEM)
621 #endif
622
623 /* Message menu */
624         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/Message", "Compose", "Message/Compose", GTK_UI_MANAGER_MENUITEM)
625         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/Message", "Separator1", "Message/---", GTK_UI_MANAGER_SEPARATOR)
626         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/Message", "Reply", "Message/Reply", GTK_UI_MANAGER_MENUITEM)
627         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/Message", "ReplyTo", "Message/ReplyTo", GTK_UI_MANAGER_MENU)
628         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/Message/ReplyTo", "All", "Message/ReplyTo/All", GTK_UI_MANAGER_MENUITEM)
629         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/Message/ReplyTo", "Sender", "Message/ReplyTo/Sender", GTK_UI_MANAGER_MENUITEM)
630         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/Message/ReplyTo", "List", "Message/ReplyTo/List", GTK_UI_MANAGER_MENUITEM)
631         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/Message", "Separator2", "Message/---", GTK_UI_MANAGER_SEPARATOR)
632         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/Message", "Forward", "Message/Forward", GTK_UI_MANAGER_MENUITEM)
633         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/Message", "ForwardAtt", "Message/ForwardAtt", GTK_UI_MANAGER_MENUITEM)
634         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/Message", "Redirect", "Message/Redirect", GTK_UI_MANAGER_MENUITEM)
635         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/Message", "CheckSignature", "Message/CheckSignature", GTK_UI_MANAGER_MENUITEM)
636
637 /* Tools menu */
638         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/Tools", "AddressBook", "Tools/AddressBook", GTK_UI_MANAGER_MENUITEM)
639         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/Tools", "AddSenderToAB", "Tools/AddSenderToAB", GTK_UI_MANAGER_MENUITEM)
640         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/Tools", "Separator1", "Tools/---", GTK_UI_MANAGER_SEPARATOR)
641
642         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/Tools", "CreateFilterRule", "Tools/CreateFilterRule", GTK_UI_MANAGER_MENU)
643         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/Tools/CreateFilterRule", "Automatically", "Tools/CreateFilterRule/Automatically", GTK_UI_MANAGER_MENUITEM)
644         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/Tools/CreateFilterRule", "ByFrom", "Tools/CreateFilterRule/ByFrom", GTK_UI_MANAGER_MENUITEM)
645         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/Tools/CreateFilterRule", "ByTo", "Tools/CreateFilterRule/ByTo", GTK_UI_MANAGER_MENUITEM)
646         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/Tools/CreateFilterRule", "BySubject", "Tools/CreateFilterRule/BySubject", GTK_UI_MANAGER_MENUITEM)
647
648         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/Tools", "CreateProcessingRule", "Tools/CreateProcessingRule", GTK_UI_MANAGER_MENU)
649         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/Tools/CreateProcessingRule", "Automatically", "Tools/CreateProcessingRule/Automatically", GTK_UI_MANAGER_MENUITEM)
650         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/Tools/CreateProcessingRule", "ByFrom", "Tools/CreateProcessingRule/ByFrom", GTK_UI_MANAGER_MENUITEM)
651         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/Tools/CreateProcessingRule", "ByTo", "Tools/CreateProcessingRule/ByTo", GTK_UI_MANAGER_MENUITEM)
652         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/Tools/CreateProcessingRule", "BySubject", "Tools/CreateProcessingRule/BySubject", GTK_UI_MANAGER_MENUITEM)
653         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/Tools", "Separator2", "Tools/---", GTK_UI_MANAGER_SEPARATOR)
654         
655         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/Tools", "ListUrls", "Tools/ListUrls", GTK_UI_MANAGER_MENUITEM)
656         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/Tools", "Separator3", "Tools/---", GTK_UI_MANAGER_SEPARATOR)
657
658         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/Tools", "Actions", "Tools/Actions", GTK_UI_MANAGER_MENU)
659         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/Tools/Actions", "PlaceHolder", "Tools/Actions/PlaceHolder", GTK_UI_MANAGER_MENUITEM)
660
661 /* Help menu */
662         MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/Help", "About", "Help/About", GTK_UI_MANAGER_MENUITEM)
663
664         menubar = gtk_ui_manager_get_widget(msgview->ui_manager, "/Menu");
665         gtk_widget_show_all(menubar);
666         gtk_window_add_accel_group(GTK_WINDOW(window), gtk_ui_manager_get_accel_group(msgview->ui_manager));
667
668         gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, TRUE, 0);
669
670         cm_toggle_menu_set_active_full(msgview->ui_manager, "Menu/View/AllHeaders",
671                                         prefs_common.show_all_headers);
672
673         if (prefs_common.toolbar_detachable) {
674                 handlebox = gtk_handle_box_new();
675         } else {
676                 handlebox = gtk_hbox_new(FALSE, 0);
677         }
678         gtk_box_pack_start(GTK_BOX(vbox), handlebox, FALSE, FALSE, 0);
679         gtk_widget_realize(handlebox);
680         msgview->toolbar = toolbar_create(TOOLBAR_MSGVIEW, handlebox,
681                                           (gpointer)msgview);
682 #ifndef GENERIC_UMPC
683         statusbar = gtk_statusbar_new();
684         gtk_widget_show(statusbar);
685         gtk_box_pack_end(GTK_BOX(vbox), statusbar, FALSE, FALSE, 0);
686         msgview->statusbar = statusbar;
687         msgview->statusbar_cid = gtk_statusbar_get_context_id
688                 (GTK_STATUSBAR(statusbar), "Message View");
689 #else
690         msgview->statusbar = NULL;
691         msgview->statusbar_cid = 0;
692 #endif
693
694
695         msgview->handlebox = handlebox;
696         msgview->menubar   = menubar;
697
698         gtk_container_add(GTK_CONTAINER(vbox),
699                           GTK_WIDGET_PTR(msgview));
700
701         messageview_update_actions_menu(msgview);
702
703         msgview_list = g_list_append(msgview_list, msgview);
704 }
705
706 static MessageView *messageview_create_with_new_window_visible(MainWindow *mainwin, gboolean show)
707 {
708         MessageView *msgview;
709         GtkWidget *window;
710         static GdkGeometry geometry;
711
712         window = gtkut_window_new(GTK_WINDOW_TOPLEVEL, "messageview");
713         gtk_window_set_title(GTK_WINDOW(window), _("Claws Mail - Message View"));
714         gtk_window_set_resizable(GTK_WINDOW(window), TRUE);
715
716         if (!geometry.min_height) {
717                 geometry.min_width = 320;
718                 geometry.min_height = 200;
719         }
720         gtk_window_set_geometry_hints(GTK_WINDOW(window), NULL, &geometry,
721                                       GDK_HINT_MIN_SIZE);
722
723         gtk_widget_set_size_request(window, prefs_common.msgwin_width,
724                                     prefs_common.msgwin_height);
725 #ifdef G_OS_WIN32
726         gtk_window_move(GTK_WINDOW(window), 48, 48);
727 #endif
728
729         msgview = messageview_create(mainwin);
730
731         g_signal_connect(G_OBJECT(window), "size_allocate",
732                          G_CALLBACK(messageview_size_allocate_cb),
733                          msgview);
734         g_signal_connect(G_OBJECT(window), "delete_event",
735                          G_CALLBACK(messageview_delete_cb), msgview);
736         g_signal_connect(G_OBJECT(window), "key_press_event",
737                          G_CALLBACK(key_pressed), msgview);
738         messageview_add_toolbar(msgview, window);
739
740         if (show) {
741                 gtk_widget_show(window);
742         } else {
743                 gtk_widget_realize(window);
744         }
745
746         msgview->new_window = TRUE;
747         msgview->window = window;
748         msgview->visible = TRUE;
749
750         toolbar_set_style(msgview->toolbar->toolbar, msgview->handlebox, 
751                           prefs_common.toolbar_style);
752         messageview_init(msgview);
753
754         if (show) {
755                 GTK_EVENTS_FLUSH();
756                 gtk_widget_grab_focus(msgview->mimeview->textview->text);
757         }
758
759         return msgview;
760 }
761
762 MessageView *messageview_create_with_new_window(MainWindow *mainwin)
763 {
764         return messageview_create_with_new_window_visible(mainwin, TRUE);
765 }
766 void messageview_init(MessageView *messageview)
767 {
768         headerview_init(messageview->headerview);
769         mimeview_init(messageview->mimeview);
770         /*messageview_set_font(messageview);*/
771
772         noticeview_hide(messageview->noticeview);
773 }
774
775 static void notification_convert_header(gchar *dest, gint len, 
776                                         const gchar *src_,
777                                         gint header_len)
778 {
779         char *src;
780
781         cm_return_if_fail(src_ != NULL);
782         cm_return_if_fail(dest != NULL);
783
784         if (len < 1) return;
785
786         Xstrndup_a(src, src_, len, return);
787
788         remove_return(src);
789
790         if (is_ascii_str(src)) {
791                 strncpy2(dest, src, len);
792                 dest[len - 1] = '\0';
793                 return;
794         } else
795                 conv_encode_header(dest, len, src, header_len, FALSE);
796 }
797
798 static gint disposition_notification_send(MsgInfo *msginfo)
799 {
800         gchar buf[BUFFSIZE];
801         gchar tmp[MAXPATHLEN + 1];
802         FILE *fp;
803         GList *ac_list;
804         PrefsAccount *account = NULL;
805         gint ok;
806         gchar *to;
807         FolderItem *queue, *outbox;
808         gint num;
809         gchar *path;
810         gchar *addr;
811         gchar *addrp;
812         gchar *foo = NULL;
813         gboolean queued_removed = FALSE;
814         gchar *boundary = NULL;
815         gchar *date = NULL;
816         gchar *orig_to = NULL;
817         gchar *enc_sub = NULL;
818
819         if (!msginfo->extradata)
820                 return -1;
821         if (!msginfo->extradata->returnreceiptto && 
822             !msginfo->extradata->dispositionnotificationto) 
823                 return -1;
824
825         /* RFC2298: Test for Return-Path */
826         if (msginfo->extradata->dispositionnotificationto)
827                 to = msginfo->extradata->dispositionnotificationto;
828         else
829                 to = msginfo->extradata->returnreceiptto;
830
831         ok = procheader_get_header_from_msginfo(msginfo, buf, sizeof(buf),
832                                 "Return-Path:");
833         if (ok == 0) {
834                 gchar *to_addr = g_strdup(to);
835                 extract_address(to_addr);
836                 extract_address(buf);
837                 ok = strcasecmp(to_addr, buf);
838                 g_free(to_addr);
839         } else {
840                 g_strlcpy(buf, _("<No Return-Path found>"), 
841                                 sizeof(buf));
842         }
843         
844         if (ok != 0) {
845                 AlertValue val;
846                 gchar *message;
847                 message = g_markup_printf_escaped(
848                   _("The notification address to which the return receipt is\n"
849                     "to be sent does not correspond to the return path:\n"
850                     "Notification address: %s\n"
851                     "Return path: %s\n"
852                     "It is advised to not send the return receipt."),
853                   to, buf);
854                 val = alertpanel_full(_("Warning"), message,
855                                 _("_Don't Send"), _("_Send"), NULL, FALSE,
856                                 NULL, ALERT_WARNING, G_ALERTDEFAULT);
857                 g_free(message);                                
858                 if (val != G_ALERTALTERNATE)
859                         return -1;
860         }
861
862         ac_list = account_find_all_from_address(NULL, msginfo->to);
863         ac_list = account_find_all_from_address(ac_list, msginfo->cc);
864
865         if (ac_list == NULL) {
866                 AlertValue val = 
867                 alertpanel_full(_("Warning"),
868                   _("This message is asking for a return receipt notification\n"
869                     "but according to its 'To' and 'Cc' headers it was not\n"
870                     "officially addressed to you.\n"
871                     "It is advised to not send the return receipt."),
872                   _("_Don't Send"), _("_Send"), NULL, FALSE,
873                   NULL, ALERT_WARNING, G_ALERTDEFAULT);
874                 if (val != G_ALERTALTERNATE)
875                         return -1;
876         }
877
878         if (g_list_length(ac_list) > 1) {
879                 if ((account = select_account_from_list(ac_list)) == NULL)
880                         return -1;
881         }
882         else if (ac_list != NULL)
883                 account = (PrefsAccount *) ac_list->data;
884         g_list_free(ac_list);
885
886         if (account == NULL)
887                 account = account_get_default();
888         if (!account || account->protocol == A_NNTP) {
889                 alertpanel_error(_("Account for sending mail is not specified.\n"
890                                    "Please select a mail account before sending."));
891                 return -1;
892         }
893
894         /* write to temporary file */
895         g_snprintf(tmp, sizeof(tmp), "%s%ctmpmsg%p",
896                    get_rc_dir(), G_DIR_SEPARATOR, msginfo);
897
898         if ((fp = g_fopen(tmp, "wb")) == NULL) {
899                 FILE_OP_ERROR(tmp, "fopen");
900                 return -1;
901         }
902
903         /* chmod for security */
904         if (change_file_mode_rw(fp, tmp) < 0) {
905                 FILE_OP_ERROR(tmp, "chmod");
906                 g_warning("can't change file mode");
907         }
908         
909         addr = g_strdup(to);
910         
911         extract_address(addr);
912         addrp = addr;
913         
914         /* write queue headers */
915         ok = fprintf(fp, "AF:\n"
916                     "NF:0\n"
917                     "PS:10\n"
918                     "SRH:1\n"
919                     "SFN:\n"
920                     "DSR:\n"
921                     "MID:\n"
922                     "CFG:\n"
923                     "PT:0\n"
924                     "S:%s\n"
925                     "RQ:\n"
926                     "SSV:%s\n"
927                     "SSH:\n"
928                     "R:<%s>\n", 
929                     account->address,
930                     account->smtp_server?account->smtp_server:"",
931                     addrp);
932
933         g_free(addrp);
934         if (ok < 0)
935                 goto FILE_ERROR;
936         
937         /* check whether we need to save the message */
938         outbox = account_get_special_folder(account, F_OUTBOX); 
939         if (folder_get_default_outbox() == outbox && !prefs_common.savemsg)
940                 outbox = NULL;
941         if (outbox) {
942                 path = folder_item_get_identifier(outbox);
943                 ok = fprintf(fp, "SCF:%s\n", path);
944                 g_free(path);
945                 
946                 if (ok < 0)
947                         goto FILE_ERROR;
948         }               
949
950         if (fprintf(fp, "X-Claws-End-Special-Headers: 1\n") < 0)
951                 goto FILE_ERROR;
952
953         /* Date */
954         get_rfc822_date(buf, sizeof(buf));
955         if (fprintf(fp, "Date: %s\n", buf) < 0)
956                 goto FILE_ERROR;
957
958         /* From */
959         if (account->name && *account->name) {
960                 notification_convert_header
961                         (buf, sizeof(buf), account->name,
962                          strlen("From: "));
963                 if (fprintf(fp, "From: %s <%s>\n", buf, account->address) < 0)
964                         goto FILE_ERROR;
965         } else
966                 if (fprintf(fp, "From: %s\n", account->address) < 0)
967                         goto FILE_ERROR;
968
969         if (fprintf(fp, "To: %s\n", to) < 0)
970                 goto FILE_ERROR;
971
972         /* Subject */
973         notification_convert_header(buf, sizeof(buf), msginfo->subject,
974                                     strlen("Subject: "));
975         if (fprintf(fp, "Subject: Disposition notification: %s\n", buf) < 0)
976                 goto FILE_ERROR;
977
978         /* Message ID */
979         if (account->gen_msgid) {
980                 gchar *addr = prefs_account_generate_msgid(account);
981                 if (fprintf(fp, "Message-ID: <%s>\n", addr) < 0) {
982                         g_free(addr);
983                         goto FILE_ERROR;
984                 }
985                 g_free(addr);
986         }
987
988         boundary = generate_mime_boundary("DN");
989         get_rfc822_date(buf, sizeof(buf));
990         date = g_strdup(buf);
991         if (msginfo->to) {
992                 orig_to = g_strdup(msginfo->to);
993                 extract_address(orig_to);
994         }
995         if (msginfo->subject && *(msginfo->subject)) {
996                 enc_sub = g_malloc0(strlen(msginfo->subject)*8);
997                 qp_encode_line(enc_sub, (const guchar *)msginfo->subject);
998                 g_strstrip(enc_sub);
999         }
1000         ok = fprintf(fp,"MIME-Version: 1.0\n"
1001                         "Content-Type: multipart/report; report-type=disposition-notification;\n"
1002                         "  boundary=\"%s\"\n"
1003                         "\n"
1004                         "--%s\n"
1005                         "Content-Type: text/plain; charset=UTF-8\n"
1006                         "Content-Transfer-Encoding: quoted-printable\n"
1007                         "\n"
1008                         "The message sent on: %s\n"
1009                         "To: %s\n"
1010                         "With subject: \"%s\"\n"
1011                         "has been displayed at %s.\n"
1012                         "\n"
1013                         "There is no guarantee that the message has been read or understood.\n"
1014                         "\n"
1015                         "--%s\n"
1016                         "Content-Type: message/disposition-notification\n"
1017                         "\n"
1018                         "Reporting-UA: %s\n"
1019                         "Original-Recipient: rfc822;%s\n"
1020                         "Final-Recipient: rfc822;%s\n"
1021                         "Original-Message-ID: <%s>\n"
1022                         "Disposition: manual-action/MDN-sent-manually; displayed\n"
1023                         "\n"
1024                         "--%s\n"
1025                         "Content-Type: application/octet-stream\n"
1026                         "\n"
1027                         "Reporting-UA: %s\n"
1028                         "Original-Recipient: rfc822;%s\n"
1029                         "Final-Recipient: rfc822;%s\n"
1030                         "Original-Message-ID: <%s>\n"
1031                         "Disposition: manual-action/MDN-sent-manually; displayed\n"
1032                         "\n"
1033                         "--%s--\n", 
1034                         boundary, 
1035                         boundary,
1036                         msginfo->date, 
1037                         orig_to?orig_to:"No To:",
1038                         enc_sub?enc_sub:"No subject",
1039                         date,
1040                         boundary,
1041                         PROG_VERSION,
1042                         orig_to?orig_to:"No To:",
1043                         account->address,
1044                         msginfo->msgid?msginfo->msgid:"NO MESSAGE ID",
1045                         boundary,
1046                         PROG_VERSION,
1047                         orig_to?orig_to:"No To:",
1048                         account->address,
1049                         msginfo->msgid?msginfo->msgid:"NO MESSAGE ID",
1050                         boundary);
1051
1052         g_free(enc_sub);
1053         g_free(orig_to);
1054         g_free(date);
1055         g_free(boundary);
1056
1057         if (ok < 0)
1058                 goto FILE_ERROR;        
1059
1060         if (fclose(fp) == EOF) {
1061                 FILE_OP_ERROR(tmp, "fclose");
1062                 claws_unlink(tmp);
1063                 return -1;
1064         }
1065
1066         /* put it in queue */
1067         queue = account_get_special_folder(account, F_QUEUE);
1068         if (!queue) queue = folder_get_default_queue();
1069         if (!queue) {
1070                 g_warning("can't find queue folder");
1071                 claws_unlink(tmp);
1072                 return -1;
1073         }
1074         folder_item_scan(queue);
1075         if ((num = folder_item_add_msg(queue, tmp, NULL, TRUE)) < 0) {
1076                 g_warning("can't queue the message");
1077                 claws_unlink(tmp);
1078                 return -1;
1079         }
1080                 
1081         if (prefs_common.work_offline && 
1082             !inc_offline_should_override(TRUE,
1083                 _("Claws Mail needs network access in order "
1084                   "to send this email.")))
1085                 return 0;
1086
1087         /* send it */
1088         path = folder_item_fetch_msg(queue, num);
1089         ok = procmsg_send_message_queue_with_lock(path, &foo, queue, num, &queued_removed);
1090         g_free(path);
1091         g_free(foo);
1092         if (ok == 0 && !queued_removed)
1093                 folder_item_remove_msg(queue, num);
1094
1095         return ok;
1096
1097 FILE_ERROR:
1098         fclose(fp);
1099         claws_unlink(tmp);
1100         return -1;
1101 }
1102
1103 static gboolean find_encrypted_func(GNode *node, gpointer data)
1104 {
1105         MimeInfo *mimeinfo = (MimeInfo *) node->data;
1106         MimeInfo **encinfo = (MimeInfo **) data;
1107         
1108         if (privacy_mimeinfo_is_encrypted(mimeinfo)) {
1109                 *encinfo = mimeinfo;
1110                 return TRUE;
1111         }
1112         
1113         return FALSE;
1114 }
1115
1116 static MimeInfo *find_encrypted_part(MimeInfo *rootinfo)
1117 {
1118         MimeInfo *encinfo = NULL;
1119
1120         g_node_traverse(rootinfo->node, G_IN_ORDER, G_TRAVERSE_ALL, -1,
1121                 find_encrypted_func, &encinfo);
1122         
1123         return encinfo;
1124 }
1125
1126 static gboolean find_broken_func(GNode *node, gpointer data)
1127 {
1128         MimeInfo *mimeinfo = (MimeInfo *) node->data;
1129         MimeInfo **brokeninfo = (MimeInfo **) data;
1130         
1131         if (mimeinfo->broken) {
1132                 *brokeninfo = mimeinfo;
1133                 return TRUE;
1134         }
1135         
1136         return FALSE;
1137 }
1138
1139 static MimeInfo *find_broken_part(MimeInfo *rootinfo)
1140 {
1141         MimeInfo *brokeninfo = NULL;
1142
1143         g_node_traverse(rootinfo->node, G_IN_ORDER, G_TRAVERSE_ALL, -1,
1144                 find_broken_func, &brokeninfo);
1145         
1146         return brokeninfo;
1147 }
1148
1149 static void messageview_register_nav(MessageView *messageview)
1150 {
1151         gchar *id;
1152         gint pos = -1;
1153         GList *existing;
1154
1155         cm_return_if_fail(messageview);
1156         cm_return_if_fail(messageview->msginfo);
1157
1158         id = procmsg_msginfo_get_identifier(messageview->msginfo);
1159         existing = g_list_find_custom(messageview->trail, id, (GCompareFunc)g_strcmp0);
1160
1161         if (existing != NULL)
1162                 pos = g_list_position(messageview->trail, existing);
1163         else
1164                 pos = -1;
1165
1166         if (pos != -1) {
1167                 messageview->trail_pos = pos;
1168                 g_free(id);
1169         } else {
1170                 /* Cut the end of the list */
1171                 GList *end = g_list_nth(messageview->trail, messageview->trail_pos + 1);
1172                 if (end) {
1173                         if (end->prev) {
1174                                 end->prev->next = NULL;
1175                                 end->prev = NULL;
1176                                 list_free_strings(end);
1177                                 g_list_free(end);
1178                         } else {
1179                                 list_free_strings(messageview->trail);
1180                                 g_list_free(messageview->trail);
1181                                 messageview->trail = NULL;
1182                         }
1183                 }
1184                 messageview->trail = g_list_append(messageview->trail, id);
1185                 messageview->trail_pos = g_list_length(messageview->trail) - 1;
1186                 
1187                 /* Cut the beginning if needed */
1188                 while (messageview->trail_pos > prefs_common.nav_history_length) {
1189                         g_free(messageview->trail->data);
1190                         messageview->trail = g_list_delete_link(messageview->trail,
1191                                                 messageview->trail);
1192                         messageview->trail_pos--;
1193                 }
1194         }
1195         messageview_set_menu_sensitive(messageview);
1196 }
1197
1198 gboolean messageview_nav_has_prev(MessageView *messageview) {
1199         return messageview != NULL && messageview->trail != NULL
1200                 && messageview->trail_pos > 0;
1201 }
1202
1203 gboolean messageview_nav_has_next(MessageView *messageview) {
1204         if (!messageview || !messageview->trail)
1205                 return FALSE;
1206         
1207         return sc_g_list_bigger(messageview->trail, messageview->trail_pos + 1);
1208 }
1209
1210 MsgInfo *messageview_nav_get_prev(MessageView *messageview) {
1211         GList *item;
1212         MsgInfo *info;
1213
1214         cm_return_val_if_fail(messageview, NULL);
1215         cm_return_val_if_fail(messageview->trail, NULL);
1216
1217         do {
1218                 if (!messageview_nav_has_prev(messageview))
1219                         return NULL;
1220
1221                 item = g_list_nth(messageview->trail, messageview->trail_pos - 1);
1222                 cm_return_val_if_fail(item != NULL, NULL);
1223
1224                 info = procmsg_get_msginfo_from_identifier((const gchar *)item->data);
1225                 if (info != NULL)
1226                         break;
1227
1228                 g_free(item->data);
1229                 messageview->trail = g_list_delete_link(messageview->trail, item);
1230                 if (messageview->trail_pos > 0)
1231                         messageview->trail_pos--;
1232         } while (info == NULL);
1233
1234         return info;
1235 }
1236
1237 MsgInfo *messageview_nav_get_next(MessageView *messageview) {
1238         GList *item;
1239         MsgInfo *info;
1240
1241         cm_return_val_if_fail(messageview, NULL);
1242         cm_return_val_if_fail(messageview->trail, NULL);
1243
1244         do {
1245                 if (!messageview_nav_has_next(messageview))
1246                         return NULL;
1247
1248                 item = g_list_nth(messageview->trail, messageview->trail_pos + 1);
1249                 cm_return_val_if_fail(item != NULL, NULL);
1250
1251                 info = procmsg_get_msginfo_from_identifier((const gchar *)item->data);
1252                 if (info != NULL)
1253                         break;
1254
1255                 g_free(item->data);
1256                 messageview->trail = g_list_delete_link(messageview->trail, item);
1257         } while (info == NULL);
1258         
1259         return info;
1260 }
1261
1262 static gboolean messageview_try_select_mimeinfo(MessageView *messageview, MsgInfo *msginfo, MimeInfo *mimeinfo)
1263 {
1264         if (mimeinfo->type == MIMETYPE_TEXT) {
1265                 if (!strcasecmp(mimeinfo->subtype, "calendar")
1266                                 && mimeview_has_viewer_for_content_type(messageview->mimeview, "text/calendar")) {
1267                         mimeview_select_mimepart_icon(messageview->mimeview, mimeinfo);
1268                         return TRUE;
1269                 } else if (!strcasecmp(mimeinfo->subtype, "html")
1270                                 && mimeinfo->disposition != DISPOSITIONTYPE_ATTACHMENT
1271                                 && (msginfo->folder->prefs->promote_html_part == HTML_PROMOTE_ALWAYS
1272                                         || (msginfo->folder->prefs->promote_html_part == HTML_PROMOTE_DEFAULT
1273                                                 && prefs_common.promote_html_part))) {
1274                         mimeview_select_mimepart_icon(messageview->mimeview, mimeinfo);
1275                         return TRUE;
1276                 }
1277         }
1278         return FALSE;
1279 }
1280
1281 static void messageview_find_part_depth_first(MimeInfoSearch *context, MimeMediaType type, const gchar *subtype)
1282 {
1283         MimeInfo * mimeinfo = context->current;
1284
1285         if (!mimeinfo)
1286                 return;
1287
1288         debug_print("found part %d/%s\n", mimeinfo->type, mimeinfo->subtype);
1289
1290         if (mimeinfo->type == type
1291                         && !strcasecmp(mimeinfo->subtype, subtype)) {
1292                 context->found = mimeinfo;
1293         } else if (mimeinfo->type == MIMETYPE_MULTIPART) {
1294                 if (!strcasecmp(mimeinfo->subtype, "alternative")
1295                                 || !strcasecmp(mimeinfo->subtype, "related")) {
1296                         context->found = procmime_mimeinfo_next(mimeinfo);
1297                         while (context->found && context->found != context->parent) {
1298                                 if (context->found->type == type
1299                                         && !strcasecmp(context->found->subtype, subtype))
1300                                                 break;
1301                                 context->found = procmime_mimeinfo_next(context->found);
1302                         }
1303                         if (context->found == context->parent)
1304                                 context->found = NULL;
1305                 }
1306                 if (!context->found
1307                         && (!strcasecmp(mimeinfo->subtype, "related")
1308                                 || !strcasecmp(mimeinfo->subtype, "mixed"))) {
1309                         context->parent = mimeinfo;
1310                         context->current = procmime_mimeinfo_next(mimeinfo);
1311                         messageview_find_part_depth_first(context, type, subtype);
1312                 }
1313         }
1314 }
1315
1316 gint messageview_show(MessageView *messageview, MsgInfo *msginfo,
1317                       gboolean all_headers)
1318 {
1319         gchar *text = NULL;
1320         gchar *file;
1321         MimeInfo *mimeinfo, *encinfo, *root;
1322         gchar *subject = NULL;
1323         cm_return_val_if_fail(msginfo != NULL, -1);
1324
1325         if (msginfo != messageview->msginfo)
1326                 messageview->show_full_text = FALSE;
1327
1328         if (messageview->mimeview->textview &&
1329             messageview->mimeview->textview->loading) {
1330                 messageview->mimeview->textview->stop_loading = TRUE;
1331                 return 0;
1332         }
1333
1334         if (messageview->toolbar)
1335                 toolbar_set_learn_button
1336                         (messageview->toolbar,
1337                          MSG_IS_SPAM(msginfo->flags)?LEARN_HAM:LEARN_SPAM);
1338         else
1339                 toolbar_set_learn_button
1340                         (messageview->mainwin->toolbar,
1341                          MSG_IS_SPAM(msginfo->flags)?LEARN_HAM:LEARN_SPAM);
1342
1343         if (messageview->toolbar) {
1344                 if (messageview->toolbar->learn_spam_btn) {
1345                         gboolean can_learn = FALSE;
1346                         if (procmsg_spam_can_learn() &&
1347                             (msginfo->folder &&
1348                              msginfo->folder->folder->klass->type != F_UNKNOWN &&
1349                              msginfo->folder->folder->klass->type != F_NEWS))
1350                                 can_learn = TRUE;
1351
1352                         gtk_widget_set_sensitive(
1353                                 messageview->toolbar->learn_spam_btn, 
1354                                 can_learn);
1355                 }
1356         }
1357         
1358         noticeview_hide(messageview->noticeview);
1359         mimeview_clear(messageview->mimeview);
1360         messageview->updating = TRUE;
1361
1362         if (msginfo->size > 1024*1024)
1363                 statuswindow_print_all(_("Fetching message (%s)..."),
1364                         to_human_readable(msginfo->size));
1365         
1366         file = procmsg_get_message_file_path(msginfo);
1367
1368         if (msginfo->size > 1024*1024)
1369                 statuswindow_pop_all();
1370
1371         if (!file) {
1372                 g_warning("can't get message file path.");
1373                 textview_show_error(messageview->mimeview->textview);
1374                 return -1;
1375         }
1376         
1377         if (!folder_has_parent_of_type(msginfo->folder, F_QUEUE) &&
1378             !folder_has_parent_of_type(msginfo->folder, F_DRAFT))
1379                 mimeinfo = procmime_scan_file(file);
1380         else
1381                 mimeinfo = procmime_scan_queue_file(file);
1382
1383         messageview->updating = FALSE;
1384         
1385         if (messageview->deferred_destroy) {
1386                 g_free(file);
1387                 messageview_destroy(messageview);
1388                 return 0;
1389         }
1390
1391         if (!mimeinfo) {
1392                 textview_show_error(messageview->mimeview->textview);
1393                 return -1;
1394         }
1395
1396         while ((encinfo = find_encrypted_part(mimeinfo)) != NULL) {
1397                 debug_print("decrypting message part\n");
1398                 if (privacy_mimeinfo_decrypt(encinfo) < 0) {
1399                         text = g_strdup_printf(_("Couldn't decrypt: %s"),
1400                                                privacy_get_error());
1401                         noticeview_show(messageview->noticeview);
1402                         noticeview_set_icon(messageview->noticeview,
1403                                             STOCK_PIXMAP_NOTICE_WARN);
1404                         noticeview_set_text(messageview->noticeview, text);
1405                         gtk_widget_hide(messageview->noticeview->button);
1406                         gtk_widget_hide(messageview->noticeview->button2);
1407                         g_free(text);
1408                         break;
1409                 }
1410         }
1411                         
1412         if (messageview->msginfo != msginfo) {
1413                 procmsg_msginfo_free(&(messageview->msginfo));
1414                 messageview->msginfo = NULL;
1415                 messageview_set_menu_sensitive(messageview);
1416                 messageview->msginfo = 
1417                         procmsg_msginfo_get_full_info_from_file(msginfo, file);
1418                 if (!messageview->msginfo)
1419                         messageview->msginfo = procmsg_msginfo_copy(msginfo);
1420         } else {
1421                 messageview->msginfo = NULL;
1422                 messageview_set_menu_sensitive(messageview);
1423                 messageview->msginfo = msginfo;
1424         }
1425         if (prefs_common.display_header_pane)
1426                 headerview_show(messageview->headerview, messageview->msginfo);
1427
1428         messageview_register_nav(messageview);
1429         messageview_set_position(messageview, 0);
1430
1431         if (messageview->window) {
1432                 gtk_window_set_title(GTK_WINDOW(messageview->window), 
1433                                 _("Claws Mail - Message View"));
1434                 GTK_EVENTS_FLUSH();
1435         }
1436         mimeview_show_message(messageview->mimeview, mimeinfo, file);
1437         
1438 #ifndef GENERIC_UMPC
1439         messageview_set_position(messageview, 0);
1440 #endif
1441
1442         if (messageview->window && msginfo->subject) {
1443                 subject = g_strdup(msginfo->subject);
1444                 if (!g_utf8_validate(subject, -1, NULL)) {
1445                         g_free(subject);
1446                         subject = g_malloc(strlen(msginfo->subject)*2 +1);
1447                         conv_localetodisp(subject, strlen(msginfo->subject)*2 +1, 
1448                                 msginfo->subject);
1449                 }
1450                 if (g_utf8_validate(subject, -1, NULL))
1451                         gtk_window_set_title(GTK_WINDOW(messageview->window), 
1452                                 subject);
1453                 g_free(subject);
1454         }
1455
1456         if (msginfo && msginfo->folder) {
1457                 msginfo->folder->last_seen = msginfo->msgnum;   
1458         }
1459
1460         main_create_mailing_list_menu(messageview->mainwin, messageview->msginfo);
1461
1462         if (messageview->msginfo && messageview->msginfo->extradata
1463             && messageview->msginfo->extradata->partial_recv
1464             && !noticeview_is_visible(messageview->noticeview))
1465                 partial_recv_show(messageview->noticeview, 
1466                                   messageview->msginfo);
1467         else if (messageview->msginfo && messageview->msginfo->extradata &&
1468             (messageview->msginfo->extradata->dispositionnotificationto || 
1469              messageview->msginfo->extradata->returnreceiptto) &&
1470             !MSG_IS_RETRCPT_SENT(messageview->msginfo->flags) &&
1471             !prefs_common.never_send_retrcpt &&
1472             !noticeview_is_visible(messageview->noticeview))
1473                 return_receipt_show(messageview->noticeview, 
1474                                     messageview->msginfo);
1475
1476         if (find_broken_part(mimeinfo) != NULL) {
1477                 noticeview_set_icon(messageview->noticeview,
1478                                     STOCK_PIXMAP_NOTICE_WARN);
1479                 if (!noticeview_is_visible(messageview->noticeview)) {
1480                         noticeview_set_text(messageview->noticeview, _("Message doesn't conform to MIME standard. "
1481                                                 "It may render wrongly."));
1482                         gtk_widget_hide(messageview->noticeview->button);
1483                         gtk_widget_hide(messageview->noticeview->button2);
1484                 } else {
1485                         gchar *full = g_strconcat(
1486                                         gtk_label_get_text(GTK_LABEL(messageview->noticeview->text)), 
1487                                         "\n", 
1488                                         _("Message doesn't conform to MIME standard. "
1489                                         "It may render wrongly."), NULL);
1490                         noticeview_set_text(messageview->noticeview, full);
1491                         g_free(full);
1492                 }
1493                 noticeview_show(messageview->noticeview);
1494         }
1495                         
1496         root = mimeinfo;
1497         mimeinfo = procmime_mimeinfo_next(mimeinfo);
1498         if (!all_headers && mimeinfo
1499                         && (mimeinfo->type != MIMETYPE_TEXT
1500                                 || strcasecmp(mimeinfo->subtype, "plain"))
1501                         && (mimeinfo->type != MIMETYPE_MULTIPART
1502                                 || strcasecmp(mimeinfo->subtype, "signed"))) {
1503                 if (strcasecmp(mimeinfo->subtype, "html")) {
1504                         MimeInfoSearch context = {
1505                                 .parent = root,
1506                                 .current = mimeinfo,
1507                                 .found = NULL
1508                         };
1509                         if (mimeview_has_viewer_for_content_type(messageview->mimeview, "text/calendar")) {
1510                                 MimeInfoSearch cal_context = context;
1511                                 messageview_find_part_depth_first(&cal_context, MIMETYPE_TEXT, "calendar");
1512                                 if (cal_context.found) { /* calendar found */
1513                                         mimeinfo = cal_context.found;
1514                                         if (messageview_try_select_mimeinfo(messageview, msginfo, mimeinfo))
1515                                                 goto done;
1516                                 }
1517                         }
1518                         messageview_find_part_depth_first(&context, MIMETYPE_TEXT, "html");
1519                         if (context.found &&
1520                             (msginfo->folder->prefs->promote_html_part == HTML_PROMOTE_ALWAYS ||
1521                              (msginfo->folder->prefs->promote_html_part == HTML_PROMOTE_DEFAULT &&
1522                               prefs_common.promote_html_part))) { /* html found */
1523                                 mimeinfo = context.found;
1524                                 if (messageview_try_select_mimeinfo(messageview, msginfo, mimeinfo))
1525                                         goto done;
1526                         } else
1527                                 mimeinfo = root; /* nothing found */
1528
1529                         if (!mimeview_show_part(messageview->mimeview, mimeinfo))
1530                                 mimeview_select_mimepart_icon(messageview->mimeview, root);
1531                         goto done;
1532                 } else if (prefs_common.invoke_plugin_on_html) {
1533                         mimeview_select_mimepart_icon(messageview->mimeview, mimeinfo);
1534                         goto done;
1535                 }
1536         }
1537         if (!all_headers && mimeinfo &&
1538             mimeinfo->type == MIMETYPE_MULTIPART &&
1539             mimeview_has_viewer_for_content_type(messageview->mimeview, "text/calendar")) {
1540                 /* look for a calendar part or it looks really strange */
1541                 while (mimeinfo) {
1542                         if (mimeinfo->type == MIMETYPE_TEXT &&
1543                             !strcasecmp(mimeinfo->subtype, "calendar")) {
1544                                 mimeview_select_mimepart_icon(messageview->mimeview, mimeinfo);
1545                                 goto done;
1546                         }
1547                         mimeinfo = procmime_mimeinfo_next(mimeinfo);
1548                 }
1549         }
1550
1551         mimeview_select_mimepart_icon(messageview->mimeview, root);
1552 done:
1553         messageview_set_menu_sensitive(messageview);
1554         /* plugins may hook in here to work with the message view */
1555         hooks_invoke(MESSAGE_VIEW_SHOW_DONE_HOOKLIST, messageview);
1556
1557         g_free(file);
1558
1559         return 0;
1560 }
1561
1562 void messageview_reflect_prefs_pixmap_theme(void)
1563 {
1564         GList *cur;
1565         MessageView *msgview;
1566
1567         for (cur = msgview_list; cur != NULL; cur = cur->next) {
1568                 msgview = (MessageView*)cur->data;
1569                 toolbar_update(TOOLBAR_MSGVIEW, msgview);
1570                 mimeview_update(msgview->mimeview);
1571         }
1572 }
1573
1574 void messageview_clear(MessageView *messageview)
1575 {
1576         if (!messageview)
1577                 return;
1578         procmsg_msginfo_free(&(messageview->msginfo));
1579         messageview->msginfo = NULL;
1580         messageview->filtered = FALSE;
1581
1582         if (messageview->window) {
1583                 gtk_window_set_title(GTK_WINDOW(messageview->window), 
1584                                 _("Claws Mail - Message View"));
1585                 GTK_EVENTS_FLUSH();
1586         }
1587
1588         mimeview_clear(messageview->mimeview);
1589         headerview_clear(messageview->headerview);
1590         noticeview_hide(messageview->noticeview);
1591 }
1592
1593 void messageview_destroy(MessageView *messageview)
1594 {
1595         debug_print("destroy messageview\n");
1596         messageview_list = g_list_remove(messageview_list, messageview);
1597
1598         if (messageview->mainwin->summaryview->messageview == messageview) {
1599                 messageview->mainwin->summaryview->displayed = NULL;
1600                 messageview->mainwin->summaryview->messageview = NULL;
1601         }
1602         if (messageview->mainwin->summaryview->ext_messageview == messageview) {
1603                 messageview->mainwin->summaryview->displayed = NULL;
1604                 messageview->mainwin->summaryview->ext_messageview = NULL;
1605         }
1606         if (!messageview->deferred_destroy)
1607                 hooks_unregister_hook(MSGINFO_UPDATE_HOOKLIST,
1608                               messageview->msginfo_update_callback_id);
1609
1610         if (messageview->updating) {
1611                 debug_print("uh oh, better not touch that now (fetching)\n");
1612                 messageview->deferred_destroy = TRUE;
1613                 gtk_widget_hide(messageview->window);
1614                 return;
1615         }
1616         
1617         if (messageview->mimeview->textview
1618         &&  messageview->mimeview->textview->loading) {
1619                 debug_print("uh oh, better not touch that now (loading text)\n");
1620                 messageview->deferred_destroy = TRUE;
1621                 messageview->mimeview->textview->stop_loading = TRUE;
1622                 gtk_widget_hide(messageview->window);
1623                 return;
1624         }
1625
1626         headerview_destroy(messageview->headerview);
1627         mimeview_destroy(messageview->mimeview);
1628         noticeview_destroy(messageview->noticeview);
1629
1630         procmsg_msginfo_free(&(messageview->msginfo));
1631         toolbar_clear_list(TOOLBAR_MSGVIEW);
1632         if (messageview->toolbar) {
1633                 toolbar_destroy(messageview->toolbar);
1634                 g_free(messageview->toolbar);
1635         }
1636
1637         list_free_strings(messageview->trail);
1638         g_list_free(messageview->trail);
1639         msgview_list = g_list_remove(msgview_list, messageview); 
1640
1641         if (messageview->window)
1642                 gtk_widget_destroy(messageview->window);
1643         g_free(messageview);
1644 }
1645
1646 void messageview_delete(MessageView *msgview)
1647 {
1648         MsgInfo *msginfo = NULL;
1649         FolderItem *trash = NULL;
1650         PrefsAccount *ac = NULL;
1651
1652         if (msgview->msginfo && msgview->mainwin && msgview->mainwin->summaryview)
1653                 msginfo = summary_get_selected_msg(msgview->mainwin->summaryview);
1654         
1655         /* need a procmsg_msginfo_equal() */
1656         if (msginfo && msgview->msginfo && 
1657             msginfo->msgnum == msgview->msginfo->msgnum && 
1658             msginfo->folder == msgview->msginfo->folder) {
1659                 summary_delete_trash(msgview->mainwin->summaryview);
1660         } else {                
1661                 msginfo = msgview->msginfo;
1662
1663                 cm_return_if_fail(msginfo != NULL);
1664
1665                 /* to get the trash folder, we have to choose either
1666                  * the folder's or account's trash default - we prefer
1667                  * the one in the account prefs */
1668                 if (msginfo->folder) {
1669                         if (NULL != (ac = account_find_from_item(msginfo->folder)))
1670                                 trash = account_get_special_folder(ac, F_TRASH);
1671                         if (!trash && msginfo->folder->folder)  
1672                                 trash = msginfo->folder->folder->trash;
1673                         /* if still not found, use the default */
1674                         if (!trash) 
1675                                 trash = folder_get_default_trash();
1676                 }       
1677
1678                 cm_return_if_fail(trash != NULL);
1679
1680                 if (prefs_common.immediate_exec)
1681                         /* TODO: Delete from trash */
1682                         folder_item_move_msg(trash, msginfo);
1683                 else {
1684                         procmsg_msginfo_set_to_folder(msginfo, trash);
1685                         procmsg_msginfo_set_flags(msginfo, MSG_DELETED, 0);
1686                         /* NOTE: does not update to next message in summaryview */
1687                 }
1688         }
1689 #ifdef GENERIC_UMPC
1690         if (msgview->window && !prefs_common.always_show_msg) {
1691                 messageview_destroy(msgview);
1692         }
1693 #endif
1694 }
1695
1696 /* 
1697  * \brief update messageview with currently selected message in summaryview
1698  *        leave unchanged if summaryview is empty
1699  * \param pointer to MessageView
1700  */     
1701 static void messageview_update(MessageView *msgview, MsgInfo *old_msginfo)
1702 {
1703         SummaryView *summaryview = (SummaryView*)msgview->mainwin->summaryview;
1704
1705         cm_return_if_fail(summaryview != NULL);
1706         
1707         if (summaryview->selected) {
1708                 MsgInfo *msginfo = summary_get_selected_msg(summaryview);
1709                 if (msginfo == NULL || msginfo == old_msginfo)
1710                         return;
1711
1712                 messageview_show(msgview, msginfo, 
1713                                  msgview->all_headers);
1714         } 
1715 }
1716
1717 TextView *messageview_get_current_textview(MessageView *messageview)
1718 {
1719         TextView *text = NULL;
1720
1721         text = messageview->mimeview->textview;
1722
1723         return text;
1724 }
1725
1726 MimeInfo *messageview_get_selected_mime_part(MessageView *messageview)
1727 {
1728         return mimeview_get_selected_part(messageview->mimeview);
1729 }
1730
1731 void messageview_copy_clipboard(MessageView *messageview)
1732 {
1733         gchar *text = messageview_get_selection(messageview);
1734         if (text) {
1735                 gtk_clipboard_set_text(
1736                         gtk_clipboard_get(GDK_SELECTION_CLIPBOARD),
1737                         text, -1);
1738         }
1739         g_free(text);
1740 }
1741
1742 void messageview_select_all(MessageView *messageview)
1743 {
1744         TextView *text;
1745
1746         text = messageview_get_current_textview(messageview);
1747         if (text) {
1748                 GtkTextView *textview = GTK_TEXT_VIEW(text->text);
1749                 GtkTextBuffer *buffer;
1750                 GtkTextIter start, end;
1751
1752                 buffer = gtk_text_view_get_buffer(textview);
1753                 gtk_text_buffer_get_bounds(buffer, &start, &end);
1754                 gtk_text_buffer_select_range(buffer, &start, &end);
1755         }
1756 }
1757
1758 void messageview_set_position(MessageView *messageview, gint pos)
1759 {
1760         TextView *text;
1761
1762         text = messageview_get_current_textview(messageview);
1763         if (text)
1764                 textview_set_position(text, pos);
1765 }
1766
1767 gboolean messageview_search_string(MessageView *messageview, const gchar *str,
1768                                    gboolean case_sens)
1769 {
1770         TextView *text;
1771
1772         if (messageview->mimeview->type == MIMEVIEW_VIEWER) {
1773                 MimeViewer *viewer = messageview->mimeview->mimeviewer;
1774                 if (viewer && viewer->text_search) {
1775                         return viewer->text_search(viewer, FALSE, str, case_sens);
1776                 }
1777         }
1778
1779         text = messageview_get_current_textview(messageview);
1780         if (text)
1781                 return textview_search_string(text, str, case_sens);
1782         return FALSE;
1783 }
1784
1785 gboolean messageview_search_string_backward(MessageView *messageview,
1786                                             const gchar *str,
1787                                             gboolean case_sens)
1788 {
1789         TextView *text;
1790
1791         if (messageview->mimeview->type == MIMEVIEW_VIEWER) {
1792                 MimeViewer *viewer = messageview->mimeview->mimeviewer;
1793                 if (viewer && viewer->text_search) {
1794                         return viewer->text_search(viewer, TRUE, str, case_sens);
1795                 }
1796         }
1797
1798         text = messageview_get_current_textview(messageview);
1799         if (text)       
1800                 return textview_search_string_backward(text,
1801                                                        str, case_sens);
1802         return FALSE;
1803 }
1804
1805 gboolean messageview_is_visible(MessageView *messageview)
1806 {
1807         if (messageview == NULL)
1808                 return FALSE;
1809         return messageview->visible;
1810 }
1811
1812 static void messageview_save_as(MessageView *messageview)
1813 {
1814         gchar *filename = NULL;
1815         MsgInfo *msginfo;
1816         gchar *src, *dest, *tmp;
1817
1818         if (!messageview->msginfo) return;
1819         msginfo = messageview->msginfo;
1820
1821         if (msginfo->subject) {
1822                 Xstrdup_a(filename, msginfo->subject, return);
1823                 subst_for_filename(filename);
1824         }
1825         if (filename && !g_utf8_validate(filename, -1, NULL)) {
1826                 gchar *oldstr = filename;
1827                 filename = conv_codeset_strdup(filename,
1828                                                conv_get_locale_charset_str(),
1829                                                CS_UTF_8);
1830                 if (!filename) {
1831                         g_warning("messageview_save_as(): failed to convert character set.");
1832                         filename = g_strdup(oldstr);
1833                 }
1834                 dest = filesel_select_file_save(_("Save as"), filename);
1835                 g_free(filename);
1836         } else
1837                 dest = filesel_select_file_save(_("Save as"), filename);
1838         if (!dest) return;
1839         if (is_file_exist(dest)) {
1840                 AlertValue aval;
1841
1842                 aval = alertpanel(_("Overwrite"),
1843                                   _("Overwrite existing file?"),
1844                                   GTK_STOCK_CANCEL, GTK_STOCK_OK, NULL);
1845                 if (G_ALERTALTERNATE != aval) return;
1846         }
1847
1848         src = procmsg_get_message_file(msginfo);
1849         if (copy_file(src, dest, TRUE) < 0) {
1850                 tmp =  g_path_get_basename(dest);
1851                 alertpanel_error(_("Couldn't save the file '%s'."), tmp);
1852                 g_free(tmp);
1853         }
1854         g_free(dest);
1855         g_free(src);
1856 }
1857
1858 static gint messageview_delete_cb(GtkWidget *widget, GdkEventAny *event,
1859                                   MessageView *messageview)
1860 {
1861         messageview_destroy(messageview);
1862         return TRUE;
1863 }
1864
1865 static void messageview_size_allocate_cb(GtkWidget *widget,
1866                                          GtkAllocation *allocation)
1867 {
1868         cm_return_if_fail(allocation != NULL);
1869
1870         prefs_common.msgwin_width  = allocation->width;
1871         prefs_common.msgwin_height = allocation->height;
1872 }
1873
1874 static gboolean key_pressed(GtkWidget *widget, GdkEventKey *event,
1875                         MessageView *messageview)
1876 {
1877         if (event && event->keyval == GDK_KEY_Escape && messageview->window) {
1878                 messageview_destroy(messageview);
1879                 return TRUE;
1880         }
1881
1882         if (event && (event->state & (GDK_MOD1_MASK|GDK_CONTROL_MASK)) != 0)
1883                 return FALSE;
1884         if (event && (event->state & GDK_SHIFT_MASK) && event->keyval != GDK_KEY_space) 
1885                 return FALSE;
1886
1887         return mimeview_pass_key_press_event(messageview->mimeview, event);
1888 }
1889
1890 static void messageview_show_partial_display_cb(NoticeView *noticeview, MessageView *messageview)
1891 {
1892         messageview->show_full_text = TRUE;
1893         main_window_cursor_wait(mainwindow_get_mainwindow());
1894         noticeview_hide(messageview->noticeview);
1895         messageview->partial_display_shown = FALSE;
1896         GTK_EVENTS_FLUSH();
1897         mimeview_handle_cmd(messageview->mimeview, "sc://display_as_text", NULL, NULL);
1898         main_window_cursor_normal(mainwindow_get_mainwindow());
1899 }
1900
1901 void messageview_show_partial_display(MessageView *messageview, MsgInfo *msginfo,
1902                                              size_t length)
1903 {
1904         gchar *msg = g_strdup_printf(_("Show all %s."), to_human_readable((goffset)length));
1905         noticeview_set_icon(messageview->noticeview, STOCK_PIXMAP_NOTICE_WARN);
1906         noticeview_set_text(messageview->noticeview, _("Only the first megabyte of text is shown."));
1907         noticeview_set_button_text(messageview->noticeview, msg);
1908         g_free(msg);
1909         noticeview_set_button_press_callback(messageview->noticeview,
1910                                              G_CALLBACK(messageview_show_partial_display_cb),
1911                                              (gpointer) messageview);
1912         noticeview_show(messageview->noticeview);
1913         messageview->partial_display_shown = TRUE;
1914 }
1915
1916 static void return_receipt_show(NoticeView *noticeview, MsgInfo *msginfo)
1917 {
1918         gchar *addr = NULL;
1919         gboolean from_me = FALSE;
1920         if (msginfo->folder 
1921                 && (folder_has_parent_of_type(msginfo->folder, F_QUEUE)
1922                  || folder_has_parent_of_type(msginfo->folder, F_DRAFT)))
1923                 return;
1924
1925         addr = g_strdup(msginfo->from);
1926         if (addr) {
1927                 extract_address(addr);
1928                 if (account_find_from_address(addr, FALSE)) {
1929                         from_me = TRUE;
1930                 }
1931                 g_free(addr);
1932         }
1933
1934         if (from_me) {
1935                 noticeview_set_icon(noticeview, STOCK_PIXMAP_NOTICE_WARN);
1936                 if (MSG_IS_RETRCPT_GOT(msginfo->flags)) {
1937                         noticeview_set_text(noticeview, _("You got a return receipt for this message: "
1938                                                           "it has been displayed by the recipient."));
1939                 } else {
1940                         noticeview_set_text(noticeview, _("You asked for a return receipt in this message."));
1941                 }
1942                 noticeview_set_button_text(noticeview, NULL);
1943                 noticeview_set_button_press_callback(noticeview, NULL, NULL);
1944         } else {
1945                 noticeview_set_icon(noticeview, STOCK_PIXMAP_NOTICE_WARN);
1946                 noticeview_set_text(noticeview, _("This message asks for a return receipt."));
1947                 noticeview_set_button_text(noticeview, _("Send receipt"));
1948                 noticeview_set_button_press_callback(noticeview,
1949                                                      G_CALLBACK(return_receipt_send_clicked),
1950                                                      (gpointer) msginfo);
1951         }
1952         noticeview_show(noticeview);
1953 }
1954
1955 static void return_receipt_send_clicked(NoticeView *noticeview, MsgInfo *msginfo)
1956 {
1957         MsgInfo *tmpmsginfo;
1958         gchar *file;
1959
1960         file = procmsg_get_message_file_path(msginfo);
1961         if (!file) {
1962                 g_warning("can't get message file path.");
1963                 return;
1964         }
1965
1966         tmpmsginfo = procheader_parse_file(file, msginfo->flags, TRUE, TRUE);
1967         tmpmsginfo->folder = msginfo->folder;
1968         tmpmsginfo->msgnum = msginfo->msgnum;
1969
1970         if (disposition_notification_send(tmpmsginfo) >= 0) {
1971                 procmsg_msginfo_set_flags(msginfo, MSG_RETRCPT_SENT, 0);
1972                 noticeview_hide(noticeview);
1973         }               
1974
1975         procmsg_msginfo_free(&tmpmsginfo);
1976         g_free(file);
1977 }
1978
1979 static void partial_recv_show(NoticeView *noticeview, MsgInfo *msginfo)
1980 {
1981         gchar *text = NULL;
1982         gchar *button1 = NULL;
1983         gchar *button2 = NULL;
1984         void  *button1_cb = NULL;
1985         void  *button2_cb = NULL;
1986
1987         if (!msginfo->extradata)
1988                 return;
1989         if (!partial_msg_in_uidl_list(msginfo)) {
1990                 text = g_strdup_printf(_("This message has been partially "
1991                                 "retrieved,\nand has been deleted from the "
1992                                 "server."));
1993         } else {
1994                 switch (msginfo->planned_download) {
1995                 case POP3_PARTIAL_DLOAD_UNKN:
1996                         text = g_strdup_printf(_("This message has been "
1997                                         "partially retrieved;\nit is %s."),
1998                                         to_human_readable(
1999                                                 (goffset)(msginfo->total_size)));
2000                         button1 = _("Mark for download");
2001                         button2 = _("Mark for deletion");
2002                         button1_cb = partial_recv_dload_clicked;
2003                         button2_cb = partial_recv_del_clicked;
2004                         break;
2005                 case POP3_PARTIAL_DLOAD_DLOAD:
2006                         text = g_strdup_printf(_("This message has been "
2007                                         "partially retrieved;\nit is %s and "
2008                                         "will be downloaded."),
2009                                         to_human_readable(
2010                                                 (goffset)(msginfo->total_size)));
2011                         button1 = _("Unmark");
2012                         button1_cb = partial_recv_unmark_clicked;
2013                         button2 = _("Mark for deletion");
2014                         button2_cb = partial_recv_del_clicked;
2015                         break;
2016                 case POP3_PARTIAL_DLOAD_DELE:
2017                         text = g_strdup_printf(_("This message has been "
2018                                         "partially retrieved;\nit is %s and "
2019                                         "will be deleted."),
2020                                         to_human_readable(
2021                                                 (goffset)(msginfo->total_size)));
2022                         button1 = _("Mark for download");
2023                         button1_cb = partial_recv_dload_clicked;
2024                         button2 = _("Unmark");
2025                         button2_cb = partial_recv_unmark_clicked;
2026                         break;
2027                 default:
2028                         return;
2029                 }
2030         }
2031         
2032         noticeview_set_icon(noticeview, STOCK_PIXMAP_NOTICE_WARN);
2033         noticeview_set_text(noticeview, text);
2034         g_free(text);
2035         noticeview_set_button_text(noticeview, button1);
2036         noticeview_set_button_press_callback(noticeview,
2037                      G_CALLBACK(button1_cb), (gpointer) msginfo);
2038
2039         noticeview_set_2ndbutton_text(noticeview, button2);
2040         noticeview_set_2ndbutton_press_callback(noticeview,
2041                      G_CALLBACK(button2_cb), (gpointer) msginfo);
2042
2043         noticeview_show(noticeview);
2044 }
2045
2046 static void partial_recv_dload_clicked(NoticeView *noticeview, 
2047                                        MsgInfo *msginfo)
2048 {
2049         if (partial_mark_for_download(msginfo) == 0) {
2050                 partial_recv_show(noticeview, msginfo);
2051         }
2052 }
2053
2054 static void partial_recv_del_clicked(NoticeView *noticeview, 
2055                                        MsgInfo *msginfo)
2056 {
2057         if (partial_mark_for_delete(msginfo) == 0) {
2058                 partial_recv_show(noticeview, msginfo);
2059         }
2060 }
2061
2062 static void partial_recv_unmark_clicked(NoticeView *noticeview, 
2063                                        MsgInfo *msginfo)
2064 {
2065         if (partial_unmark(msginfo) == 0) {
2066                 partial_recv_show(noticeview, msginfo);
2067         }
2068 }
2069
2070 static void select_account_cb(GtkWidget *w, gpointer data)
2071 {
2072         *(gint*)data = combobox_get_active_data(GTK_COMBO_BOX(w));
2073 }
2074
2075 static PrefsAccount *select_account_from_list(GList *ac_list)
2076 {
2077         GtkWidget *optmenu;
2078         gint account_id;
2079
2080         cm_return_val_if_fail(ac_list != NULL, NULL);
2081         cm_return_val_if_fail(ac_list->data != NULL, NULL);
2082         
2083         optmenu = gtkut_account_menu_new(ac_list,
2084                         G_CALLBACK(select_account_cb),
2085                         &account_id);
2086         if (!optmenu)
2087                 return NULL;
2088         account_id = ((PrefsAccount *) ac_list->data)->account_id;
2089         if (alertpanel_with_widget(
2090                                 _("Return Receipt Notification"),
2091                                 _("More than one of your accounts uses the "
2092                                   "address that this message was sent to.\n"
2093                                   "Please choose which account you want to "
2094                                   "use for sending the receipt notification:"),
2095                                 _("_Cancel"), _("_Send Notification"), NULL,
2096                                 FALSE, G_ALERTDEFAULT, optmenu) != G_ALERTALTERNATE)
2097                 return NULL;
2098         return account_find_from_id(account_id);
2099 }
2100
2101 /* 
2102  * \brief return selected messageview text, when nothing is 
2103  *        selected and message was filtered, return complete text
2104  *
2105  * \param  pointer to Messageview 
2106  *
2107  * \return pointer to text (needs to be free'd by calling func)
2108  */
2109 gchar *messageview_get_selection(MessageView *msgview)
2110 {
2111         TextView *textview;
2112         gchar *text = NULL;
2113         GtkTextView *edit = NULL;
2114         GtkTextBuffer *textbuf;
2115         gint body_pos = 0;
2116         GtkTextIter start_iter, end_iter;
2117         GtkTextMark *body_start, *body_end;
2118         
2119         cm_return_val_if_fail(msgview != NULL, NULL);
2120
2121         if (msgview->mimeview->type == MIMEVIEW_VIEWER) {
2122                 MimeViewer *viewer = msgview->mimeview->mimeviewer;
2123                 if (viewer && viewer->get_selection) {
2124                         text = viewer->get_selection(viewer);
2125                         if (text)
2126                                 return text;
2127                 }
2128         }
2129
2130         textview = messageview_get_current_textview(msgview);
2131         cm_return_val_if_fail(textview != NULL, NULL);
2132
2133         edit = GTK_TEXT_VIEW(textview->text);
2134         cm_return_val_if_fail(edit != NULL, NULL);
2135         body_pos = textview->body_pos;
2136
2137         textbuf = gtk_text_view_get_buffer(edit);
2138
2139         if (gtk_text_buffer_get_selection_bounds(textbuf, NULL, NULL)) {
2140                 return gtkut_text_view_get_selection(edit);
2141         } else {
2142                 if (msgview->filtered) {
2143                         gtk_text_buffer_get_iter_at_offset(textbuf, &start_iter, body_pos);
2144                         gtk_text_buffer_get_end_iter(textbuf, &end_iter);
2145                 } else {
2146                         body_start = gtk_text_buffer_get_mark(textbuf, "body_start");
2147
2148                         /* If there is no body_start mark, an attachment is likely
2149                          * selected, and we're looking at instructions on what to do
2150                          * with it. No point in quoting that, so we'll just return NULL,
2151                          * so that original message body is quoted instead down the line.
2152                          */
2153                         if (body_start == NULL) {
2154                                 return NULL;
2155                         }
2156
2157                         gtk_text_buffer_get_iter_at_mark(textbuf, &start_iter, body_start);
2158
2159                         body_end = gtk_text_buffer_get_mark(textbuf, "body_end");
2160                         if (body_end != NULL) /* Just in case */
2161                                 gtk_text_buffer_get_iter_at_mark(textbuf, &end_iter, body_end);
2162                         else
2163                                 gtk_text_buffer_get_end_iter(textbuf, &end_iter);
2164                 }
2165
2166                 return gtk_text_buffer_get_text(textbuf, &start_iter, &end_iter, FALSE);
2167         }
2168
2169         return text;
2170 }
2171
2172 static void save_as_cb(GtkAction *action, gpointer data)
2173 {
2174         MessageView *messageview = (MessageView *)data;
2175         messageview_save_as(messageview);
2176 }
2177
2178 static void print_mimeview(MimeView *mimeview, gint sel_start, gint sel_end, gint partnum) 
2179 {
2180         MainWindow *mainwin;
2181         if (!mimeview 
2182         ||  !mimeview->textview
2183         ||  !mimeview->textview->text)
2184                 alertpanel_warning(_("Cannot print: the message doesn't "
2185                                      "contain text."));
2186         else {
2187                 gtk_widget_realize(mimeview->textview->text);
2188                 if (partnum > 0) {
2189                         mimeview_select_part_num(mimeview, partnum);
2190                 }
2191                 if (mimeview->type == MIMEVIEW_VIEWER) {
2192                         MimeViewer *viewer = mimeview->mimeviewer;
2193                         if (viewer && viewer->print) {
2194                                 viewer->print(viewer);
2195                                 return;
2196                         }
2197                 }
2198                 if (sel_start != -1 && sel_end != -1) {
2199                         GtkTextIter start, end;
2200                         GtkTextView *text = GTK_TEXT_VIEW(mimeview->textview->text);
2201                         GtkTextBuffer *buffer = gtk_text_view_get_buffer(text);
2202
2203                         gtk_text_buffer_get_iter_at_offset(buffer, &start, sel_start);
2204                         gtk_text_buffer_get_iter_at_offset(buffer, &end, sel_end);
2205                         gtk_text_buffer_select_range(buffer, &start, &end);
2206                 }
2207                 /* TODO: Get the real parent window, not the main window */
2208                 mainwin = mainwindow_get_mainwindow();
2209                 printing_print(GTK_TEXT_VIEW(mimeview->textview->text),
2210                                mainwin ? GTK_WINDOW(mainwin->window) : NULL,
2211                                 sel_start, sel_end,
2212                                 (mimeview->textview->image 
2213                                         ? GTK_IMAGE(mimeview->textview->image)
2214                                         : NULL));
2215         }
2216 }
2217
2218 void messageview_print(MsgInfo *msginfo, gboolean all_headers, 
2219                         gint sel_start, gint sel_end, gint partnum) 
2220 {
2221         PangoFontDescription *font_desc = NULL;
2222         MessageView *tmpview = messageview_create_with_new_window_visible(
2223                                 mainwindow_get_mainwindow(), FALSE);
2224
2225         if (prefs_common.use_different_print_font) {
2226                 font_desc = pango_font_description_from_string
2227                                                 (prefs_common.printfont);
2228         } else {
2229                 font_desc = pango_font_description_from_string
2230                                                 (prefs_common.textfont);
2231         }
2232         if (font_desc) {
2233                 gtk_widget_modify_font(tmpview->mimeview->textview->text, 
2234                         font_desc);
2235                 pango_font_description_free(font_desc);
2236         }
2237
2238         tmpview->all_headers = all_headers;
2239         if (msginfo && messageview_show(tmpview, msginfo, 
2240                 tmpview->all_headers) >= 0) {
2241                         print_mimeview(tmpview->mimeview, 
2242                                 sel_start, sel_end, partnum);
2243         }
2244         messageview_destroy(tmpview);
2245 }
2246
2247 static void page_setup_cb(GtkAction *action, gpointer data)
2248 {
2249         MessageView *messageview = (MessageView *)data;
2250         printing_page_setup(messageview ?
2251                             GTK_WINDOW(messageview->window) : NULL);
2252 }
2253
2254 static void print_cb(GtkAction *action, gpointer data)
2255 {
2256         MessageView *messageview = (MessageView *)data;
2257         gint sel_start = -1, sel_end = -1, partnum = 0;
2258
2259         if (!messageview->msginfo) return;
2260
2261         partnum = mimeview_get_selected_part_num(messageview->mimeview);
2262         textview_get_selection_offsets(messageview->mimeview->textview,
2263                 &sel_start, &sel_end);
2264         messageview_print(messageview->msginfo, messageview->all_headers, 
2265                 sel_start, sel_end, partnum);
2266 }
2267
2268 static void close_cb(GtkAction *action, gpointer data)
2269 {
2270         MessageView *messageview = (MessageView *)data;
2271         messageview_destroy(messageview);
2272 }
2273
2274 static void copy_cb(GtkAction *action, gpointer data)
2275 {
2276         MessageView *messageview = (MessageView *)data;
2277         messageview_copy_clipboard(messageview);
2278 }
2279
2280 static void allsel_cb(GtkAction *action, gpointer data)
2281 {
2282         MessageView *messageview = (MessageView *)data;
2283         messageview_select_all(messageview);
2284 }
2285
2286 static void search_cb(GtkAction *action, gpointer data)
2287 {
2288         MessageView *messageview = (MessageView *)data;
2289         message_search(messageview);
2290 }
2291
2292 static void prev_cb(GtkAction *action, gpointer data)
2293 {
2294         MessageView *messageview = (MessageView *)data;
2295         messageview->updating = TRUE;
2296         summary_select_prev(messageview->mainwin->summaryview);
2297         messageview->updating = FALSE;
2298
2299         if (messageview->deferred_destroy) {
2300                 debug_print("messageview got away!\n");
2301                 messageview_destroy(messageview);
2302                 return;
2303         }
2304         if (messageview->mainwin->summaryview->selected) {
2305 #ifndef GENERIC_UMPC
2306                 MsgInfo * msginfo = summary_get_selected_msg(messageview->mainwin->summaryview);
2307                        
2308                 if (msginfo)
2309                         messageview_show(messageview, msginfo, 
2310                                          messageview->all_headers);
2311 #endif
2312         } else {
2313                 gtk_widget_destroy(messageview->window);
2314         }
2315 }
2316
2317 static void next_cb(GtkAction *action, gpointer data)
2318 {
2319         MessageView *messageview = (MessageView *)data;
2320         messageview->updating = TRUE;
2321         summary_select_next(messageview->mainwin->summaryview);
2322         messageview->updating = FALSE;
2323
2324         if (messageview->deferred_destroy) {
2325                 debug_print("messageview got away!\n");
2326                 messageview_destroy(messageview);
2327                 return;
2328         }
2329         if (messageview->mainwin->summaryview->selected) {
2330 #ifndef GENERIC_UMPC
2331                 MsgInfo * msginfo = summary_get_selected_msg(messageview->mainwin->summaryview);
2332                        
2333                 if (msginfo)
2334                         messageview_show(messageview, msginfo, 
2335                                          messageview->all_headers);
2336 #endif
2337         } else {
2338                 gtk_widget_destroy(messageview->window);
2339         }
2340 }
2341
2342 static void prev_unread_cb(GtkAction *action, gpointer data)
2343 {
2344         MessageView *messageview = (MessageView *)data;
2345         messageview->updating = TRUE;
2346         summary_select_prev_unread(messageview->mainwin->summaryview);
2347         messageview->updating = FALSE;
2348
2349         if (messageview->deferred_destroy) {
2350                 debug_print("messageview got away!\n");
2351                 messageview_destroy(messageview);
2352                 return;
2353         }
2354         if (messageview->mainwin->summaryview->selected) {
2355 #ifndef GENERIC_UMPC
2356                 MsgInfo * msginfo = summary_get_selected_msg(messageview->mainwin->summaryview);
2357                        
2358                 if (msginfo)
2359                         messageview_show(messageview, msginfo, 
2360                                          messageview->all_headers);
2361 #endif
2362         } else {
2363                 gtk_widget_destroy(messageview->window);
2364         }
2365 }
2366
2367 static void next_unread_cb(GtkAction *action, gpointer data)
2368 {
2369         MessageView *messageview = (MessageView *)data;
2370         messageview->updating = TRUE;
2371         summary_select_next_unread(messageview->mainwin->summaryview);
2372         messageview->updating = FALSE;
2373
2374         if (messageview->deferred_destroy) {
2375                 debug_print("messageview got away!\n");
2376                 messageview_destroy(messageview);
2377                 return;
2378         }
2379         if (messageview->mainwin->summaryview->selected) {
2380 #ifndef GENERIC_UMPC
2381                 MsgInfo * msginfo = summary_get_selected_msg(messageview->mainwin->summaryview);
2382                        
2383                 if (msginfo)
2384                         messageview_show(messageview, msginfo, 
2385                                          messageview->all_headers);
2386 #endif
2387         } else {
2388                 gtk_widget_destroy(messageview->window);
2389         }
2390 }
2391
2392 static void prev_new_cb(GtkAction *action, gpointer data)
2393 {
2394         MessageView *messageview = (MessageView *)data;
2395         messageview->updating = TRUE;
2396         summary_select_prev_new(messageview->mainwin->summaryview);
2397         messageview->updating = FALSE;
2398
2399         if (messageview->deferred_destroy) {
2400                 debug_print("messageview got away!\n");
2401                 messageview_destroy(messageview);
2402                 return;
2403         }
2404         if (messageview->mainwin->summaryview->selected) {
2405 #ifndef GENERIC_UMPC
2406                 MsgInfo * msginfo = summary_get_selected_msg(messageview->mainwin->summaryview);
2407                        
2408                 if (msginfo)
2409                         messageview_show(messageview, msginfo, 
2410                                          messageview->all_headers);
2411 #endif
2412         } else {
2413                 gtk_widget_destroy(messageview->window);
2414         }
2415 }
2416
2417 static void next_new_cb(GtkAction *action, gpointer data)
2418 {
2419         MessageView *messageview = (MessageView *)data;
2420         messageview->updating = TRUE;
2421         summary_select_next_new(messageview->mainwin->summaryview);
2422         messageview->updating = FALSE;
2423
2424         if (messageview->deferred_destroy) {
2425                 debug_print("messageview got away!\n");
2426                 messageview_destroy(messageview);
2427                 return;
2428         }
2429         if (messageview->mainwin->summaryview->selected) {
2430 #ifndef GENERIC_UMPC
2431                 MsgInfo * msginfo = summary_get_selected_msg(messageview->mainwin->summaryview);
2432                        
2433                 if (msginfo)
2434                         messageview_show(messageview, msginfo, 
2435                                          messageview->all_headers);
2436 #endif
2437         } else {
2438                 gtk_widget_destroy(messageview->window);
2439         }
2440 }
2441
2442 static void prev_marked_cb(GtkAction *action, gpointer data)
2443 {
2444         MessageView *messageview = (MessageView *)data;
2445         messageview->updating = TRUE;
2446         summary_select_prev_marked(messageview->mainwin->summaryview);
2447         messageview->updating = FALSE;
2448
2449         if (messageview->deferred_destroy) {
2450                 debug_print("messageview got away!\n");
2451                 messageview_destroy(messageview);
2452                 return;
2453         }
2454         if (messageview->mainwin->summaryview->selected) {
2455 #ifndef GENERIC_UMPC
2456                 MsgInfo * msginfo = summary_get_selected_msg(messageview->mainwin->summaryview);
2457                        
2458                 if (msginfo)
2459                         messageview_show(messageview, msginfo, 
2460                                          messageview->all_headers);
2461 #endif
2462         } else {
2463                 gtk_widget_destroy(messageview->window);
2464         }
2465 }
2466
2467 static void next_marked_cb(GtkAction *action, gpointer data)
2468 {
2469         MessageView *messageview = (MessageView *)data;
2470         messageview->updating = TRUE;
2471         summary_select_next_marked(messageview->mainwin->summaryview);
2472         messageview->updating = FALSE;
2473
2474         if (messageview->deferred_destroy) {
2475                 debug_print("messageview got away!\n");
2476                 messageview_destroy(messageview);
2477                 return;
2478         }
2479         if (messageview->mainwin->summaryview->selected) {
2480 #ifndef GENERIC_UMPC
2481                 MsgInfo * msginfo = summary_get_selected_msg(messageview->mainwin->summaryview);
2482                        
2483                 if (msginfo)
2484                         messageview_show(messageview, msginfo, 
2485                                          messageview->all_headers);
2486 #endif
2487         } else {
2488                 gtk_widget_destroy(messageview->window);
2489         }
2490 }
2491
2492 static void prev_labeled_cb(GtkAction *action, gpointer data)
2493 {
2494         MessageView *messageview = (MessageView *)data;
2495         messageview->updating = TRUE;
2496         summary_select_prev_labeled(messageview->mainwin->summaryview);
2497         messageview->updating = FALSE;
2498
2499         if (messageview->deferred_destroy) {
2500                 debug_print("messageview got away!\n");
2501                 messageview_destroy(messageview);
2502                 return;
2503         }
2504         if (messageview->mainwin->summaryview->selected) {
2505 #ifndef GENERIC_UMPC
2506                 MsgInfo * msginfo = summary_get_selected_msg(messageview->mainwin->summaryview);
2507                        
2508                 if (msginfo)
2509                         messageview_show(messageview, msginfo, 
2510                                          messageview->all_headers);
2511 #endif
2512         } else {
2513                 gtk_widget_destroy(messageview->window);
2514         }
2515 }
2516
2517 static void next_labeled_cb(GtkAction *action, gpointer data)
2518 {
2519         MessageView *messageview = (MessageView *)data;
2520         messageview->updating = TRUE;
2521         summary_select_next_labeled(messageview->mainwin->summaryview);
2522         messageview->updating = FALSE;
2523
2524         if (messageview->deferred_destroy) {
2525                 debug_print("messageview got away!\n");
2526                 messageview_destroy(messageview);
2527                 return;
2528         }
2529         if (messageview->mainwin->summaryview->selected) {
2530 #ifndef GENERIC_UMPC
2531                 MsgInfo * msginfo = summary_get_selected_msg(messageview->mainwin->summaryview);
2532                        
2533                 if (msginfo)
2534                         messageview_show(messageview, msginfo, 
2535                                          messageview->all_headers);
2536 #endif
2537         } else {
2538                 gtk_widget_destroy(messageview->window);
2539         }
2540 }
2541
2542 static void prev_history_cb(GtkAction *action, gpointer data)
2543 {
2544         MessageView *messageview = (MessageView *)data;
2545         MsgInfo *info = messageview_nav_get_prev(messageview);
2546         if (info) {
2547                 messageview->updating = TRUE;
2548                 messageview_show(messageview, info, 
2549                                          messageview->all_headers);
2550                 messageview->updating = FALSE;
2551                 procmsg_msginfo_free(&info);
2552                 if (messageview->deferred_destroy) {
2553                         debug_print("messageview got away!\n");
2554                         messageview_destroy(messageview);
2555                         return;
2556                 }
2557         }
2558 }
2559
2560 static void next_history_cb(GtkAction *action, gpointer data)
2561 {
2562         MessageView *messageview = (MessageView *)data;
2563         MsgInfo *info = messageview_nav_get_next(messageview);
2564         if (info) {
2565                 messageview->updating = TRUE;
2566                 messageview_show(messageview, info, 
2567                                          messageview->all_headers);
2568                 messageview->updating = FALSE;
2569                 procmsg_msginfo_free(&info);
2570                 if (messageview->deferred_destroy) {
2571                         debug_print("messageview got away!\n");
2572                         messageview_destroy(messageview);
2573                         return;
2574                 }
2575         }
2576 }
2577
2578 static void parent_cb(GtkAction *action, gpointer data)
2579 {
2580         MessageView *messageview = (MessageView *)data;
2581         messageview->updating = TRUE;
2582         summary_select_parent(messageview->mainwin->summaryview);
2583         messageview->updating = FALSE;
2584
2585         if (messageview->deferred_destroy) {
2586                 debug_print("messageview got away!\n");
2587                 messageview_destroy(messageview);
2588                 return;
2589         }
2590         if (messageview->mainwin->summaryview->selected) {
2591 #ifndef GENERIC_UMPC
2592                 MsgInfo * msginfo = summary_get_selected_msg(messageview->mainwin->summaryview);
2593                        
2594                 if (msginfo)
2595                         messageview_show(messageview, msginfo, 
2596                                          messageview->all_headers);
2597 #endif
2598         } else {
2599                 gtk_widget_destroy(messageview->window);
2600         }
2601 }
2602
2603 static void goto_unread_folder_cb(GtkAction *action, gpointer data)
2604 {
2605         MessageView *messageview = (MessageView *)data;
2606
2607         messageview->updating = TRUE;
2608         folderview_select_next_with_flag(messageview->mainwin->folderview, MSG_UNREAD);
2609         messageview->updating = FALSE;
2610
2611         if (messageview->deferred_destroy) {
2612                 debug_print("messageview got away!\n");
2613                 messageview_destroy(messageview);
2614                 return;
2615         }
2616         if (messageview->mainwin->summaryview->selected) {
2617 #ifndef GENERIC_UMPC
2618                 MsgInfo * msginfo = summary_get_selected_msg(messageview->mainwin->summaryview);
2619                        
2620                 if (msginfo)
2621                         messageview_show(messageview, msginfo, 
2622                                          messageview->all_headers);
2623 #endif
2624         } else {
2625                 gtk_widget_destroy(messageview->window);
2626         }
2627 }
2628
2629 static void goto_folder_cb(GtkAction *action, gpointer data)
2630 {
2631         MessageView *messageview = (MessageView *)data;
2632         FolderItem *to_folder;
2633
2634         to_folder = foldersel_folder_sel(NULL, FOLDER_SEL_ALL, NULL, FALSE);
2635
2636         if (to_folder) {
2637                 folderview_select(messageview->mainwin->folderview, to_folder);
2638
2639                 if (messageview->deferred_destroy) {
2640                         debug_print("messageview got away!\n");
2641                         messageview_destroy(messageview);
2642                         return;
2643                 }
2644                 if (messageview->mainwin->summaryview->selected) {
2645 #ifndef GENERIC_UMPC
2646                         MsgInfo * msginfo = summary_get_selected_msg(messageview->mainwin->summaryview);
2647                        
2648                         if (msginfo)
2649                                 messageview_show(messageview, msginfo, 
2650                                                  messageview->all_headers);
2651 #endif
2652                 } else {
2653                         gtk_widget_destroy(messageview->window);
2654                 }
2655         }
2656 }
2657
2658 static void scroll_prev_line_cb(GtkAction *action, gpointer data)
2659 {
2660         MessageView *messageview = (MessageView *)data;
2661         mimeview_scroll_one_line(messageview->mimeview,TRUE);
2662 }
2663
2664 static void scroll_next_line_cb(GtkAction *action, gpointer data)
2665 {
2666         MessageView *messageview = (MessageView *)data;
2667         mimeview_scroll_one_line(messageview->mimeview,FALSE);
2668 }
2669
2670 static void scroll_prev_page_cb(GtkAction *action, gpointer data)
2671 {
2672         MessageView *messageview = (MessageView *)data;
2673         mimeview_scroll_page(messageview->mimeview,TRUE);
2674 }
2675
2676 static void scroll_next_page_cb(GtkAction *action, gpointer data)
2677 {
2678         MessageView *messageview = (MessageView *)data;
2679         mimeview_scroll_page(messageview->mimeview,FALSE);
2680 }
2681
2682 static void set_charset_cb(GtkAction *action, GtkRadioAction *current, gpointer data)
2683 {
2684         MessageView *messageview = (MessageView *)data;
2685         gboolean active = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (current));
2686         gint value = gtk_radio_action_get_current_value (GTK_RADIO_ACTION (current));
2687         const gchar *charset;
2688
2689         if (active) {
2690                 charset = conv_get_charset_str((CharSet)value);
2691                 g_free(messageview->forced_charset);
2692                 messageview->forced_charset = g_strdup(charset);
2693                 procmime_force_charset(charset);
2694                 
2695                 messageview_show(messageview, messageview->msginfo, FALSE);
2696         }
2697 }
2698
2699 static void set_decode_cb(GtkAction *action, GtkRadioAction *current, gpointer data)
2700 {
2701         MessageView *messageview = (MessageView *)data;
2702         gboolean active = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (current));
2703         gint value = gtk_radio_action_get_current_value (GTK_RADIO_ACTION (current));
2704
2705         if (active) {
2706                 messageview->forced_encoding = (EncodingType)value;
2707
2708                 messageview_show(messageview, messageview->msginfo, FALSE);
2709                 debug_print("forced encoding: %d\n", value);
2710         }
2711 }
2712
2713
2714 static void view_source_cb(GtkAction *action, gpointer data)
2715 {
2716         MessageView *messageview = (MessageView *)data;
2717         SourceWindow *srcwin;
2718
2719         if (!messageview->msginfo) return;
2720
2721         srcwin = source_window_create();
2722         source_window_show_msg(srcwin, messageview->msginfo);
2723         source_window_show(srcwin);
2724 }
2725
2726 static void show_all_header_cb(GtkToggleAction *action, gpointer data)
2727 {
2728         MessageView *messageview = (MessageView *)data;
2729         MsgInfo *msginfo = messageview->msginfo;
2730
2731         if (messageview->mimeview->textview &&
2732             messageview->mimeview->textview->loading) {
2733                 return;
2734         }
2735         if (messageview->updating)
2736                 return;
2737
2738         messageview->all_headers = prefs_common.show_all_headers =
2739                         gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
2740         if (!msginfo) return;
2741         messageview->msginfo = NULL;
2742         messageview_show(messageview, msginfo, messageview->all_headers);
2743         procmsg_msginfo_free(&msginfo);
2744         main_window_set_menu_sensitive(messageview->mainwin);
2745         summary_redisplay_msg(messageview->mainwin->summaryview);
2746 }
2747
2748 static void msg_hide_quotes_cb(GtkToggleAction *action, gpointer data)
2749 {
2750         MessageView *messageview = (MessageView *)data;
2751         MsgInfo *msginfo = messageview->msginfo;
2752         static gboolean updating_menu = FALSE;
2753
2754         if (updating_menu)
2755                 return;
2756         if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))) {
2757                 const gchar *a_name = gtk_action_get_name(GTK_ACTION(action));
2758                 if (!strcmp(a_name, "View/Quotes/CollapseAll")) prefs_common.hide_quotes = 1;
2759                 else if (!strcmp(a_name, "View/Quotes/Collapse2")) prefs_common.hide_quotes = 2;
2760                 else if (!strcmp(a_name, "View/Quotes/Collapse3")) prefs_common.hide_quotes = 3;
2761         } else
2762                 prefs_common.hide_quotes = 0;
2763         
2764         updating_menu=TRUE;
2765         
2766         cm_toggle_menu_set_active_full(messageview->ui_manager, "Menu/View/Quotes/CollapseAll", (prefs_common.hide_quotes == 1));
2767         cm_toggle_menu_set_active_full(messageview->ui_manager, "Menu/View/Quotes/Collapse2", (prefs_common.hide_quotes == 2));
2768         cm_toggle_menu_set_active_full(messageview->ui_manager, "Menu/View/Quotes/Collapse3", (prefs_common.hide_quotes == 3));
2769
2770         updating_menu=FALSE;
2771         if (!msginfo) return;
2772         messageview->msginfo = NULL;
2773         messageview_show(messageview, msginfo,
2774                          messageview->all_headers);
2775         procmsg_msginfo_free(&msginfo);
2776         
2777         /* update main window */
2778         main_window_set_menu_sensitive(messageview->mainwin);
2779         summary_redisplay_msg(messageview->mainwin->summaryview);
2780 }
2781 #undef SET_CHECK_MENU_ACTIVE
2782
2783 static void compose_cb(GtkAction *action, gpointer data)
2784 {
2785         MessageView *messageview = (MessageView *)data;
2786         PrefsAccount *ac = NULL;
2787         FolderItem *item = NULL;
2788
2789         if (messageview->msginfo)
2790                 item = messageview->msginfo->folder;
2791
2792         if (item) {
2793                 ac = account_find_from_item(item);
2794                 if (ac && ac->protocol == A_NNTP &&
2795                     FOLDER_TYPE(item->folder) == F_NEWS) {
2796                         compose_new(ac, item->path, NULL);
2797                         return;
2798                 }
2799         }
2800
2801         compose_new(ac, NULL, NULL);
2802 }
2803
2804 #define DO_ACTION(name, act)    { if (!strcmp(a_name, name)) action = act; }
2805
2806 static void reply_cb(GtkAction *gaction, gpointer data)
2807 {
2808         MessageView *messageview = (MessageView *)data;
2809         GSList *msginfo_list = NULL;
2810         gint action = COMPOSE_REPLY;
2811         const gchar *a_name = gtk_action_get_name(gaction);
2812         
2813         cm_return_if_fail(messageview->msginfo);
2814
2815         DO_ACTION("Message/Reply", COMPOSE_REPLY);
2816         DO_ACTION("Message/ReplyTo/All", COMPOSE_REPLY_TO_ALL);
2817         DO_ACTION("Message/ReplyTo/Sender", COMPOSE_REPLY_TO_SENDER);
2818         DO_ACTION("Message/ReplyTo/List", COMPOSE_REPLY_TO_LIST);
2819         DO_ACTION("Message/Forward", COMPOSE_FORWARD_INLINE);
2820         DO_ACTION("Message/ForwardAtt", COMPOSE_FORWARD_AS_ATTACH);
2821         DO_ACTION("Message/Redirect", COMPOSE_REDIRECT);
2822
2823         msginfo_list = g_slist_append(msginfo_list, messageview->msginfo);
2824         compose_reply_from_messageview(messageview, msginfo_list, action);
2825         g_slist_free(msginfo_list);
2826 }
2827
2828 static void addressbook_open_cb(GtkAction *action, gpointer data)
2829 {
2830 #ifndef USE_ALT_ADDRBOOK
2831         addressbook_open(NULL);
2832 #else
2833         GError* error = NULL;
2834         
2835         addressbook_dbus_open(FALSE, &error);
2836         if (error) {
2837                 g_warning("Failed to open address book: %s", error->message);
2838                 g_error_free(error);
2839         }
2840 #endif
2841 }
2842
2843 static void add_address_cb(GtkAction *action, gpointer data)
2844 {
2845         MessageView *messageview = (MessageView *)data;
2846         MsgInfo *msginfo, *full_msginfo;
2847         gchar *from;
2848         GdkPixbuf *picture = NULL;
2849         AvatarRender *avatarr;
2850
2851         if (!messageview->msginfo || !messageview->msginfo->from) 
2852                 return;
2853
2854         msginfo = messageview->msginfo;
2855         Xstrdup_a(from, msginfo->from, return);
2856         eliminate_address_comment(from);
2857         extract_address(from);
2858         
2859         full_msginfo = procmsg_msginfo_get_full_info(msginfo);
2860
2861         avatarr = avatars_avatarrender_new(full_msginfo);
2862         hooks_invoke(AVATAR_IMAGE_RENDER_HOOKLIST, avatarr);
2863
2864         procmsg_msginfo_free(&full_msginfo);
2865
2866         if (avatarr->image != NULL)
2867                 picture = gtk_image_get_pixbuf(GTK_IMAGE(avatarr->image));
2868
2869 #ifndef USE_ALT_ADDRBOOK
2870         addressbook_add_contact(msginfo->fromname, from, NULL, picture);
2871 #else
2872         if (addressadd_selection(msginfo->fromname, from, NULL, picture)) {
2873                 debug_print( "addressbook_add_contact - added\n" );
2874         }
2875 #endif
2876         avatars_avatarrender_free(avatarr);
2877 }
2878
2879 static void create_filter_cb(GtkAction *gaction, gpointer data)
2880 {
2881         MessageView *messageview = (MessageView *)data;
2882         FolderItem * item;
2883         gint action = -1;
2884         const gchar *a_name = gtk_action_get_name(gaction);
2885
2886         if (!messageview->msginfo) return;
2887
2888         DO_ACTION("Tools/CreateFilterRule/Automatically", FILTER_BY_AUTO);
2889         DO_ACTION("Tools/CreateFilterRule/ByFrom", FILTER_BY_FROM);
2890         DO_ACTION("Tools/CreateFilterRule/ByTo", FILTER_BY_TO);
2891         DO_ACTION("Tools/CreateFilterRule/BySubject", FILTER_BY_SUBJECT);
2892         
2893         item = messageview->msginfo->folder;
2894         summary_msginfo_filter_open(item,  messageview->msginfo,
2895                                     (PrefsFilterType)action, 0);
2896 }
2897
2898 static void create_processing_cb(GtkAction *gaction, gpointer data)
2899 {
2900         MessageView *messageview = (MessageView *)data;
2901         FolderItem * item;
2902         gint action = -1;
2903         const gchar *a_name = gtk_action_get_name(gaction);
2904         
2905         if (!messageview->msginfo) return;
2906         
2907         DO_ACTION("Tools/CreateProcessingRule/Automatically", FILTER_BY_AUTO);
2908         DO_ACTION("Tools/CreateProcessingRule/ByFrom", FILTER_BY_FROM);
2909         DO_ACTION("Tools/CreateProcessingRule/ByTo", FILTER_BY_TO);
2910         DO_ACTION("Tools/CreateProcessingRule/BySubject", FILTER_BY_SUBJECT);
2911
2912         item = messageview->msginfo->folder;
2913         summary_msginfo_filter_open(item,  messageview->msginfo,
2914                                     (PrefsFilterType)action, 1);
2915 }
2916
2917 static void open_urls_cb(GtkAction *action, gpointer data)
2918 {
2919         MessageView *messageview = (MessageView *)data;
2920         messageview_list_urls(messageview);
2921 }
2922
2923 static void about_cb(GtkAction *gaction, gpointer data)
2924 {
2925         about_show();
2926 }
2927
2928 static gboolean messageview_update_msg(gpointer source, gpointer data)
2929 {
2930         MsgInfoUpdate *msginfo_update = (MsgInfoUpdate *) source;
2931         MessageView *messageview = (MessageView *)data;
2932         MsgInfo *old_msginfo = messageview->msginfo;
2933
2934         if (messageview->msginfo != msginfo_update->msginfo)
2935                 return FALSE;
2936
2937         if ((msginfo_update->flags & MSGINFO_UPDATE_DELETED) ||
2938             MSG_IS_DELETED(old_msginfo->flags))
2939         {
2940                 if (messageview->new_window) {
2941                         if (old_msginfo->folder && old_msginfo->folder->total_msgs == 0) {
2942                                 messageview_clear(messageview);
2943                                 textview_show_info(messageview->mimeview->textview,
2944                                         _("\n  There are no messages in this folder"));
2945                                 return FALSE;
2946                         }
2947                         
2948                         if (!prefs_common.always_show_msg) {
2949                                 messageview_clear(messageview);
2950                                 textview_show_info(messageview->mimeview->textview,
2951                                         MSG_IS_DELETED(old_msginfo->flags) ?
2952                                         _("\n  Message has been deleted") :
2953                                         _("\n  Message has been deleted or moved to another folder"));
2954                         } else
2955                                 messageview->update_needed = TRUE;
2956
2957                 } else {
2958                         messageview_clear(messageview);
2959                         messageview_update(messageview, old_msginfo);
2960                 }
2961         } 
2962
2963         return FALSE;
2964 }
2965
2966 void messageview_set_menu_sensitive(MessageView *messageview)
2967 {
2968         if (!messageview || !messageview->ui_manager)
2969                 return;
2970
2971         cm_toggle_menu_set_active_full(messageview->ui_manager, "Menu/View/Quotes/CollapseAll", (prefs_common.hide_quotes == 1));
2972         cm_toggle_menu_set_active_full(messageview->ui_manager, "Menu/View/Quotes/Collapse2", (prefs_common.hide_quotes == 2));
2973         cm_toggle_menu_set_active_full(messageview->ui_manager, "Menu/View/Quotes/Collapse3", (prefs_common.hide_quotes == 3));
2974         cm_menu_set_sensitive_full(messageview->ui_manager, "Menu/View/Goto/PrevHistory", messageview_nav_has_prev(messageview));
2975         cm_menu_set_sensitive_full(messageview->ui_manager, "Menu/View/Goto/NextHistory", messageview_nav_has_next(messageview));
2976
2977         cm_menu_set_sensitive_full(messageview->ui_manager, "Menu/Message/CheckSignature", messageview->mimeview->signed_part);
2978 }
2979
2980 void messageview_learn (MessageView *msgview, gboolean is_spam)
2981 {
2982         if (is_spam) {
2983                 if (procmsg_spam_learner_learn(msgview->msginfo, NULL, TRUE) == 0)
2984                         procmsg_msginfo_set_flags(msgview->msginfo, MSG_SPAM, 0);
2985                 else
2986                         log_error(LOG_PROTOCOL, _("An error happened while learning.\n"));
2987                 
2988         } else {
2989                 if (procmsg_spam_learner_learn(msgview->msginfo, NULL, FALSE) == 0)
2990                         procmsg_msginfo_unset_flags(msgview->msginfo, MSG_SPAM, 0);
2991                 else
2992                         log_error(LOG_PROTOCOL, _("An error happened while learning.\n"));
2993         }
2994         if (msgview->toolbar)
2995                 toolbar_set_learn_button
2996                         (msgview->toolbar,
2997                          MSG_IS_SPAM(msgview->msginfo->flags)?LEARN_HAM:LEARN_SPAM);
2998         else
2999                 toolbar_set_learn_button
3000                         (msgview->mainwin->toolbar,
3001                          MSG_IS_SPAM(msgview->msginfo->flags)?LEARN_HAM:LEARN_SPAM);
3002 }
3003
3004 void messageview_list_urls (MessageView *msgview)
3005 {
3006         GSList *cur = msgview->mimeview->textview->uri_list;
3007         GSList *newlist = NULL;
3008         GHashTable *uri_hashtable;
3009         gchar *tmp;
3010         
3011         uri_hashtable = g_hash_table_new_full(g_str_hash, g_str_equal,
3012                                          (GDestroyNotify) g_free, NULL);
3013         
3014         for (; cur; cur = cur->next) {
3015                 ClickableText *uri = (ClickableText *)cur->data;
3016                 if (uri->uri &&
3017                     (!g_ascii_strncasecmp(uri->uri, "ftp.", 4) ||
3018                      !g_ascii_strncasecmp(uri->uri, "ftp:", 4) ||
3019                      !g_ascii_strncasecmp(uri->uri, "www.", 4) ||
3020                      !g_ascii_strncasecmp(uri->uri, "http:", 5) ||
3021                      !g_ascii_strncasecmp(uri->uri, "https:", 6)))
3022                 {
3023                         tmp = g_utf8_strdown(uri->uri, -1);
3024                         
3025                         if (g_hash_table_lookup(uri_hashtable, tmp)) {
3026                                 g_free(tmp);
3027                                 continue;
3028                         }
3029                         
3030                         newlist = g_slist_prepend(newlist, uri);
3031                         g_hash_table_insert(uri_hashtable, tmp,
3032                                             GUINT_TO_POINTER(g_str_hash(tmp)));
3033                 }
3034         }
3035         newlist = g_slist_reverse(newlist);
3036         uri_opener_open(msgview, newlist);
3037         g_slist_free(newlist);
3038         g_hash_table_destroy(uri_hashtable);
3039 }
3040
3041 static void save_part_as_cb(GtkAction *action, gpointer data)
3042 {
3043         MessageView *messageview = (MessageView *)data;
3044
3045         if (messageview->mimeview)
3046                 mimeview_save_as(messageview->mimeview);
3047 }
3048
3049 static void view_part_as_text_cb(GtkAction *action, gpointer data)
3050 {
3051         MessageView *messageview = (MessageView *)data;
3052
3053         if (messageview->mimeview)
3054                 mimeview_display_as_text(messageview->mimeview);
3055 }
3056
3057 static void open_part_cb(GtkAction *action, gpointer data)
3058 {
3059         MessageView *messageview = (MessageView *)data;
3060
3061         if (messageview->mimeview)
3062                 mimeview_launch(messageview->mimeview, NULL);
3063 }
3064 #ifndef G_OS_WIN32
3065 static void open_part_with_cb(GtkAction *action, gpointer data)
3066 {
3067         MessageView *messageview = (MessageView *)data;
3068
3069         if (messageview->mimeview)
3070                 mimeview_open_with(messageview->mimeview);
3071 }
3072 #endif
3073 static void check_signature_cb(GtkAction *action, gpointer data)
3074 {
3075         MessageView *messageview = (MessageView *)data;
3076
3077         if (messageview->mimeview)
3078                 mimeview_check_signature(messageview->mimeview);
3079 }
3080
3081 static void goto_next_part_cb(GtkAction *action, gpointer data)
3082 {
3083         MessageView *messageview = (MessageView *)data;
3084
3085         if (messageview->mimeview)
3086                 mimeview_select_next_part(messageview->mimeview);
3087 }
3088
3089 static void goto_prev_part_cb(GtkAction *action, gpointer data)
3090 {
3091         MessageView *messageview = (MessageView *)data;
3092
3093         if (messageview->mimeview)
3094                 mimeview_select_prev_part(messageview->mimeview);
3095 }
3096