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