1 /*
2  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 1999-2012 Hiroyuki Yamamoto
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 2 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, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18  */
19 
20 #include "defs.h"
21 
22 #include <glib.h>
23 #include <glib/gi18n.h>
24 #include <gdk/gdkkeysyms.h>
25 #include <gtk/gtknotebook.h>
26 #include <gtk/gtkvbox.h>
27 #include <gtk/gtkcontainer.h>
28 #include <gtk/gtkwindow.h>
29 #include <gtk/gtktextview.h>
30 #include <gtk/gtkmenu.h>
31 #include <gtk/gtkmenuitem.h>
32 #include <gtk/gtkcheckmenuitem.h>
33 #include <gtk/gtkstatusbar.h>
34 #include <gtk/gtktooltips.h>
35 #include <gtk/gtkarrow.h>
36 #include <stdio.h>
37 #include <ctype.h>
38 #include <string.h>
39 
40 #include "main.h"
41 #include "messageview.h"
42 #include "message_search.h"
43 #include "headerview.h"
44 #include "textview.h"
45 #include "imageview.h"
46 #include "mimeview.h"
47 #include "menu.h"
48 #include "about.h"
49 #include "filesel.h"
50 #include "sourcewindow.h"
51 #include "addressbook.h"
52 #include "alertpanel.h"
53 #include "inputdialog.h"
54 #include "manage_window.h"
55 #include "printing.h"
56 #include "procmsg.h"
57 #include "procheader.h"
58 #include "procmime.h"
59 #include "account.h"
60 #include "action.h"
61 #include "prefs_common.h"
62 #include "prefs_account.h"
63 #include "prefs_filter.h"
64 #include "filter.h"
65 #include "gtkutils.h"
66 #include "utils.h"
67 #include "rfc2015.h"
68 #include "plugin.h"
69 
70 static GList *messageview_list = NULL;
71 
72 static void messageview_set_mime_view_layout
73 					(MessageView		*messageview);
74 static void messageview_change_view_type(MessageView		*messageview,
75 					 MessageType		 type);
76 static void messageview_set_tool_menu	(MessageView		*messageview,
77 					 MimeInfo		*mimeinfo);
78 static void messageview_set_menu_state	(MessageView		*messageview);
79 
80 static void messageview_set_encoding_menu
81 					(MessageView		*messageview);
82 
83 static gint messageview_delete_cb	(GtkWidget		*widget,
84 					 GdkEventAny		*event,
85 					 MessageView		*messageview);
86 static void messageview_size_allocate_cb(GtkWidget		*widget,
87 					 GtkAllocation		*allocation);
88 static void messageview_toggle_attach_cb(GtkToggleButton	*toggle,
89 					 MessageView		*messageview);
90 static void messageview_switch_page_cb	(GtkNotebook		*notebook,
91 					 GtkNotebookPage	*page,
92 					 guint			 page_num,
93 					 MessageView		*messageview);
94 static gint messageview_menu_tool_btn_pressed
95 					(GtkWidget		*widget,
96 					 GdkEventButton		*event,
97 					 MessageView		*messageview);
98 static void messageview_open_file_cb	(GtkWidget		*widget,
99 					 MessageView		*messageview);
100 static void messageview_save_all_cb	(GtkWidget		*widget,
101 					 MessageView		*messageview);
102 static gboolean key_pressed		(GtkWidget		*widget,
103 					 GdkEventKey		*event,
104 					 MessageView		*messageview);
105 
106 static void save_as_cb			(gpointer	 data,
107 					 guint		 action,
108 					 GtkWidget	*widget);
109 #if GTK_CHECK_VERSION(2, 10, 0)
110 static void page_setup_cb		(gpointer	 data,
111 					 guint		 action,
112 					 GtkWidget	*widget);
113 #endif
114 static void print_cb			(gpointer	 data,
115 					 guint		 action,
116 					 GtkWidget	*widget);
117 static void close_cb			(gpointer	 data,
118 					 guint		 action,
119 					 GtkWidget	*widget);
120 static void copy_cb			(gpointer	 data,
121 					 guint		 action,
122 					 GtkWidget	*widget);
123 static void allsel_cb			(gpointer	 data,
124 					 guint		 action,
125 					 GtkWidget	*widget);
126 static void search_cb			(gpointer	 data,
127 					 guint		 action,
128 					 GtkWidget	*widget);
129 
130 static void set_charset_cb		(gpointer	 data,
131 					 guint		 action,
132 					 GtkWidget	*widget);
133 static void view_source_cb		(gpointer	 data,
134 					 guint		 action,
135 					 GtkWidget	*widget);
136 static void show_all_header_cb		(gpointer	 data,
137 					 guint		 action,
138 					 GtkWidget	*widget);
139 
140 static void compose_cb			(gpointer	 data,
141 					 guint		 action,
142 					 GtkWidget	*widget);
143 static void reply_cb			(gpointer	 data,
144 					 guint		 action,
145 					 GtkWidget	*widget);
146 static void reedit_cb			(gpointer	 data,
147 					 guint		 action,
148 					 GtkWidget	*widget);
149 
150 static void addressbook_open_cb		(gpointer	 data,
151 					 guint		 action,
152 					 GtkWidget	*widget);
153 static void add_address_cb		(gpointer	 data,
154 					 guint		 action,
155 					 GtkWidget	*widget);
156 static void create_filter_cb		(gpointer	 data,
157 					 guint		 action,
158 					 GtkWidget	*widget);
159 
160 static void about_cb			(gpointer	 data,
161 					 guint		 action,
162 					 GtkWidget	*widget);
163 
164 static GtkItemFactoryEntry msgview_entries[] =
165 {
166 	{N_("/_File"),			NULL, NULL, 0, "<Branch>"},
167 	{N_("/_File/_Save as..."),	NULL, save_as_cb, 0, NULL},
168 	{N_("/_File/---"),		NULL, NULL, 0, "<Separator>"},
169 #if GTK_CHECK_VERSION(2, 10, 0)
170 	{N_("/_File/Page set_up..."),	NULL, page_setup_cb, 0, NULL},
171 #endif
172 	{N_("/_File/_Print..."),	NULL, print_cb, 0, NULL},
173 	{N_("/_File/---"),		NULL, NULL, 0, "<Separator>"},
174 	{N_("/_File/_Close"),		NULL, close_cb, 0, NULL},
175 
176 	{N_("/_Edit"),			NULL, NULL, 0, "<Branch>"},
177 	{N_("/_Edit/_Copy"),		NULL, copy_cb, 0, NULL},
178 	{N_("/_Edit/Select _all"),	NULL, allsel_cb, 0, NULL},
179 	{N_("/_Edit/---"),		NULL, NULL, 0, "<Separator>"},
180 	{N_("/_Edit/_Find in current message..."),
181 					NULL, search_cb, 0, NULL},
182 
183 	{N_("/_View"),			NULL, NULL, 0, "<Branch>"},
184 
185 #define ENC_SEPARATOR \
186 	{N_("/_View/Character _encoding/---"),	NULL, NULL, 0, "<Separator>"}
187 #define ENC_ACTION(action) \
188 	NULL, set_charset_cb, action, "/View/Character encoding/Auto detect"
189 
190 	{N_("/_View/Character _encoding"),	NULL, NULL, 0, "<Branch>"},
191 	{N_("/_View/Character _encoding/_Auto detect"),
192 					NULL, set_charset_cb, C_AUTO, "<RadioItem>"},
193 	ENC_SEPARATOR,
194 	{N_("/_View/Character _encoding/7bit ascii (US-ASC_II)"),
195 	 ENC_ACTION(C_US_ASCII)},
196 
197 	{N_("/_View/Character _encoding/Unicode (_UTF-8)"),
198 	 ENC_ACTION(C_UTF_8)},
199 	ENC_SEPARATOR,
200 	{N_("/_View/Character _encoding/Western European (ISO-8859-_1)"),
201 	 ENC_ACTION(C_ISO_8859_1)},
202 	{N_("/_View/Character _encoding/Western European (ISO-8859-15)"),
203 	 ENC_ACTION(C_ISO_8859_15)},
204 	{N_("/_View/Character _encoding/Western European (Windows-1252)"),
205 	 ENC_ACTION(C_WINDOWS_1252)},
206 	ENC_SEPARATOR,
207 	{N_("/_View/Character _encoding/Central European (ISO-8859-_2)"),
208 	 ENC_ACTION(C_ISO_8859_2)},
209 	ENC_SEPARATOR,
210 	{N_("/_View/Character _encoding/_Baltic (ISO-8859-13)"),
211 	 ENC_ACTION(C_ISO_8859_13)},
212 	{N_("/_View/Character _encoding/Baltic (ISO-8859-_4)"),
213 	 ENC_ACTION(C_ISO_8859_4)},
214 	{N_("/_View/Character _encoding/Baltic (Windows-1257)"),
215 	 ENC_ACTION(C_WINDOWS_1257)},
216 	ENC_SEPARATOR,
217 	{N_("/_View/Character _encoding/Greek (ISO-8859-_7)"),
218 	 ENC_ACTION(C_ISO_8859_7)},
219 	ENC_SEPARATOR,
220 	{N_("/_View/Character _encoding/Arabic (ISO-8859-_6)"),
221 	 ENC_ACTION(C_ISO_8859_6)},
222 	{N_("/_View/Character _encoding/Arabic (Windows-1256)"),
223 	 ENC_ACTION(C_CP1256)},
224 	ENC_SEPARATOR,
225 	{N_("/_View/Character _encoding/Hebrew (ISO-8859-_8)"),
226 	 ENC_ACTION(C_ISO_8859_8)},
227 	{N_("/_View/Character _encoding/Hebrew (Windows-1255)"),
228 	 ENC_ACTION(C_CP1255)},
229 	ENC_SEPARATOR,
230 	{N_("/_View/Character _encoding/Turkish (ISO-8859-_9)"),
231 	 ENC_ACTION(C_ISO_8859_9)},
232 	ENC_SEPARATOR,
233 	{N_("/_View/Character _encoding/Cyrillic (ISO-8859-_5)"),
234 	 ENC_ACTION(C_ISO_8859_5)},
235 	{N_("/_View/Character _encoding/Cyrillic (KOI8-_R)"),
236 	 ENC_ACTION(C_KOI8_R)},
237 	{N_("/_View/Character _encoding/Cyrillic (KOI8-U)"),
238 	 ENC_ACTION(C_KOI8_U)},
239 	{N_("/_View/Character _encoding/Cyrillic (Windows-1251)"),
240 	 ENC_ACTION(C_CP1251)},
241 	ENC_SEPARATOR,
242 	{N_("/_View/Character _encoding/Japanese (ISO-2022-_JP)"),
243 	 ENC_ACTION(C_ISO_2022_JP)},
244 	{N_("/_View/Character _encoding/Japanese (ISO-2022-JP-2)"),
245 	 ENC_ACTION(C_ISO_2022_JP_2)},
246 	{N_("/_View/Character _encoding/Japanese (_EUC-JP)"),
247 	 ENC_ACTION(C_EUC_JP)},
248 	{N_("/_View/Character _encoding/Japanese (_Shift__JIS)"),
249 	 ENC_ACTION(C_SHIFT_JIS)},
250 	ENC_SEPARATOR,
251 	{N_("/_View/Character _encoding/Simplified Chinese (_GB2312)"),
252 	 ENC_ACTION(C_GB2312)},
253 	{N_("/_View/Character _encoding/Simplified Chinese (GBK)"),
254 	 ENC_ACTION(C_GBK)},
255 	{N_("/_View/Character _encoding/Traditional Chinese (_Big5)"),
256 	 ENC_ACTION(C_BIG5)},
257 	{N_("/_View/Character _encoding/Traditional Chinese (EUC-_TW)"),
258 	 ENC_ACTION(C_EUC_TW)},
259 	{N_("/_View/Character _encoding/Chinese (ISO-2022-_CN)"),
260 	 ENC_ACTION(C_ISO_2022_CN)},
261 	ENC_SEPARATOR,
262 	{N_("/_View/Character _encoding/Korean (EUC-_KR)"),
263 	 ENC_ACTION(C_EUC_KR)},
264 	{N_("/_View/Character _encoding/Korean (ISO-2022-KR)"),
265 	 ENC_ACTION(C_ISO_2022_KR)},
266 	ENC_SEPARATOR,
267 	{N_("/_View/Character _encoding/Thai (TIS-620)"),
268 	 ENC_ACTION(C_TIS_620)},
269 	{N_("/_View/Character _encoding/Thai (Windows-874)"),
270 	 ENC_ACTION(C_WINDOWS_874)},
271 
272 #undef ENC_SEPARATOR
273 #undef ENC_ACTION
274 
275 	{N_("/_View/---"),		NULL, NULL, 0, "<Separator>"},
276 	{N_("/_View/Mess_age source"),	NULL, view_source_cb, 0, NULL},
277 	{N_("/_View/All _headers"),
278 					NULL, show_all_header_cb, 0, "<ToggleItem>"},
279 
280 	{N_("/_Message"),		NULL, NULL, 0, "<Branch>"},
281 	{N_("/_Message/Compose _new message"),
282 					NULL, compose_cb, 0, NULL},
283 	{N_("/_Message/---"),		NULL, NULL, 0, "<Separator>"},
284 	{N_("/_Message/_Reply"),	NULL, reply_cb, COMPOSE_REPLY, NULL},
285 	{N_("/_Message/Repl_y to/_all"),
286 					NULL, reply_cb, COMPOSE_REPLY_TO_ALL, NULL},
287 	{N_("/_Message/Repl_y to/_sender"),
288 					NULL, reply_cb, COMPOSE_REPLY_TO_SENDER, NULL},
289 	{N_("/_Message/Repl_y to/mailing _list"),
290 					NULL, reply_cb, COMPOSE_REPLY_TO_LIST, NULL},
291 	{N_("/_Message/---"),		NULL, NULL, 0, "<Separator>"},
292 	{N_("/_Message/_Forward"),	NULL, reply_cb, COMPOSE_FORWARD, NULL},
293 	{N_("/_Message/For_ward as attachment"),
294 					NULL, reply_cb, COMPOSE_FORWARD_AS_ATTACH, NULL},
295 	{N_("/_Message/Redirec_t"),	NULL, reply_cb, COMPOSE_REDIRECT, NULL},
296 	{N_("/_Message/---"),		NULL, NULL, 0, "<Separator>"},
297 	{N_("/_Message/Re-_edit"),	NULL, reedit_cb, 0, NULL},
298 
299 	{N_("/_Tools"),			NULL, NULL, 0, "<Branch>"},
300 	{N_("/_Tools/_Address book"),	NULL, addressbook_open_cb, 0, NULL},
301 	{N_("/_Tools/Add sender to address boo_k"),
302 					NULL, add_address_cb, 0, NULL},
303 	{N_("/_Tools/---"),		NULL, NULL, 0, "<Separator>"},
304 	{N_("/_Tools/_Create filter rule"),
305 					NULL, NULL, 0, "<Branch>"},
306 	{N_("/_Tools/_Create filter rule/_Automatically"),
307 					NULL, create_filter_cb, FLT_BY_AUTO, NULL},
308 	{N_("/_Tools/_Create filter rule/by _From"),
309 					NULL, create_filter_cb, FLT_BY_FROM, NULL},
310 	{N_("/_Tools/_Create filter rule/by _To"),
311 					NULL, create_filter_cb, FLT_BY_TO, NULL},
312 	{N_("/_Tools/_Create filter rule/by _Subject"),
313 					NULL, create_filter_cb, FLT_BY_SUBJECT, NULL},
314 #ifndef G_OS_WIN32
315 	{N_("/_Tools/---"),		NULL, NULL, 0, "<Separator>"},
316 	{N_("/_Tools/Actio_ns"),	NULL, NULL, 0, "<Branch>"},
317 #endif
318 
319 	{N_("/_Help"),			NULL, NULL, 0, "<Branch>"},
320 	{N_("/_Help/_About"),		NULL, about_cb, 0, NULL}
321 };
322 
323 
messageview_create(void)324 MessageView *messageview_create(void)
325 {
326 	MessageView *messageview;
327 	GtkWidget *vbox;
328 	GtkWidget *notebook;
329 	GtkWidget *hbox;
330 	GtkWidget *toolbar_vbox;
331 	GtkWidget *toolbar_hbox;
332 	GtkWidget *image;
333 	GtkWidget *arrow;
334 	GtkWidget *mime_toggle_btn;
335 	GtkWidget *menu_tool_btn;
336 	GtkWidget *tool_menu;
337 	GtkWidget *menuitem;
338 	HeaderView *headerview;
339 	TextView *textview;
340 	MimeView *mimeview;
341 	GtkTooltips *tip;
342 
343 	debug_print(_("Creating message view...\n"));
344 	messageview = g_new0(MessageView, 1);
345 
346 	messageview->type = MVIEW_TEXT;
347 
348 	headerview = headerview_create();
349 
350 	textview = textview_create();
351 	textview->messageview = messageview;
352 
353 	mimeview = mimeview_create();
354 	mimeview->textview = textview_create();
355 	mimeview->textview->messageview = messageview;
356 	mimeview->imageview = imageview_create();
357 	mimeview->imageview->messageview = messageview;
358 	mimeview->messageview = messageview;
359 
360 	notebook = gtk_notebook_new();
361 	gtk_notebook_set_show_border(GTK_NOTEBOOK(notebook), FALSE);
362 	gtk_notebook_set_show_tabs(GTK_NOTEBOOK(notebook), FALSE);
363 	gtk_notebook_set_scrollable(GTK_NOTEBOOK(notebook), TRUE);
364 	gtk_widget_show(notebook);
365 
366 	gtk_container_add(GTK_CONTAINER(notebook), GTK_WIDGET_PTR(textview));
367 	gtk_notebook_set_tab_label_text
368 		(GTK_NOTEBOOK(notebook), GTK_WIDGET_PTR(textview), _("Text"));
369 
370 	gtk_container_add(GTK_CONTAINER(notebook), GTK_WIDGET_PTR(mimeview));
371 	gtk_notebook_set_tab_label_text(GTK_NOTEBOOK(notebook),
372 					GTK_WIDGET_PTR(mimeview),
373 					_("Attachments"));
374 
375 	gtk_notebook_set_current_page(GTK_NOTEBOOK(notebook), 0);
376 	gtk_widget_show_all(notebook);
377 
378 	/* Attachment toolbar */
379 	toolbar_vbox = gtk_vbox_new(FALSE, 0);
380 	gtk_widget_show(toolbar_vbox);
381 
382 	toolbar_hbox = gtk_hbox_new(FALSE, 0);
383 	gtk_widget_show(toolbar_hbox);
384 	gtk_box_pack_start(GTK_BOX(toolbar_vbox), toolbar_hbox, TRUE, FALSE, 0);
385 
386 	mime_toggle_btn = gtk_toggle_button_new();
387 	gtk_widget_show(mime_toggle_btn);
388 	gtk_box_pack_start(GTK_BOX(toolbar_hbox), mime_toggle_btn,
389 			   FALSE, FALSE, 0);
390 	g_signal_connect(G_OBJECT(mime_toggle_btn), "toggled",
391 			 G_CALLBACK(messageview_toggle_attach_cb), messageview);
392 
393 	image = stock_pixbuf_widget_scale(NULL, STOCK_PIXMAP_MAIL_ATTACH, 18, 18);
394 	gtk_widget_show(image);
395 	gtk_container_add(GTK_CONTAINER(mime_toggle_btn), image);
396 
397 	tip = gtk_tooltips_new();
398 	gtk_tooltips_set_tip(tip, mime_toggle_btn,
399 			     _("Switch to attachment list view"), NULL);
400 
401 	arrow = gtk_arrow_new(GTK_ARROW_DOWN, GTK_SHADOW_OUT);
402 	gtk_widget_show(arrow);
403 	gtk_widget_set_size_request(arrow, 5, -1);
404 
405 	menu_tool_btn = gtk_button_new();
406 	gtk_container_add(GTK_CONTAINER(menu_tool_btn), arrow);
407 	GTK_WIDGET_UNSET_FLAGS(menu_tool_btn, GTK_CAN_FOCUS);
408 	gtk_widget_show(menu_tool_btn);
409 	gtk_box_pack_start(GTK_BOX(toolbar_hbox), menu_tool_btn,
410 			   FALSE, FALSE, 0);
411 	g_signal_connect(G_OBJECT(menu_tool_btn), "button_press_event",
412 			 G_CALLBACK(messageview_menu_tool_btn_pressed),
413 			 messageview);
414 
415 	tool_menu = gtk_menu_new();
416 	MENUITEM_ADD(tool_menu, menuitem, NULL, 0);
417 	MENUITEM_ADD_WITH_MNEMONIC(tool_menu, menuitem, _("Save _all attachments..."), 0);
418 	g_signal_connect(G_OBJECT(menuitem), "activate",
419 			 G_CALLBACK(messageview_save_all_cb), messageview);
420 	gtk_widget_show_all(tool_menu);
421 
422 	gtk_widget_hide(toolbar_vbox);
423 
424 	hbox = gtk_hbox_new(FALSE, 0);
425 	gtk_widget_show(hbox);
426 	gtk_box_pack_start(GTK_BOX(hbox), toolbar_vbox, FALSE, FALSE, 0);
427 	gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET_PTR(headerview), TRUE, TRUE, 0);
428 
429 	vbox = gtk_vbox_new(FALSE, 0);
430 	gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
431 	gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0);
432 	gtk_widget_show(vbox);
433 
434 	/* to remove without destroyed */
435 	gtk_widget_ref(GTK_WIDGET_PTR(mimeview->textview));
436 	gtk_widget_ref(GTK_WIDGET_PTR(mimeview->imageview));
437 
438 	g_signal_connect(G_OBJECT(notebook), "switch_page",
439 			 G_CALLBACK(messageview_switch_page_cb), messageview);
440 
441 	messageview->vbox        = vbox;
442 
443 	messageview->notebook    = notebook;
444 
445 	messageview->hbox            = hbox;
446 	messageview->toolbar_vbox    = toolbar_vbox;
447 	messageview->mime_toggle_btn = mime_toggle_btn;
448 	messageview->menu_tool_btn   = menu_tool_btn;
449 	messageview->tool_menu       = tool_menu;
450 
451 	messageview->new_window  = FALSE;
452 	messageview->window      = NULL;
453 	messageview->window_vbox = NULL;
454 	messageview->body_vbox   = NULL;
455 
456 	messageview->headerview  = headerview;
457 	messageview->textview    = textview;
458 	messageview->mimeview    = mimeview;
459 
460 	messageview->statusbar     = NULL;
461 	messageview->statusbar_cid = 0;
462 
463 	messageview->current_page = 0;
464 
465 	return messageview;
466 }
467 
messageview_create_with_new_window(void)468 MessageView *messageview_create_with_new_window(void)
469 {
470 	MessageView *msgview;
471 	GtkWidget *window;
472 	GtkWidget *window_vbox;
473 	GtkWidget *body_vbox;
474 	GtkWidget *vspacer;
475 	GtkWidget *menubar;
476 	GtkItemFactory *ifactory;
477 	GtkWidget *statusbar;
478 	guint n_menu_entries;
479 
480 	window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
481 	gtk_window_set_title(GTK_WINDOW(window), _("Message View - Sylpheed"));
482 	gtk_window_set_wmclass(GTK_WINDOW(window), "message_view", "Sylpheed");
483 	gtk_window_set_policy(GTK_WINDOW(window), TRUE, TRUE, FALSE);
484 	gtk_widget_set_size_request(window, prefs_common.msgwin_width,
485 				    prefs_common.msgwin_height);
486 
487 	msgview = messageview_create();
488 
489 	window_vbox = gtk_vbox_new(FALSE, 0);
490 	gtk_container_add(GTK_CONTAINER(window), window_vbox);
491 
492 	g_signal_connect(G_OBJECT(window), "size_allocate",
493 			 G_CALLBACK(messageview_size_allocate_cb),
494 			 msgview);
495 	g_signal_connect(G_OBJECT(window), "delete_event",
496 			 G_CALLBACK(messageview_delete_cb), msgview);
497 	g_signal_connect(G_OBJECT(window), "key_press_event",
498 			 G_CALLBACK(key_pressed), msgview);
499 	MANAGE_WINDOW_SIGNALS_CONNECT(window);
500 
501 	n_menu_entries = sizeof(msgview_entries) / sizeof (msgview_entries[0]);
502 	menubar = menubar_create(window, msgview_entries, n_menu_entries,
503 				 "<MessageView>", msgview);
504 #if 0
505 	menu_factory_copy_rc("<Main>", "<MessageView>");
506 #endif
507 	gtk_box_pack_start(GTK_BOX(window_vbox), menubar, FALSE, TRUE, 0);
508 
509 	vspacer = gtk_vbox_new(FALSE, 0);
510 	gtk_box_pack_start(GTK_BOX(window_vbox), vspacer, FALSE, TRUE,
511 			   BORDER_WIDTH);
512 
513 	body_vbox = gtk_vbox_new(FALSE, BORDER_WIDTH);
514 	gtk_box_pack_start(GTK_BOX(window_vbox), body_vbox, TRUE, TRUE, 0);
515 
516 	gtk_box_pack_start(GTK_BOX(body_vbox), GTK_WIDGET_PTR(msgview),
517 			   TRUE, TRUE, 0);
518 	gtk_widget_grab_focus(msgview->textview->text);
519 
520 	statusbar = gtk_statusbar_new();
521 	gtk_box_pack_end(GTK_BOX(body_vbox), statusbar, FALSE, FALSE, 0);
522 	msgview->statusbar = statusbar;
523 	msgview->statusbar_cid = gtk_statusbar_get_context_id
524 		(GTK_STATUSBAR(statusbar), "Message View");
525 
526 	msgview->new_window = TRUE;
527 	msgview->window = window;
528 	msgview->window_vbox = window_vbox;
529 	msgview->body_vbox = body_vbox;
530 	msgview->menubar = menubar;
531 	msgview->menu_locked = FALSE;
532 	msgview->visible = TRUE;
533 
534 	gtk_widget_show_all(window);
535 	gtk_widget_hide(msgview->toolbar_vbox);
536 
537 	messageview_init(msgview);
538 
539 	messageview_set_encoding_menu(msgview);
540 
541 	ifactory = gtk_item_factory_from_widget(menubar);
542 #ifndef G_OS_WIN32
543 	action_update_msgview_menu(ifactory, msgview);
544 #endif
545 
546 	messageview_list = g_list_append(messageview_list, msgview);
547 
548 	return msgview;
549 }
550 
messageview_init(MessageView * messageview)551 void messageview_init(MessageView *messageview)
552 {
553 	headerview_init(messageview->headerview);
554 	textview_init(messageview->textview);
555 	mimeview_init(messageview->mimeview);
556 	/* messageview_set_font(messageview); */
557 }
558 
messageview_reflect_prefs(MessageView * messageview)559 void messageview_reflect_prefs(MessageView *messageview)
560 {
561 	if (messageview->type == MVIEW_MIME)
562 		messageview_set_mime_view_layout(messageview);
563 }
564 
messageview_get_window_list(void)565 GList *messageview_get_window_list(void)
566 {
567 	return messageview_list;
568 }
569 
messageview_show(MessageView * messageview,MsgInfo * msginfo,gboolean all_headers)570 gint messageview_show(MessageView *messageview, MsgInfo *msginfo,
571 		      gboolean all_headers)
572 {
573 	gchar *file;
574 	MimeInfo *mimeinfo;
575 
576 	g_return_val_if_fail(msginfo != NULL, -1);
577 
578 	mimeinfo = procmime_scan_message(msginfo);
579 	if (!mimeinfo) {
580 		messageview_change_view_type(messageview, MVIEW_TEXT);
581 		textview_show_error(messageview->textview);
582 		return -1;
583 	}
584 
585 	file = procmsg_get_message_file_path(msginfo);
586 	if (!file) {
587 		g_warning("can't get message file path.\n");
588 		procmime_mimeinfo_free_all(mimeinfo);
589 		messageview_change_view_type(messageview, MVIEW_TEXT);
590 		textview_show_error(messageview->textview);
591 		return -1;
592 	}
593 
594 	if (messageview->msginfo != msginfo) {
595 		procmsg_msginfo_free(messageview->msginfo);
596 		messageview->msginfo = procmsg_msginfo_get_full_info(msginfo);
597 		if (!messageview->msginfo)
598 			messageview->msginfo = procmsg_msginfo_copy(msginfo);
599 	}
600 	procmime_mimeinfo_free_all(messageview->mimeinfo);
601 	messageview->mimeinfo = mimeinfo;
602 	g_free(messageview->file);
603 	messageview->file = file;
604 
605 	if (messageview->window && msginfo->subject) {
606 		gchar *title;
607 
608 		title = g_strconcat(msginfo->subject, " - Sylpheed", NULL);
609 		gtk_window_set_title(GTK_WINDOW(messageview->window), title);
610 		g_free(title);
611 	}
612 	headerview_show(messageview->headerview, messageview->msginfo);
613 
614 	textview_set_all_headers(messageview->textview, all_headers);
615 	textview_set_all_headers(messageview->mimeview->textview, all_headers);
616 
617 	if (mimeinfo->mime_type != MIME_TEXT &&
618 	    (prefs_common.html_only_as_attach ||
619 	     mimeinfo->mime_type != MIME_TEXT_HTML)) {
620 		messageview_change_view_type(messageview, MVIEW_MIME);
621 		mimeview_show_message(messageview->mimeview, mimeinfo, file);
622 		messageview_set_tool_menu(messageview, mimeinfo);
623 	} else {
624 		messageview_change_view_type(messageview, MVIEW_TEXT);
625 		textview_show_message(messageview->textview, mimeinfo, file);
626 	}
627 
628 	if (messageview->new_window)
629 		messageview_set_menu_state(messageview);
630 
631 	syl_plugin_signal_emit("messageview-show", messageview, msginfo,
632 			       all_headers);
633 
634 	return 0;
635 }
636 
messageview_set_mime_view_layout(MessageView * messageview)637 static void messageview_set_mime_view_layout(MessageView *messageview)
638 {
639 	if (prefs_common.attach_toolbutton_pos == 0)
640 		gtk_box_set_child_packing(GTK_BOX(messageview->hbox), messageview->toolbar_vbox, FALSE, FALSE, 0, GTK_PACK_START);
641 	else
642 		gtk_box_set_child_packing(GTK_BOX(messageview->hbox), messageview->toolbar_vbox, FALSE, FALSE, 0, GTK_PACK_END);
643 
644 	if (prefs_common.show_attach_tab)
645 		gtk_widget_hide(messageview->toolbar_vbox);
646 	else
647 		gtk_widget_show(messageview->toolbar_vbox);
648 
649 	gtk_notebook_set_show_tabs(GTK_NOTEBOOK(messageview->notebook),
650 				   prefs_common.show_attach_tab);
651 }
652 
messageview_change_view_type(MessageView * messageview,MessageType type)653 static void messageview_change_view_type(MessageView *messageview,
654 					 MessageType type)
655 {
656 	GtkWidget *notebook = messageview->notebook;
657 
658 	if (messageview->type == type) return;
659 
660 	if (type == MVIEW_MIME) {
661 		messageview_set_mime_view_layout(messageview);
662 		gtk_notebook_set_current_page(GTK_NOTEBOOK(notebook),
663 					      messageview->current_page);
664 		if (messageview->current_page == 0)
665 			gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(messageview->mime_toggle_btn), FALSE);
666 		else
667 			gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(messageview->mime_toggle_btn), TRUE);
668 	} else if (type == MVIEW_TEXT) {
669 		gint current_page = messageview->current_page;
670 
671 		gtk_widget_hide(messageview->toolbar_vbox);
672 		gtk_notebook_set_show_tabs(GTK_NOTEBOOK(notebook), FALSE);
673 		gtk_notebook_set_current_page(GTK_NOTEBOOK(notebook), 0);
674 		messageview->current_page = current_page;
675 		mimeview_clear(messageview->mimeview);
676 	} else
677 		return;
678 
679 	messageview->type = type;
680 }
681 
messageview_set_tool_menu(MessageView * messageview,MimeInfo * mimeinfo)682 static void messageview_set_tool_menu(MessageView *messageview,
683 				      MimeInfo *mimeinfo)
684 {
685 	MimeInfo *partinfo;
686 	const gchar *name;
687 	GtkWidget *menuitem;
688 	GList *cur_item, *next = NULL;
689 	gint pos = 0;
690 	gboolean exist;
691 
692 	cur_item = GTK_MENU_SHELL(messageview->tool_menu)->children;
693 	while (cur_item != NULL) {
694 		next = cur_item->next;
695 		if (GTK_BIN(cur_item->data)->child == NULL)
696 			break;
697 		gtk_widget_destroy(GTK_WIDGET(cur_item->data));
698 		cur_item = next;
699 	}
700 
701 	for (partinfo = mimeinfo; partinfo != NULL;
702 	     partinfo = procmime_mimeinfo_next(partinfo)) {
703 		if (partinfo->filename || partinfo->name) {
704 			name = g_basename(partinfo->filename ? partinfo->filename : partinfo->name);
705 			if (*name == '\0')
706 				name = "mimetmp";
707 			menuitem = gtk_menu_item_new_with_label(name);
708 			gtk_widget_show(menuitem);
709 			gtk_menu_shell_insert(GTK_MENU_SHELL(messageview->tool_menu), menuitem, pos++);
710 			g_object_set_data(G_OBJECT(menuitem), "tool-menu-mimeinfo", partinfo);
711 			g_signal_connect(G_OBJECT(menuitem), "activate",
712 					 G_CALLBACK(messageview_open_file_cb),
713 					 messageview);
714 		}
715 	}
716 
717 	exist = (pos != 0);
718 	for (cur_item = next; cur_item != NULL; cur_item = cur_item->next) {
719 		menuitem = GTK_WIDGET(cur_item->data);
720 		gtk_widget_set_sensitive(menuitem, exist);
721 	}
722 }
723 
messageview_set_menu_state(MessageView * messageview)724 static void messageview_set_menu_state(MessageView *messageview)
725 {
726 	GtkItemFactory *ifactory;
727 	GtkWidget *menuitem;
728 
729 	messageview->menu_locked = TRUE;
730 
731 	ifactory = gtk_item_factory_from_widget(messageview->menubar);
732 	menuitem = gtk_item_factory_get_widget
733 		(ifactory, "/View/All headers");
734 	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menuitem),
735 				       messageview->textview->show_all_headers);
736 
737 	if (messageview->msginfo &&
738 	    FOLDER_ITEM_IS_SENT_FOLDER(messageview->msginfo->folder))
739 		menu_set_sensitive(ifactory, "/Message/Re-edit", TRUE);
740 	else
741 		menu_set_sensitive(ifactory, "/Message/Re-edit", FALSE);
742 
743 	messageview->menu_locked = FALSE;
744 }
745 
messageview_set_encoding_menu(MessageView * messageview)746 static void messageview_set_encoding_menu(MessageView *messageview)
747 {
748 	GtkItemFactoryEntry *entry;
749 	GtkItemFactory *ifactory;
750 	CharSet encoding;
751 	gchar *path, *p, *q;
752 	GtkWidget *item;
753 
754 	encoding = conv_get_charset_from_str(prefs_common.force_charset);
755 	ifactory = gtk_item_factory_from_widget(messageview->menubar);
756 
757 	for (entry = msgview_entries; entry->callback != view_source_cb;
758 	     entry++) {
759 		if (entry->callback == set_charset_cb &&
760 		    (CharSet)entry->callback_action == encoding) {
761 			p = q = path = g_strdup(entry->path);
762 			while (*p) {
763 				if (*p == '_') {
764 					if (p[1] == '_') {
765 						p++;
766 						*q++ = '_';
767 					}
768 				} else
769 					*q++ = *p;
770 				p++;
771 			}
772 			*q = '\0';
773 			item = gtk_item_factory_get_item(ifactory, path);
774 			gtk_widget_activate(item);
775 			g_free(path);
776 			break;
777 		}
778 	}
779 }
780 
messageview_clear(MessageView * messageview)781 void messageview_clear(MessageView *messageview)
782 {
783 	messageview_set_tool_menu(messageview, NULL);
784 	g_free(messageview->file);
785 	messageview->file = NULL;
786 	procmime_mimeinfo_free_all(messageview->mimeinfo);
787 	messageview->mimeinfo = NULL;
788 	procmsg_msginfo_free(messageview->msginfo);
789 	messageview->msginfo = NULL;
790 	messageview_change_view_type(messageview, MVIEW_TEXT);
791 	headerview_clear(messageview->headerview);
792 	textview_clear(messageview->textview);
793 	mimeview_clear(messageview->mimeview);
794 }
795 
messageview_destroy(MessageView * messageview)796 void messageview_destroy(MessageView *messageview)
797 {
798 	GtkWidget *textview  = GTK_WIDGET_PTR(messageview->mimeview->textview);
799 	GtkWidget *imageview = GTK_WIDGET_PTR(messageview->mimeview->imageview);
800 
801 	messageview_list = g_list_remove(messageview_list, messageview);
802 
803 	headerview_destroy(messageview->headerview);
804 	textview_destroy(messageview->textview);
805 	mimeview_destroy(messageview->mimeview);
806 
807 	procmsg_msginfo_free(messageview->msginfo);
808 
809 	gtk_widget_destroy(messageview->tool_menu);
810 	if (messageview->window)
811 		gtk_widget_destroy(messageview->window);
812 
813 	g_free(messageview);
814 
815 	gtk_widget_unref(textview);
816 	gtk_widget_unref(imageview);
817 }
818 
messageview_quote_color_set(void)819 void messageview_quote_color_set(void)
820 {
821 }
822 
messageview_set_font(MessageView * messageview)823 void messageview_set_font(MessageView *messageview)
824 {
825 	textview_set_font(messageview->textview, NULL);
826 }
827 
messageview_get_current_textview(MessageView * messageview)828 TextView *messageview_get_current_textview(MessageView *messageview)
829 {
830 	TextView *text = NULL;
831 
832 	if (messageview->type == MVIEW_TEXT)
833 		text = messageview->textview;
834 	else if (messageview->type == MVIEW_MIME) {
835 		if (gtk_notebook_get_current_page
836 			(GTK_NOTEBOOK(messageview->notebook)) == 0)
837 			text = messageview->textview;
838 		else if (messageview->mimeview->type == MIMEVIEW_TEXT)
839 			text = messageview->mimeview->textview;
840 	}
841 
842 	return text;
843 }
844 
messageview_get_selected_mime_part(MessageView * messageview)845 MimeInfo *messageview_get_selected_mime_part(MessageView *messageview)
846 {
847 	if (messageview->type == MVIEW_MIME)
848 		return mimeview_get_selected_part(messageview->mimeview);
849 
850 	return NULL;
851 }
852 
messageview_copy_clipboard(MessageView * messageview)853 void messageview_copy_clipboard(MessageView *messageview)
854 {
855 	TextView *text;
856 
857 	text = messageview_get_current_textview(messageview);
858 	if (text) {
859 		GtkTextView *textview = GTK_TEXT_VIEW(text->text);
860 		GtkTextBuffer *buffer;
861 		GtkClipboard *clipboard;
862 
863 		buffer = gtk_text_view_get_buffer(textview);
864 		clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
865 		gtk_text_buffer_copy_clipboard(buffer, clipboard);
866 	}
867 }
868 
messageview_select_all(MessageView * messageview)869 void messageview_select_all(MessageView *messageview)
870 {
871 	TextView *text;
872 
873 	text = messageview_get_current_textview(messageview);
874 	if (text) {
875 		GtkTextView *textview = GTK_TEXT_VIEW(text->text);
876 		GtkTextBuffer *buffer;
877 		GtkTextIter start, end;
878 
879 		buffer = gtk_text_view_get_buffer(textview);
880 		gtk_text_buffer_get_bounds(buffer, &start, &end);
881 		gtk_text_buffer_select_range(buffer, &start, &end);
882 	}
883 }
884 
messageview_set_position(MessageView * messageview,gint pos)885 void messageview_set_position(MessageView *messageview, gint pos)
886 {
887 	textview_set_position(messageview->textview, pos);
888 }
889 
messageview_search_string(MessageView * messageview,const gchar * str,gboolean case_sens)890 gboolean messageview_search_string(MessageView *messageview, const gchar *str,
891 				   gboolean case_sens)
892 {
893 	return textview_search_string(messageview->textview, str, case_sens);
894 	return FALSE;
895 }
896 
messageview_search_string_backward(MessageView * messageview,const gchar * str,gboolean case_sens)897 gboolean messageview_search_string_backward(MessageView *messageview,
898 					    const gchar *str,
899 					    gboolean case_sens)
900 {
901 	return textview_search_string_backward(messageview->textview,
902 					       str, case_sens);
903 	return FALSE;
904 }
905 
messageview_is_visible(MessageView * messageview)906 gboolean messageview_is_visible(MessageView *messageview)
907 {
908 	return messageview->visible;
909 }
910 
messageview_save_as(MessageView * messageview)911 void messageview_save_as(MessageView *messageview)
912 {
913 	gchar *filename = NULL;
914 	MsgInfo *msginfo;
915 	gchar *src, *dest;
916 	FileselFileType types[4] = {{NULL, NULL}};
917 	gint selected_type = 0;
918 	gint result;
919 	gboolean all_headers;
920 
921 	if (!messageview->msginfo) return;
922 	msginfo = messageview->msginfo;
923 
924 	if (msginfo->subject && *msginfo->subject) {
925 		filename = g_strdup_printf("%s.eml", msginfo->subject);
926 	} else {
927 		filename = g_strdup_printf("%u.eml", msginfo->msgnum);
928 	}
929 	subst_for_filename(filename);
930 
931 	types[0].type = _("Original (EML/RFC 822)");
932 	types[0].ext = "eml";
933 	types[1].type = _("Text");
934 	types[1].ext = "txt";
935 	types[2].type = _("Text (UTF-8)");
936 	types[2].ext = "txt";
937 	dest = filesel_save_as_type(filename, types, prefs_common.save_file_type, &selected_type);
938 
939 	g_free(filename);
940 	if (!dest)
941 		return;
942 
943 	all_headers = messageview->textview->show_all_headers;
944 
945 	if (selected_type == 1) {
946 		result = procmsg_save_message_as_text(msginfo, dest, conv_get_locale_charset_str(), all_headers);
947 	} else if (selected_type == 2) {
948 		result = procmsg_save_message_as_text(msginfo, dest, NULL, all_headers);
949 	} else {
950 		src = procmsg_get_message_file(msginfo);
951 		result = copy_file(src, dest, TRUE);
952 		g_free(src);
953 	}
954 
955 	if (result < 0) {
956 		gchar *utf8_dest;
957 
958 		utf8_dest = conv_filename_to_utf8(dest);
959 		alertpanel_error(_("Can't save the file `%s'."),
960 				 g_basename(utf8_dest));
961 		g_free(utf8_dest);
962 	}
963 
964 	g_free(dest);
965 
966 	prefs_common.save_file_type = selected_type;
967 }
968 
messageview_delete_cb(GtkWidget * widget,GdkEventAny * event,MessageView * messageview)969 static gint messageview_delete_cb(GtkWidget *widget, GdkEventAny *event,
970 				  MessageView *messageview)
971 {
972 	messageview_destroy(messageview);
973 	return TRUE;
974 }
975 
messageview_size_allocate_cb(GtkWidget * widget,GtkAllocation * allocation)976 static void messageview_size_allocate_cb(GtkWidget *widget,
977 					 GtkAllocation *allocation)
978 {
979 	g_return_if_fail(allocation != NULL);
980 
981 	prefs_common.msgwin_width  = allocation->width;
982 	prefs_common.msgwin_height = allocation->height;
983 }
984 
messageview_toggle_attach_cb(GtkToggleButton * toggle,MessageView * messageview)985 static void messageview_toggle_attach_cb(GtkToggleButton *toggle,
986 					 MessageView *messageview)
987 {
988 	if (gtk_toggle_button_get_active(toggle))
989 		gtk_notebook_set_current_page(GTK_NOTEBOOK(messageview->notebook), 1);
990 	else
991 		gtk_notebook_set_current_page(GTK_NOTEBOOK(messageview->notebook), 0);
992 }
993 
messageview_switch_page_cb(GtkNotebook * notebook,GtkNotebookPage * page,guint page_num,MessageView * messageview)994 static void messageview_switch_page_cb(GtkNotebook *notebook,
995 				       GtkNotebookPage *page, guint page_num,
996 				       MessageView *messageview)
997 {
998 	if (messageview->current_page != page_num) {
999 		messageview->current_page = page_num;
1000 		if (page_num == 0)
1001 			gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(messageview->mime_toggle_btn), FALSE);
1002 		else
1003 			gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(messageview->mime_toggle_btn), TRUE);
1004 	}
1005 }
1006 
messageview_menu_tool_btn_pressed(GtkWidget * widget,GdkEventButton * event,MessageView * messageview)1007 static gint messageview_menu_tool_btn_pressed(GtkWidget *widget,
1008 					      GdkEventButton *event,
1009 					      MessageView *messageview)
1010 {
1011 	if (!event)
1012 		return FALSE;
1013 
1014 	gtk_menu_popup(GTK_MENU(messageview->tool_menu), NULL, NULL,
1015 		       menu_button_position, messageview->mime_toggle_btn,
1016 		       event->button, event->time);
1017 
1018 	return TRUE;
1019 }
1020 
messageview_open_file_cb(GtkWidget * widget,MessageView * messageview)1021 static void messageview_open_file_cb(GtkWidget *widget, MessageView *messageview)
1022 {
1023 	MimeInfo *partinfo;
1024 
1025 	partinfo = g_object_get_data(G_OBJECT(widget), "tool-menu-mimeinfo");
1026 	if (partinfo)
1027 		mimeview_launch_part(messageview->mimeview, partinfo);
1028 }
1029 
messageview_save_all_cb(GtkWidget * widget,MessageView * messageview)1030 static void messageview_save_all_cb(GtkWidget *widget, MessageView *messageview)
1031 {
1032 	mimeview_save_all(messageview->mimeview);
1033 }
1034 
key_pressed(GtkWidget * widget,GdkEventKey * event,MessageView * messageview)1035 static gboolean key_pressed(GtkWidget *widget, GdkEventKey *event,
1036 			    MessageView *messageview)
1037 {
1038 	if (event && event->keyval == GDK_Escape && messageview->window) {
1039 		messageview_destroy(messageview);
1040 		return TRUE;
1041 	}
1042 	return FALSE;
1043 }
1044 
save_as_cb(gpointer data,guint action,GtkWidget * widget)1045 static void save_as_cb(gpointer data, guint action, GtkWidget *widget)
1046 {
1047 	MessageView *messageview = (MessageView *)data;
1048 	messageview_save_as(messageview);
1049 }
1050 
1051 #if GTK_CHECK_VERSION(2, 10, 0)
page_setup_cb(gpointer data,guint action,GtkWidget * widget)1052 static void page_setup_cb(gpointer data, guint action, GtkWidget *widget)
1053 {
1054 	printing_page_setup_gtk();
1055 }
1056 #endif
1057 
print_cb(gpointer data,guint action,GtkWidget * widget)1058 static void print_cb(gpointer data, guint action, GtkWidget *widget)
1059 {
1060 	MessageView *messageview = (MessageView *)data;
1061 
1062 	if (!messageview->msginfo) return;
1063 
1064 	printing_print_message(messageview->msginfo,
1065 			       messageview->textview->show_all_headers);
1066 }
1067 
close_cb(gpointer data,guint action,GtkWidget * widget)1068 static void close_cb(gpointer data, guint action, GtkWidget *widget)
1069 {
1070 	MessageView *messageview = (MessageView *)data;
1071 	messageview_destroy(messageview);
1072 }
1073 
copy_cb(gpointer data,guint action,GtkWidget * widget)1074 static void copy_cb(gpointer data, guint action, GtkWidget *widget)
1075 {
1076 	MessageView *messageview = (MessageView *)data;
1077 	messageview_copy_clipboard(messageview);
1078 }
1079 
allsel_cb(gpointer data,guint action,GtkWidget * widget)1080 static void allsel_cb(gpointer data, guint action, GtkWidget *widget)
1081 {
1082 	MessageView *messageview = (MessageView *)data;
1083 	messageview_select_all(messageview);
1084 }
1085 
search_cb(gpointer data,guint action,GtkWidget * widget)1086 static void search_cb(gpointer data, guint action, GtkWidget *widget)
1087 {
1088 	MessageView *messageview = (MessageView *)data;
1089 	message_search(messageview);
1090 }
1091 
set_charset_cb(gpointer data,guint action,GtkWidget * widget)1092 static void set_charset_cb(gpointer data, guint action, GtkWidget *widget)
1093 {
1094 	MessageView *messageview = (MessageView *)data;
1095 	const gchar *charset;
1096 
1097 	if (GTK_CHECK_MENU_ITEM(widget)->active) {
1098 		charset = conv_get_charset_str((CharSet)action);
1099 		g_free(messageview->forced_charset);
1100 		messageview->forced_charset = g_strdup(charset);
1101 		if (messageview->msginfo)
1102 			messageview_show(messageview, messageview->msginfo,
1103 					 FALSE);
1104 	}
1105 }
1106 
view_source_cb(gpointer data,guint action,GtkWidget * widget)1107 static void view_source_cb(gpointer data, guint action, GtkWidget *widget)
1108 {
1109 	MessageView *messageview = (MessageView *)data;
1110 	SourceWindow *srcwin;
1111 
1112 	if (!messageview->msginfo) return;
1113 
1114 	srcwin = source_window_create();
1115 	source_window_show_msg(srcwin, messageview->msginfo);
1116 	source_window_show(srcwin);
1117 }
1118 
show_all_header_cb(gpointer data,guint action,GtkWidget * widget)1119 static void show_all_header_cb(gpointer data, guint action, GtkWidget *widget)
1120 {
1121 	MessageView *messageview = (MessageView *)data;
1122 	MsgInfo *msginfo = messageview->msginfo;
1123 
1124 	if (!msginfo) return;
1125 	if (messageview->menu_locked) return;
1126 
1127 	messageview->msginfo = NULL;
1128 	messageview_show(messageview, msginfo,
1129 			 GTK_CHECK_MENU_ITEM(widget)->active);
1130 	procmsg_msginfo_free(msginfo);
1131 }
1132 
compose_cb(gpointer data,guint action,GtkWidget * widget)1133 static void compose_cb(gpointer data, guint action, GtkWidget *widget)
1134 {
1135 	MessageView *messageview = (MessageView *)data;
1136 	PrefsAccount *ac = NULL;
1137 	FolderItem *item = NULL;
1138 
1139 	if (messageview->msginfo)
1140 		item = messageview->msginfo->folder;
1141 
1142 	if (item) {
1143 		ac = account_find_from_item(item);
1144 		if (ac && ac->protocol == A_NNTP &&
1145 		    FOLDER_TYPE(item->folder) == F_NEWS) {
1146 			compose_new(ac, item, item->path, NULL);
1147 			return;
1148 		}
1149 	}
1150 
1151 	compose_new(ac, item, NULL, NULL);
1152 }
1153 
reply_cb(gpointer data,guint action,GtkWidget * widget)1154 static void reply_cb(gpointer data, guint action, GtkWidget *widget)
1155 {
1156 	MessageView *messageview = (MessageView *)data;
1157 	GSList *mlist = NULL;
1158 	MsgInfo *msginfo;
1159 	gchar *text = NULL;
1160 	ComposeMode mode = (ComposeMode)action;
1161 	gchar *prev_force_charset;
1162 
1163 	msginfo = messageview->msginfo;
1164 	mlist = g_slist_append(NULL, msginfo);
1165 
1166 	text = gtkut_text_view_get_selection
1167 		(GTK_TEXT_VIEW(messageview->textview->text));
1168 	if (text && *text == '\0') {
1169 		g_free(text);
1170 		text = NULL;
1171 	}
1172 
1173 	if (!COMPOSE_QUOTE_MODE(mode))
1174 		mode |= prefs_common.reply_with_quote
1175 			? COMPOSE_WITH_QUOTE : COMPOSE_WITHOUT_QUOTE;
1176 
1177 	prev_force_charset = prefs_common.force_charset;
1178 	prefs_common.force_charset = messageview->forced_charset;
1179 
1180 	switch (COMPOSE_MODE(mode)) {
1181 	case COMPOSE_REPLY:
1182 	case COMPOSE_REPLY_TO_SENDER:
1183 	case COMPOSE_REPLY_TO_ALL:
1184 	case COMPOSE_REPLY_TO_LIST:
1185 		compose_reply(msginfo, msginfo->folder, mode, text);
1186 		break;
1187 	case COMPOSE_FORWARD:
1188 		compose_forward(mlist, msginfo->folder, FALSE, text);
1189 		break;
1190 	case COMPOSE_FORWARD_AS_ATTACH:
1191 		compose_forward(mlist, msginfo->folder, TRUE, NULL);
1192 		break;
1193 	case COMPOSE_REDIRECT:
1194 		compose_redirect(msginfo, msginfo->folder);
1195 		break;
1196 	default:
1197 		g_warning("messageview.c: reply_cb(): invalid mode: %d\n",
1198 			  mode);
1199 	}
1200 
1201 	prefs_common.force_charset = prev_force_charset;
1202 
1203 	/* summary_set_marks_selected(summaryview); */
1204 	g_free(text);
1205 	g_slist_free(mlist);
1206 }
1207 
reedit_cb(gpointer data,guint action,GtkWidget * widget)1208 static void reedit_cb(gpointer data, guint action, GtkWidget *widget)
1209 {
1210 	MessageView *messageview = (MessageView *)data;
1211 	MsgInfo *msginfo;
1212 
1213 	if (!messageview->msginfo) return;
1214 	msginfo = messageview->msginfo;
1215 	if (!msginfo->folder) return;
1216 	if (msginfo->folder->stype != F_OUTBOX &&
1217 	    msginfo->folder->stype != F_DRAFT &&
1218 	    msginfo->folder->stype != F_QUEUE) return;
1219 
1220 	compose_reedit(msginfo);
1221 }
1222 
addressbook_open_cb(gpointer data,guint action,GtkWidget * widget)1223 static void addressbook_open_cb(gpointer data, guint action, GtkWidget *widget)
1224 {
1225 	addressbook_open(NULL);
1226 }
1227 
add_address_cb(gpointer data,guint action,GtkWidget * widget)1228 static void add_address_cb(gpointer data, guint action, GtkWidget *widget)
1229 {
1230 	MessageView *messageview = (MessageView *)data;
1231 	MsgInfo *msginfo;
1232 	gchar *from;
1233 
1234 	if (!messageview->msginfo) return;
1235 	msginfo = messageview->msginfo;
1236 	from = g_strdup(msginfo->from);
1237 	eliminate_address_comment(from);
1238 	extract_address(from);
1239 	addressbook_add_contact(msginfo->fromname, from, NULL);
1240 	g_free(from);
1241 }
1242 
create_filter_cb(gpointer data,guint action,GtkWidget * widget)1243 static void create_filter_cb(gpointer data, guint action, GtkWidget *widget)
1244 {
1245 	MessageView *messageview = (MessageView *)data;
1246 	gchar *header = NULL;
1247 	gchar *key = NULL;
1248 
1249 	if (!messageview->msginfo) return;
1250 
1251 	filter_get_keyword_from_msg(messageview->msginfo, &header, &key,
1252 				    (FilterCreateType)action);
1253 	prefs_filter_open(messageview->msginfo, header, key);
1254 
1255 	g_free(header);
1256 	g_free(key);
1257 }
1258 
about_cb(gpointer data,guint action,GtkWidget * widget)1259 static void about_cb(gpointer data, guint action, GtkWidget *widget)
1260 {
1261 	about_show();
1262 }
1263