messageview.c (78337B)
1 /* 2 * Claws Mail -- a GTK based, lightweight, and fast e-mail client 3 * Copyright (C) 1999-2025 the Claws Mail team and 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 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 "summaryview.h" 33 #include "textview.h" 34 #include "mimeview.h" 35 #include "menu.h" 36 #include "filesel.h" 37 #include "foldersel.h" 38 #include "sourcewindow.h" 39 #include "alertpanel.h" 40 #include "inputdialog.h" 41 #include "mainwindow.h" 42 #include "manage_window.h" 43 #include "procmsg.h" 44 #include "procheader.h" 45 #include "procmime.h" 46 #include "account.h" 47 #include "action.h" 48 #include "prefs_common.h" 49 #include "prefs_account.h" 50 #include "gtkutils.h" 51 #include "utils.h" 52 #include "send_message.h" 53 #include "stock_pixmap.h" 54 #include "hooks.h" 55 #include "inc.h" 56 #include "log.h" 57 #include "combobox.h" 58 #include "quoted-printable.h" 59 #include "version.h" 60 #include "statusbar.h" 61 #include "folder_item_prefs.h" 62 #include "file-utils.h" 63 64 #include "addressbook.h" 65 static GList *messageview_list = NULL; 66 67 static gint messageview_delete_cb (GtkWidget *widget, 68 GdkEventAny *event, 69 MessageView *messageview); 70 static void messageview_size_allocate_cb(GtkWidget *widget, 71 GtkAllocation *allocation); 72 static gboolean key_pressed (GtkWidget *widget, 73 GdkEventKey *event, 74 MessageView *messageview); 75 76 static void save_as_cb (GtkAction *action, 77 gpointer data); 78 void messageview_save_as (MessageView *messageview); 79 static void close_cb (GtkAction *action, 80 gpointer data); 81 static void copy_cb (GtkAction *action, 82 gpointer data); 83 static void allsel_cb (GtkAction *action, 84 gpointer data); 85 static void search_cb (GtkAction *action, 86 gpointer data); 87 88 static void prev_cb (GtkAction *action, 89 gpointer data); 90 static void next_cb (GtkAction *action, 91 gpointer data); 92 static void prev_unread_cb (GtkAction *action, 93 gpointer data); 94 static void next_unread_cb (GtkAction *action, 95 gpointer data); 96 static void prev_new_cb (GtkAction *action, 97 gpointer data); 98 static void next_new_cb (GtkAction *action, 99 gpointer data); 100 static void prev_marked_cb (GtkAction *action, 101 gpointer data); 102 static void next_marked_cb (GtkAction *action, 103 gpointer data); 104 static void prev_labeled_cb (GtkAction *action, 105 gpointer data); 106 static void next_labeled_cb (GtkAction *action, 107 gpointer data); 108 static void prev_history_cb (GtkAction *action, 109 gpointer data); 110 static void next_history_cb (GtkAction *action, 111 gpointer data); 112 static void parent_cb (GtkAction *action, 113 gpointer data); 114 static void goto_unread_folder_cb (GtkAction *action, 115 gpointer data); 116 static void goto_folder_cb (GtkAction *action, 117 gpointer data); 118 119 static void set_charset_cb (GtkAction *action, GtkRadioAction *current, gpointer data); 120 static void set_decode_cb (GtkAction *action, GtkRadioAction *current, gpointer data); 121 122 static void view_source_cb (GtkAction *action, 123 gpointer data); 124 125 static void show_all_header_cb (GtkToggleAction *action, 126 gpointer data); 127 static void msg_hide_quotes_cb (GtkToggleAction *action, 128 gpointer data); 129 130 static void compose_cb (GtkAction *action, 131 gpointer data); 132 static void reply_cb (GtkAction *action, 133 gpointer data); 134 135 static void addressbook_open_cb (GtkAction *action, 136 gpointer data); 137 static void add_address_cb (GtkAction *action, 138 gpointer data); 139 140 static void messageview_update (MessageView *msgview, 141 MsgInfo *old_msginfo); 142 static gboolean messageview_update_msg (gpointer source, gpointer data); 143 144 static void save_part_as_cb(GtkAction *action, gpointer data); 145 static void view_part_as_text_cb(GtkAction *action, gpointer data); 146 static void open_part_cb(GtkAction *action, gpointer data); 147 static void open_part_with_cb(GtkAction *action, gpointer data); 148 static void goto_next_part_cb(GtkAction *action, gpointer data); 149 static void goto_prev_part_cb(GtkAction *action, gpointer data); 150 151 static void messageview_nothing_cb (GtkAction *action, gpointer data) 152 { 153 } 154 155 static GList *msgview_list = NULL; 156 static GtkActionEntry msgview_entries[] = 157 { 158 {"Menu", NULL, "Menu", NULL, NULL, NULL }, 159 /* menus */ 160 {"File", NULL, N_("_File"), NULL, NULL, NULL }, 161 {"Edit", NULL, N_("_Edit"), NULL, NULL, NULL }, 162 {"View", NULL, N_("_View"), NULL, NULL, NULL }, 163 {"Message", NULL, N_("_Message"), NULL, NULL, NULL }, 164 {"Tools", NULL, N_("_Tools"), NULL, NULL, NULL }, 165 {"Help", NULL, N_("_Help"), NULL, NULL, NULL }, 166 {"PlaceHolder", NULL, "Placeholder", NULL, NULL, G_CALLBACK(messageview_nothing_cb) }, 167 168 /* File menu */ 169 {"File/SaveAs", NULL, N_("_Save email as..."), "<control>S", NULL, G_CALLBACK(save_as_cb) }, 170 {"File/SavePartAs", NULL, N_("_Save part as..."), "Y", NULL, G_CALLBACK(save_part_as_cb) }, 171 {"File/---", NULL, "---", NULL, NULL, NULL }, 172 {"File/Close", NULL, N_("_Close"), "<control>W", NULL, G_CALLBACK(close_cb) }, 173 174 /* Edit menu */ 175 {"Edit/Copy", NULL, N_("_Copy"), "<control>C", NULL, G_CALLBACK(copy_cb) }, 176 {"Edit/SelectAll", NULL, N_("_Select all"), "<control>A", NULL, G_CALLBACK(allsel_cb) }, 177 {"Edit/---", NULL, "---", NULL, NULL, NULL }, 178 {"Edit/Find", NULL, N_("_Find"), "<control>F", NULL, G_CALLBACK(search_cb) }, 179 180 /* View menu */ 181 {"View/Goto", NULL, N_("_Go to"), NULL, NULL, NULL }, 182 {"View/Goto/Prev", NULL, N_("_Previous message"), "P", NULL, G_CALLBACK(prev_cb) }, 183 {"View/Goto/Next", NULL, N_("_Next message"), "N", NULL, G_CALLBACK(next_cb) }, 184 {"View/Goto/---", NULL, "---", NULL, NULL, NULL }, 185 {"View/Goto/PrevUnread", NULL, N_("P_revious unread message"), "<shift>P", NULL, G_CALLBACK(prev_unread_cb) }, 186 {"View/Goto/NextUnread", NULL, N_("N_ext unread message"), "<shift>N", NULL, G_CALLBACK(next_unread_cb) }, 187 /* {"View/Goto/---", NULL, "---", NULL, NULL, NULL }, */ 188 {"View/Goto/PrevNew", NULL, N_("Previous ne_w message"), NULL, NULL, G_CALLBACK(prev_new_cb) }, 189 {"View/Goto/NextNew", NULL, N_("Ne_xt new message"), NULL, NULL, G_CALLBACK(next_new_cb) }, 190 /* {"View/Goto/---", NULL, "---", NULL, NULL, NULL }, */ 191 {"View/Goto/PrevMarked", NULL, N_("Previous _marked message"), NULL, NULL, G_CALLBACK(prev_marked_cb) }, 192 {"View/Goto/NextMarked", NULL, N_("Next m_arked message"), NULL, NULL, G_CALLBACK(next_marked_cb) }, 193 /* {"View/Goto/---", NULL, "---", NULL, NULL, NULL }, */ 194 {"View/Goto/PrevLabeled", NULL, N_("Previous _labeled message"), NULL, NULL, G_CALLBACK(prev_labeled_cb) }, 195 {"View/Goto/NextLabeled", NULL, N_("Next la_beled message"), NULL, NULL, G_CALLBACK(next_labeled_cb) }, 196 /* {"View/Goto/---", NULL, "---", NULL, NULL, NULL }, */ 197 {"View/Goto/PrevHistory", NULL, N_("Previously opened message"), "<alt>Left", NULL, G_CALLBACK(prev_history_cb) }, 198 {"View/Goto/NextHistory", NULL, N_("Next opened message"), "<alt>Right", NULL, G_CALLBACK(next_history_cb) }, 199 /* {"View/Goto/---", NULL, "---", NULL, NULL, NULL }, */ 200 {"View/Goto/ParentMessage", NULL, N_("Parent message"), "<control>Up", NULL, G_CALLBACK(parent_cb) }, 201 /* {"View/Goto/---", NULL, "---", NULL, NULL, NULL }, */ 202 {"View/Goto/NextUnreadFolder", NULL, N_("Next unread _folder"), "<shift>G", NULL, G_CALLBACK(goto_unread_folder_cb) }, 203 {"View/Goto/Folder", NULL, N_("F_older..."), "G", NULL, G_CALLBACK(goto_folder_cb) }, 204 /* {"View/Goto/---", NULL, "---", NULL, NULL, NULL }, */ 205 {"View/Goto/NextPart", NULL, N_("Next part"), "A", NULL, G_CALLBACK(goto_next_part_cb) }, 206 {"View/Goto/PrevPart", NULL, N_("Previous part"), "Z", NULL, G_CALLBACK(goto_prev_part_cb) }, 207 208 {"View/Encoding", NULL, N_("Character _encoding"), NULL, NULL, NULL }, /* set_charset_cb */ 209 {"View/Encoding/---", NULL, "---", NULL, NULL, NULL }, 210 #define ENC_ACTION(cs_char,c_char,string) \ 211 { "View/Encoding/" cs_char, NULL, N_(string), NULL, NULL, c_char } 212 213 {"View/Encoding/Western", NULL, N_("Western European"), NULL, NULL, NULL }, 214 {"View/Encoding/Baltic", NULL, N_("Baltic"), NULL, NULL, NULL }, 215 {"View/Encoding/Hebrew", NULL, N_("Hebrew"), NULL, NULL, NULL }, 216 {"View/Encoding/Arabic", NULL, N_("Arabic"), NULL, NULL, NULL }, 217 {"View/Encoding/Cyrillic", NULL, N_("Cyrillic"), NULL, NULL, NULL }, 218 {"View/Encoding/Japanese", NULL, N_("Japanese"), NULL, NULL, NULL }, 219 {"View/Encoding/Chinese", NULL, N_("Chinese"), NULL, NULL, NULL }, 220 {"View/Encoding/Korean", NULL, N_("Korean"), NULL, NULL, NULL }, 221 {"View/Encoding/Thai", NULL, N_("Thai"), NULL, NULL, NULL }, 222 223 {"View/Decode", NULL, N_("Decode"), NULL, NULL, NULL }, /* set_decode_cb */ 224 {"View/Decode/---", NULL, "---", NULL, NULL, NULL }, 225 226 #define DEC_ACTION(cs_type,c_type,string) \ 227 { "View/Decode/" cs_type, NULL, N_(string), NULL, NULL, c_type } 228 229 {"View/---", NULL, "---", NULL, NULL, NULL }, 230 {"View/MessageSource", NULL, N_("Mess_age source"), "<control>U", NULL, G_CALLBACK(view_source_cb) }, 231 {"View/Part", NULL, N_("Message part"), NULL, NULL, NULL }, 232 {"View/Part/AsText", NULL, N_("View as text"), "T", NULL, G_CALLBACK(view_part_as_text_cb) }, 233 {"View/Part/Open", NULL, N_("Open"), "L", NULL, G_CALLBACK(open_part_cb) }, 234 {"View/Part/OpenWith", NULL, N_("Open with..."), "O", NULL, G_CALLBACK(open_part_with_cb) }, 235 236 {"View/Quotes", NULL, N_("Quotes"), NULL, NULL, NULL }, 237 238 /* Message menu */ 239 {"Message/Compose", NULL, N_("Write _new message"), "<control>M", NULL, G_CALLBACK(compose_cb) }, 240 {"Message/---", NULL, "---", NULL, NULL, NULL }, 241 242 {"Message/Reply", NULL, N_("_Reply"), "<control>R", NULL, G_CALLBACK(reply_cb) }, /* COMPOSE_REPLY */ 243 {"Message/ReplyTo", NULL, N_("Repl_y to"), NULL, NULL, NULL }, 244 {"Message/ReplyTo/All", NULL, N_("_All"), "<control><shift>R", NULL, G_CALLBACK(reply_cb) }, /* COMPOSE_REPLY_TO_ALL */ 245 {"Message/ReplyTo/Sender", NULL, N_("_Sender"), NULL, NULL, G_CALLBACK(reply_cb) }, /* COMPOSE_REPLY_TO_SENDER */ 246 {"Message/ReplyTo/List", NULL, N_("Mailing _list"), "<control>L", NULL, G_CALLBACK(reply_cb) }, /* COMPOSE_REPLY_TO_LIST */ 247 /* {"Message/---", NULL, "---", NULL, NULL, NULL }, */ 248 249 {"Message/Forward", NULL, N_("_Forward"), "<control><alt>F", NULL, G_CALLBACK(reply_cb) }, /* COMPOSE_FORWARD_INLINE */ 250 {"Message/ForwardAtt", NULL, N_("For_ward as attachment"), NULL, NULL, G_CALLBACK(reply_cb) }, /* COMPOSE_FORWARD_AS_ATTACH */ 251 {"Message/Redirect", NULL, N_("Redirec_t"), NULL, NULL, G_CALLBACK(reply_cb) }, /* COMPOSE_REDIRECT */ 252 253 /* Tools menu */ 254 {"Tools/AddressBook", NULL, N_("_Address book"), "<control><shift>A", NULL, G_CALLBACK(addressbook_open_cb) }, 255 {"Tools/AddSenderToAB", NULL, N_("Add sender to address boo_k"), NULL, NULL, G_CALLBACK(add_address_cb) }, 256 {"Tools/---", NULL, "---", NULL, NULL, NULL }, 257 258 /* {"Tools/---", NULL, "---", NULL, NULL, NULL }, */ 259 {"Tools/Actions", NULL, N_("Actio_ns"), NULL, NULL, NULL }, 260 {"Tools/Actions/PlaceHolder", NULL, "Placeholder", NULL, NULL, G_CALLBACK(messageview_nothing_cb) }, 261 }; 262 263 static GtkToggleActionEntry msgview_toggle_entries[] = 264 { 265 {"View/AllHeaders", NULL, N_("Show all _headers"), "<control>H", NULL, G_CALLBACK(show_all_header_cb), FALSE }, /* toggle */ 266 {"View/Quotes/CollapseAll", NULL, N_("_Collapse all"), "<control><shift>Q", NULL, G_CALLBACK(msg_hide_quotes_cb), FALSE }, /* 1 toggle */ 267 {"View/Quotes/Collapse2", NULL, N_("Collapse from level _2"), NULL, NULL, G_CALLBACK(msg_hide_quotes_cb), FALSE }, /* 2 toggle */ 268 {"View/Quotes/Collapse3", NULL, N_("Collapse from level _3"), NULL, NULL, G_CALLBACK(msg_hide_quotes_cb), FALSE }, /* 3 toggle */ 269 }; 270 271 static GtkRadioActionEntry msgview_radio_enc_entries[] = 272 { 273 ENC_ACTION(CS_AUTO, C_AUTO, N_("_Automatic")), /* RADIO set_charset_cb */ 274 ENC_ACTION(CS_US_ASCII, C_US_ASCII, N_("7bit ASCII (US-ASC_II)")), /* RADIO set_charset_cb */ 275 ENC_ACTION(CS_UTF_8, C_UTF_8, N_("Unicode (_UTF-8)")), /* RADIO set_charset_cb */ 276 ENC_ACTION("Western/"CS_ISO_8859_1, C_ISO_8859_1, "ISO-8859-_1"), /* RADIO set_charset_cb */ 277 ENC_ACTION("Western/"CS_ISO_8859_15, C_ISO_8859_15, "ISO-8859-15"), /* RADIO set_charset_cb */ 278 ENC_ACTION("Western/"CS_WINDOWS_1252, C_WINDOWS_1252, "Windows-1252"), /* RADIO set_charset_cb */ 279 ENC_ACTION(CS_ISO_8859_2, C_ISO_8859_2, N_("Central European (ISO-8859-_2)")), /* RADIO set_charset_cb */ 280 ENC_ACTION("Baltic/"CS_ISO_8859_13, C_ISO_8859_13, "ISO-8859-13"), /* RADIO set_charset_cb */ 281 ENC_ACTION("Baltic/"CS_ISO_8859_4, C_ISO_8859_14, "ISO-8859-_4"), /* RADIO set_charset_cb */ 282 ENC_ACTION(CS_ISO_8859_7, C_ISO_8859_7, N_("Greek (ISO-8859-_7)")), /* RADIO set_charset_cb */ 283 ENC_ACTION("Hebrew/"CS_ISO_8859_8, C_ISO_8859_8, "ISO-8859-_8"), /* RADIO set_charset_cb */ 284 ENC_ACTION("Hebrew/"CS_WINDOWS_1255, C_WINDOWS_1255, "Windows-1255"), /* RADIO set_charset_cb */ 285 ENC_ACTION("Arabic/"CS_ISO_8859_6, C_ISO_8859_6, "ISO-8859-_6"), /* RADIO set_charset_cb */ 286 ENC_ACTION("Arabic/"CS_WINDOWS_1256, C_WINDOWS_1256, "Windows-1256"), /* RADIO set_charset_cb */ 287 ENC_ACTION(CS_ISO_8859_9, C_ISO_8859_9, N_("Turkish (ISO-8859-_9)")), /* RADIO set_charset_cb */ 288 ENC_ACTION("Cyrillic/"CS_ISO_8859_5, C_ISO_8859_5, "ISO-8859-_5"), /* RADIO set_charset_cb */ 289 ENC_ACTION("Cyrillic/"CS_KOI8_R, C_KOI8_R, "KOI8-_R"), /* RADIO set_charset_cb */ 290 ENC_ACTION("Cyrillic/"CS_MACCYR, C_MACCYR, "MAC_CYR"), /* RADIO set_charset_cb */ 291 ENC_ACTION("Cyrillic/"CS_KOI8_U, C_KOI8_U, "KOI8-_U"), /* RADIO set_charset_cb */ 292 ENC_ACTION("Cyrillic/"CS_WINDOWS_1251, C_WINDOWS_1251, "Windows-1251"), /* RADIO set_charset_cb */ 293 ENC_ACTION("Japanese/"CS_ISO_2022_JP, C_ISO_2022_JP, "ISO-2022-_JP"), /* RADIO set_charset_cb */ 294 ENC_ACTION("Japanese/"CS_ISO_2022_JP_2, C_ISO_2022_JP_2, "ISO-2022-JP-_2"), /* RADIO set_charset_cb */ 295 ENC_ACTION("Japanese/"CS_EUC_JP, C_EUC_JP, "_EUC-JP"), /* RADIO set_charset_cb */ 296 ENC_ACTION("Japanese/"CS_SHIFT_JIS, C_SHIFT_JIS, "_Shift-JIS"), /* RADIO set_charset_cb */ 297 ENC_ACTION("Chinese/"CS_GB18030, C_GB18030, "_GB18030"), /* RADIO set_charset_cb */ 298 ENC_ACTION("Chinese/"CS_GB2312, C_GB2312, "_GB2312"), /* RADIO set_charset_cb */ 299 ENC_ACTION("Chinese/"CS_GBK, C_GBK, "GB_K"), /* RADIO set_charset_cb */ 300 ENC_ACTION("Chinese/"CS_BIG5, C_BIG5, "_Big5-JP"), /* RADIO set_charset_cb */ 301 ENC_ACTION("Chinese/"CS_EUC_TW, C_EUC_TW, "EUC-_TW"), /* RADIO set_charset_cb */ 302 ENC_ACTION("Korean/"CS_EUC_KR, C_EUC_KR, "_EUC-KR"), /* RADIO set_charset_cb */ 303 ENC_ACTION("Korean/"CS_ISO_2022_KR, C_ISO_2022_KR, "_ISO-2022-KR"), /* RADIO set_charset_cb */ 304 ENC_ACTION("Thai/"CS_TIS_620, C_TIS_620, "_TIS-620-KR"), /* RADIO set_charset_cb */ 305 ENC_ACTION("Thai/"CS_WINDOWS_874, C_WINDOWS_874, "_Windows-874"), /* RADIO set_charset_cb */ 306 }; 307 308 static GtkRadioActionEntry msgview_radio_dec_entries[] = 309 { 310 DEC_ACTION("AutoDetect", 0, N_("_Auto detect")), /* set_decode_cb */ 311 /* --- */ 312 DEC_ACTION("8bit", ENC_8BIT, "_8bit"), 313 DEC_ACTION("QP", ENC_QUOTED_PRINTABLE, "_Quoted printable"), 314 DEC_ACTION("B64", ENC_BASE64, "_Base64"), 315 DEC_ACTION("Uuencode", ENC_X_UUENCODE, "_Uuencode"), 316 }; 317 318 MessageView *messageview_create(MainWindow *mainwin) 319 { 320 MessageView *messageview = g_new0(MessageView, 1); 321 322 MimeView *mimeview = mimeview_create(mainwin); 323 mimeview->textview = textview_create(); 324 mimeview->textview->messageview = messageview; 325 mimeview->messageview = messageview; 326 327 GtkWidget *vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); 328 gtk_widget_set_name(GTK_WIDGET(vbox), "messageview"); 329 gtk_box_pack_start(GTK_BOX(vbox), 330 GTK_WIDGET_PTR(mimeview), TRUE, TRUE, 0); 331 gtk_widget_show(vbox); 332 333 messageview->vbox = vbox; 334 messageview->new_window = FALSE; 335 messageview->window = NULL; 336 messageview->mimeview = mimeview; 337 messageview->mainwin = mainwin; 338 339 messageview->statusbar = NULL; 340 messageview->statusbar_cid = 0; 341 342 messageview->show_full_text= FALSE; 343 messageview->update_needed = FALSE; 344 345 messageview->msginfo_update_callback_id = 346 hooks_register_hook(MSGINFO_UPDATE_HOOKLIST, messageview_update_msg, (gpointer) messageview); 347 348 return messageview; 349 } 350 351 const GList *messageview_get_msgview_list(void) 352 { 353 return msgview_list; 354 } 355 356 void messageview_update_actions_menu(MessageView *msgview) 357 { 358 /* Messages opened in a new window do not have a menu bar */ 359 if (msgview->menubar == NULL) 360 return; 361 action_update_msgview_menu(msgview->ui_manager, "/Menu/Tools/Actions", msgview); 362 } 363 364 static void messageview_add_toolbar(MessageView *msgview, GtkWidget *window) 365 { 366 GtkWidget *handlebox; 367 GtkWidget *vbox; 368 GtkWidget *menubar; 369 GtkWidget *statusbar = NULL; 370 GtkActionGroup *action_group; 371 372 vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); 373 gtk_widget_show(vbox); 374 gtk_container_add(GTK_CONTAINER(window), vbox); 375 376 msgview->ui_manager = gtk_ui_manager_new(); 377 action_group = cm_menu_create_action_group_full(msgview->ui_manager,"Menu", msgview_entries, 378 G_N_ELEMENTS(msgview_entries), (gpointer)msgview); 379 gtk_action_group_add_toggle_actions(action_group, msgview_toggle_entries, 380 G_N_ELEMENTS(msgview_toggle_entries), (gpointer)msgview); 381 gtk_action_group_add_radio_actions(action_group, msgview_radio_enc_entries, 382 G_N_ELEMENTS(msgview_radio_enc_entries), C_AUTO, G_CALLBACK(set_charset_cb), (gpointer)msgview); 383 gtk_action_group_add_radio_actions(action_group, msgview_radio_dec_entries, 384 G_N_ELEMENTS(msgview_radio_dec_entries), C_AUTO, G_CALLBACK(set_decode_cb), (gpointer)msgview); 385 386 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/", "Menu", NULL, GTK_UI_MANAGER_MENUBAR) 387 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu", "File", "File", GTK_UI_MANAGER_MENU) 388 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu", "Edit", "Edit", GTK_UI_MANAGER_MENU) 389 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu", "View", "View", GTK_UI_MANAGER_MENU) 390 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu", "Message", "Message", GTK_UI_MANAGER_MENU) 391 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu", "Tools", "Tools", GTK_UI_MANAGER_MENU) 392 393 /* File menu */ 394 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/File", "SaveAs", "File/SaveAs", GTK_UI_MANAGER_MENUITEM) 395 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/File", "SavePartAs", "File/SavePartAs", GTK_UI_MANAGER_MENUITEM) 396 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/File", "Separator1", "File/---", GTK_UI_MANAGER_SEPARATOR) 397 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/File", "Separator2", "File/---", GTK_UI_MANAGER_SEPARATOR) 398 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/File", "Close", "File/Close", GTK_UI_MANAGER_MENUITEM) 399 400 /* Edit menu */ 401 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/Edit", "Copy", "Edit/Copy", GTK_UI_MANAGER_MENUITEM) 402 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/Edit", "SelectAll", "Edit/SelectAll", GTK_UI_MANAGER_MENUITEM) 403 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/Edit", "Separator1", "Edit/---", GTK_UI_MANAGER_SEPARATOR) 404 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/Edit", "Find", "Edit/Find", GTK_UI_MANAGER_MENUITEM) 405 406 /* View menu */ 407 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View", "Goto", "View/Goto", GTK_UI_MANAGER_MENU) 408 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Goto", "Prev", "View/Goto/Prev", GTK_UI_MANAGER_MENUITEM) 409 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Goto", "Next", "View/Goto/Next", GTK_UI_MANAGER_MENUITEM) 410 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Goto", "Separator1", "View/Goto/---", GTK_UI_MANAGER_SEPARATOR) 411 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Goto", "PrevUnread", "View/Goto/PrevUnread", GTK_UI_MANAGER_MENUITEM) 412 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Goto", "NextUnread", "View/Goto/NextUnread", GTK_UI_MANAGER_MENUITEM) 413 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Goto", "Separator2", "View/Goto/---", GTK_UI_MANAGER_SEPARATOR) 414 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Goto", "PrevNew", "View/Goto/PrevNew", GTK_UI_MANAGER_MENUITEM) 415 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Goto", "NextNew", "View/Goto/NextNew", GTK_UI_MANAGER_MENUITEM) 416 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Goto", "Separator3", "View/Goto/---", GTK_UI_MANAGER_SEPARATOR) 417 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Goto", "PrevMarked", "View/Goto/PrevMarked", GTK_UI_MANAGER_MENUITEM) 418 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Goto", "NextMarked", "View/Goto/NextMarked", GTK_UI_MANAGER_MENUITEM) 419 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Goto", "Separator4", "View/Goto/---", GTK_UI_MANAGER_SEPARATOR) 420 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Goto", "PrevLabeled", "View/Goto/PrevLabeled", GTK_UI_MANAGER_MENUITEM) 421 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Goto", "NextLabeled", "View/Goto/NextLabeled", GTK_UI_MANAGER_MENUITEM) 422 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Goto", "Separator5", "View/Goto/---", GTK_UI_MANAGER_SEPARATOR) 423 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Goto", "PrevHistory", "View/Goto/PrevHistory", GTK_UI_MANAGER_MENUITEM) 424 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Goto", "NextHistory", "View/Goto/NextHistory", GTK_UI_MANAGER_MENUITEM) 425 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Goto", "Separator6", "View/Goto/---", GTK_UI_MANAGER_SEPARATOR) 426 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Goto", "ParentMessage", "View/Goto/ParentMessage", GTK_UI_MANAGER_MENUITEM) 427 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Goto", "Separator7", "View/Goto/---", GTK_UI_MANAGER_SEPARATOR) 428 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Goto", "NextUnreadFolder", "View/Goto/NextUnreadFolder", GTK_UI_MANAGER_MENUITEM) 429 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Goto", "Folder", "View/Goto/Folder", GTK_UI_MANAGER_MENUITEM) 430 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Goto", "Separator8", "View/Goto/---", GTK_UI_MANAGER_SEPARATOR) 431 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Goto", "NextPart", "View/Goto/NextPart", GTK_UI_MANAGER_MENUITEM) 432 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Goto", "PrevPart", "View/Goto/PrevPart", GTK_UI_MANAGER_MENUITEM) 433 434 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View", "Separator1", "View/---", GTK_UI_MANAGER_SEPARATOR) 435 436 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View", "Encoding", "View/Encoding", GTK_UI_MANAGER_MENU) 437 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Encoding", CS_AUTO, "View/Encoding/"CS_AUTO, GTK_UI_MANAGER_MENUITEM) 438 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Encoding", "Separator1", "View/Encoding/---", GTK_UI_MANAGER_SEPARATOR) 439 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Encoding", CS_US_ASCII, "View/Encoding/"CS_US_ASCII, GTK_UI_MANAGER_MENUITEM) 440 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Encoding", CS_UTF_8, "View/Encoding/"CS_UTF_8, GTK_UI_MANAGER_MENUITEM) 441 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Encoding", "Separator2", "View/Encoding/---", GTK_UI_MANAGER_SEPARATOR) 442 443 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Encoding", "Western", "View/Encoding/Western", GTK_UI_MANAGER_MENU) 444 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) 445 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) 446 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Encoding/Western", CS_WINDOWS_1252, "View/Encoding/Western/"CS_WINDOWS_1252, GTK_UI_MANAGER_MENUITEM) 447 448 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Encoding", CS_ISO_8859_2, "View/Encoding/"CS_ISO_8859_2, GTK_UI_MANAGER_MENUITEM) 449 450 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Encoding", "Baltic", "View/Encoding/Baltic", GTK_UI_MANAGER_MENU) 451 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) 452 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) 453 454 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Encoding", CS_ISO_8859_7, "View/Encoding/"CS_ISO_8859_7, GTK_UI_MANAGER_MENUITEM) 455 456 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Encoding", "Hebrew", "View/Encoding/Hebrew", GTK_UI_MANAGER_MENU) 457 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) 458 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Encoding/Hebrew", CS_WINDOWS_1255, "View/Encoding/Hebrew/"CS_WINDOWS_1255, GTK_UI_MANAGER_MENUITEM) 459 460 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Encoding", "Arabic", "View/Encoding/Arabic", GTK_UI_MANAGER_MENU) 461 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) 462 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Encoding/Arabic", CS_WINDOWS_1256, "View/Encoding/Arabic/"CS_WINDOWS_1256, GTK_UI_MANAGER_MENUITEM) 463 464 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Encoding", CS_ISO_8859_9, "View/Encoding/"CS_ISO_8859_9, GTK_UI_MANAGER_MENUITEM) 465 466 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Encoding", "Cyrillic", "View/Encoding/Cyrillic", GTK_UI_MANAGER_MENU) 467 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) 468 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Encoding/Cyrillic", CS_KOI8_R, "View/Encoding/Cyrillic/"CS_KOI8_R, GTK_UI_MANAGER_MENUITEM) 469 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Encoding/Cyrillic", CS_MACCYR, "View/Encoding/Cyrillic/"CS_MACCYR, GTK_UI_MANAGER_MENUITEM) 470 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Encoding/Cyrillic", CS_KOI8_U, "View/Encoding/Cyrillic/"CS_KOI8_U, GTK_UI_MANAGER_MENUITEM) 471 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Encoding/Cyrillic", CS_WINDOWS_1251, "View/Encoding/Cyrillic/"CS_WINDOWS_1251, GTK_UI_MANAGER_MENUITEM) 472 473 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Encoding", "Japanese", "View/Encoding/Japanese", GTK_UI_MANAGER_MENU) 474 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) 475 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) 476 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Encoding/Japanese", CS_EUC_JP, "View/Encoding/Japanese/"CS_EUC_JP, GTK_UI_MANAGER_MENUITEM) 477 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Encoding/Japanese", CS_SHIFT_JIS, "View/Encoding/Japanese/"CS_SHIFT_JIS, GTK_UI_MANAGER_MENUITEM) 478 479 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Encoding", "Chinese", "View/Encoding/Chinese", GTK_UI_MANAGER_MENU) 480 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Encoding/Chinese", CS_GB18030, "View/Encoding/Chinese/"CS_GB18030, GTK_UI_MANAGER_MENUITEM) 481 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Encoding/Chinese", CS_GB2312, "View/Encoding/Chinese/"CS_GB2312, GTK_UI_MANAGER_MENUITEM) 482 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Encoding/Chinese", CS_GBK, "View/Encoding/Chinese/"CS_GBK, GTK_UI_MANAGER_MENUITEM) 483 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Encoding/Chinese", CS_BIG5, "View/Encoding/Chinese/"CS_BIG5, GTK_UI_MANAGER_MENUITEM) 484 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Encoding/Chinese", CS_EUC_TW, "View/Encoding/Chinese/"CS_EUC_TW, GTK_UI_MANAGER_MENUITEM) 485 486 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Encoding", "Korean", "View/Encoding/Korean", GTK_UI_MANAGER_MENU) 487 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Encoding/Korean", CS_EUC_KR, "View/Encoding/Korean/"CS_EUC_KR, GTK_UI_MANAGER_MENUITEM) 488 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) 489 490 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Encoding", "Thai", "View/Encoding/Thai", GTK_UI_MANAGER_MENU) 491 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Encoding/Thai", CS_TIS_620, "View/Encoding/Thai/"CS_TIS_620, GTK_UI_MANAGER_MENUITEM) 492 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Encoding/Thai", CS_WINDOWS_874, "View/Encoding/Thai/"CS_WINDOWS_874, GTK_UI_MANAGER_MENUITEM) 493 494 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View", "Decode", "View/Decode", GTK_UI_MANAGER_MENU) 495 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Decode", "AutoDetect", "View/Decode/AutoDetect", GTK_UI_MANAGER_MENUITEM) 496 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Decode", "Separator1", "View/Decode/---", GTK_UI_MANAGER_SEPARATOR) 497 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Decode", "8bit", "View/Decode/8bit", GTK_UI_MANAGER_MENUITEM) 498 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Decode", "QP", "View/Decode/QP", GTK_UI_MANAGER_MENUITEM) 499 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Decode", "B64", "View/Decode/B64", GTK_UI_MANAGER_MENUITEM) 500 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Decode", "Uuencode", "View/Decode/Uuencode", GTK_UI_MANAGER_MENUITEM) 501 502 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View", "Separator2", "View/---", GTK_UI_MANAGER_SEPARATOR) 503 504 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View", "MessageSource", "View/MessageSource", GTK_UI_MANAGER_MENUITEM) 505 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View", "AllHeaders", "View/AllHeaders", GTK_UI_MANAGER_MENUITEM) 506 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View", "Quotes", "View/Quotes", GTK_UI_MANAGER_MENU) 507 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Quotes", "CollapseAll", "View/Quotes/CollapseAll", GTK_UI_MANAGER_MENUITEM) 508 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Quotes", "Collapse2", "View/Quotes/Collapse2", GTK_UI_MANAGER_MENUITEM) 509 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Quotes", "Collapse3", "View/Quotes/Collapse3", GTK_UI_MANAGER_MENUITEM) 510 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View", "Part", "View/Part", GTK_UI_MANAGER_MENU) 511 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Part", "AsText", "View/Part/AsText", GTK_UI_MANAGER_MENUITEM) 512 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Part", "Open", "View/Part/Open", GTK_UI_MANAGER_MENUITEM) 513 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/View/Part", "OpenWith", "View/Part/OpenWith", GTK_UI_MANAGER_MENUITEM) 514 515 /* Message menu */ 516 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/Message", "Compose", "Message/Compose", GTK_UI_MANAGER_MENUITEM) 517 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/Message", "Separator1", "Message/---", GTK_UI_MANAGER_SEPARATOR) 518 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/Message", "Reply", "Message/Reply", GTK_UI_MANAGER_MENUITEM) 519 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/Message", "ReplyTo", "Message/ReplyTo", GTK_UI_MANAGER_MENU) 520 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/Message/ReplyTo", "All", "Message/ReplyTo/All", GTK_UI_MANAGER_MENUITEM) 521 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/Message/ReplyTo", "Sender", "Message/ReplyTo/Sender", GTK_UI_MANAGER_MENUITEM) 522 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/Message/ReplyTo", "List", "Message/ReplyTo/List", GTK_UI_MANAGER_MENUITEM) 523 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/Message", "Separator2", "Message/---", GTK_UI_MANAGER_SEPARATOR) 524 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/Message", "Forward", "Message/Forward", GTK_UI_MANAGER_MENUITEM) 525 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/Message", "ForwardAtt", "Message/ForwardAtt", GTK_UI_MANAGER_MENUITEM) 526 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/Message", "Redirect", "Message/Redirect", GTK_UI_MANAGER_MENUITEM) 527 528 /* Tools menu */ 529 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/Tools", "AddressBook", "Tools/AddressBook", GTK_UI_MANAGER_MENUITEM) 530 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/Tools", "AddSenderToAB", "Tools/AddSenderToAB", GTK_UI_MANAGER_MENUITEM) 531 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/Tools", "Separator1", "Tools/---", GTK_UI_MANAGER_SEPARATOR) 532 533 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/Tools", "Separator2", "Tools/---", GTK_UI_MANAGER_SEPARATOR) 534 535 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/Tools", "Actions", "Tools/Actions", GTK_UI_MANAGER_MENU) 536 MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/Tools/Actions", "PlaceHolder", "Tools/Actions/PlaceHolder", GTK_UI_MANAGER_MENUITEM) 537 538 menubar = gtk_ui_manager_get_widget(msgview->ui_manager, "/Menu"); 539 gtk_widget_show_all(menubar); 540 gtk_window_add_accel_group(GTK_WINDOW(window), gtk_ui_manager_get_accel_group(msgview->ui_manager)); 541 542 gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, TRUE, 0); 543 544 cm_toggle_menu_set_active_full(msgview->ui_manager, "Menu/View/AllHeaders", 545 prefs_common.show_all_headers); 546 547 handlebox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); 548 gtk_box_pack_start(GTK_BOX(vbox), handlebox, FALSE, FALSE, 0); 549 gtk_widget_realize(handlebox); 550 msgview->toolbar = toolbar_create(TOOLBAR_MSGVIEW, handlebox, 551 (gpointer)msgview); 552 statusbar = gtk_statusbar_new(); 553 gtk_widget_show(statusbar); 554 gtk_box_pack_end(GTK_BOX(vbox), statusbar, FALSE, FALSE, 0); 555 msgview->statusbar = statusbar; 556 msgview->statusbar_cid = gtk_statusbar_get_context_id 557 (GTK_STATUSBAR(statusbar), "Message View"); 558 559 560 msgview->handlebox = handlebox; 561 msgview->menubar = menubar; 562 563 gtk_container_add(GTK_CONTAINER(vbox), 564 GTK_WIDGET_PTR(msgview)); 565 566 messageview_update_actions_menu(msgview); 567 568 msgview_list = g_list_append(msgview_list, msgview); 569 } 570 571 static MessageView *messageview_create_with_new_window_visible(MainWindow *mainwin, gboolean show) 572 { 573 MessageView *msgview; 574 GtkWidget *window; 575 static GdkGeometry geometry; 576 577 window = gtkut_window_new(GTK_WINDOW_TOPLEVEL, "messageview"); 578 gtk_window_set_title(GTK_WINDOW(window), _("Claws Mail - Message View")); 579 gtk_window_set_resizable(GTK_WINDOW(window), TRUE); 580 581 gtk_window_set_default_size(GTK_WINDOW(window), prefs_common.msgwin_width, 582 prefs_common.msgwin_height); 583 584 if (!geometry.min_height) { 585 geometry.min_width = 320; 586 geometry.min_height = 200; 587 } 588 gtk_window_set_geometry_hints(GTK_WINDOW(window), NULL, &geometry, 589 GDK_HINT_MIN_SIZE); 590 591 msgview = messageview_create(mainwin); 592 593 g_signal_connect(G_OBJECT(window), "size_allocate", 594 G_CALLBACK(messageview_size_allocate_cb), 595 msgview); 596 g_signal_connect(G_OBJECT(window), "delete_event", 597 G_CALLBACK(messageview_delete_cb), msgview); 598 g_signal_connect(G_OBJECT(window), "key_press_event", 599 G_CALLBACK(key_pressed), msgview); 600 messageview_add_toolbar(msgview, window); 601 602 if (show) { 603 gtk_widget_show(window); 604 } else { 605 gtk_widget_realize(window); 606 } 607 608 msgview->new_window = TRUE; 609 msgview->window = window; 610 msgview->visible = TRUE; 611 612 toolbar_set_style(msgview->toolbar->toolbar, msgview->handlebox, 613 prefs_common.toolbar_style); 614 messageview_init(msgview); 615 616 if (show) { 617 GTK_EVENTS_FLUSH(); 618 gtk_widget_grab_focus(msgview->mimeview->textview->text); 619 } 620 621 return msgview; 622 } 623 624 MessageView *messageview_create_with_new_window(MainWindow *mainwin) 625 { 626 return messageview_create_with_new_window_visible(mainwin, TRUE); 627 } 628 void messageview_init(MessageView *messageview) 629 { 630 mimeview_init(messageview->mimeview); 631 } 632 633 static gboolean find_broken_func(GNode *node, gpointer data) 634 { 635 MimeInfo *mimeinfo = (MimeInfo *) node->data; 636 MimeInfo **brokeninfo = (MimeInfo **) data; 637 638 if (mimeinfo->broken) { 639 *brokeninfo = mimeinfo; 640 return TRUE; 641 } 642 643 return FALSE; 644 } 645 646 static MimeInfo *find_broken_part(MimeInfo *rootinfo) 647 { 648 MimeInfo *brokeninfo = NULL; 649 650 g_node_traverse(rootinfo->node, G_IN_ORDER, G_TRAVERSE_ALL, -1, 651 find_broken_func, &brokeninfo); 652 653 return brokeninfo; 654 } 655 656 static void messageview_register_nav(MessageView *messageview) 657 { 658 gchar *id; 659 gint pos = -1; 660 GList *existing; 661 662 cm_return_if_fail(messageview); 663 cm_return_if_fail(messageview->msginfo); 664 665 id = procmsg_msginfo_get_identifier(messageview->msginfo); 666 existing = g_list_find_custom(messageview->trail, id, (GCompareFunc)g_strcmp0); 667 668 if (existing != NULL) 669 pos = g_list_position(messageview->trail, existing); 670 else 671 pos = -1; 672 673 if (pos != -1) { 674 messageview->trail_pos = pos; 675 g_free(id); 676 } else { 677 /* Cut the end of the list */ 678 GList *end = g_list_nth(messageview->trail, messageview->trail_pos + 1); 679 if (end) { 680 if (end->prev) { 681 end->prev->next = NULL; 682 end->prev = NULL; 683 list_free_strings_full(end); 684 } else { 685 list_free_strings_full(messageview->trail); 686 messageview->trail = NULL; 687 } 688 } 689 messageview->trail = g_list_append(messageview->trail, id); 690 messageview->trail_pos = (gint)g_list_length(messageview->trail) - 1; 691 692 /* Cut the beginning if needed */ 693 while (messageview->trail_pos > prefs_common.nav_history_length) { 694 g_free(messageview->trail->data); 695 messageview->trail = g_list_delete_link(messageview->trail, 696 messageview->trail); 697 messageview->trail_pos--; 698 } 699 } 700 messageview_set_menu_sensitive(messageview); 701 } 702 703 gboolean messageview_nav_has_prev(MessageView *messageview) { 704 return messageview != NULL && messageview->trail != NULL 705 && messageview->trail_pos > 0; 706 } 707 708 gboolean messageview_nav_has_next(MessageView *messageview) { 709 if (!messageview || !messageview->trail) 710 return FALSE; 711 712 return sc_g_list_bigger(messageview->trail, messageview->trail_pos + 1); 713 } 714 715 MsgInfo *messageview_nav_get_prev(MessageView *messageview) { 716 GList *item; 717 MsgInfo *info; 718 719 cm_return_val_if_fail(messageview, NULL); 720 cm_return_val_if_fail(messageview->trail, NULL); 721 722 do { 723 if (!messageview_nav_has_prev(messageview)) 724 return NULL; 725 726 item = g_list_nth(messageview->trail, messageview->trail_pos - 1); 727 cm_return_val_if_fail(item != NULL, NULL); 728 729 info = procmsg_get_msginfo_from_identifier((const gchar *)item->data); 730 if (info != NULL) 731 break; 732 733 g_free(item->data); 734 messageview->trail = g_list_delete_link(messageview->trail, item); 735 if (messageview->trail_pos > 0) 736 messageview->trail_pos--; 737 } while (info == NULL); 738 739 return info; 740 } 741 742 MsgInfo *messageview_nav_get_next(MessageView *messageview) { 743 GList *item; 744 MsgInfo *info; 745 746 cm_return_val_if_fail(messageview, NULL); 747 cm_return_val_if_fail(messageview->trail, NULL); 748 749 do { 750 if (!messageview_nav_has_next(messageview)) 751 return NULL; 752 753 item = g_list_nth(messageview->trail, messageview->trail_pos + 1); 754 cm_return_val_if_fail(item != NULL, NULL); 755 756 info = procmsg_get_msginfo_from_identifier((const gchar *)item->data); 757 if (info != NULL) 758 break; 759 760 g_free(item->data); 761 messageview->trail = g_list_delete_link(messageview->trail, item); 762 } while (info == NULL); 763 764 return info; 765 } 766 767 static gboolean messageview_try_select_mimeinfo(MessageView *messageview, MsgInfo *msginfo, MimeInfo *mimeinfo) 768 { 769 if (mimeinfo->type == MIMETYPE_TEXT) { 770 if (!strcasecmp(mimeinfo->subtype, "calendar") 771 && mimeview_has_viewer_for_content_type(messageview->mimeview, "text/calendar")) { 772 mimeview_select_mimepart_icon(messageview->mimeview, mimeinfo); 773 return TRUE; 774 } 775 } 776 return FALSE; 777 } 778 779 static void messageview_find_part_depth_first(MimeInfoSearch *context, MimeMediaType type, const gchar *subtype) 780 { 781 MimeInfo * mimeinfo = context->current; 782 783 if (!mimeinfo) 784 return; 785 786 debug_print("found part %d/%s\n", mimeinfo->type, mimeinfo->subtype); 787 788 if (mimeinfo->type == type 789 && !strcasecmp(mimeinfo->subtype, subtype)) { 790 context->found = mimeinfo; 791 } else if (mimeinfo->type == MIMETYPE_MULTIPART) { 792 if (!strcasecmp(mimeinfo->subtype, "alternative") 793 || !strcasecmp(mimeinfo->subtype, "related")) { 794 context->found = procmime_mimeinfo_next(mimeinfo); 795 while (context->found && context->found != context->parent) { 796 if (context->found->type == type 797 && !strcasecmp(context->found->subtype, subtype)) 798 break; 799 context->found = procmime_mimeinfo_next(context->found); 800 } 801 if (context->found == context->parent) 802 context->found = NULL; 803 } 804 if (!context->found 805 && (!strcasecmp(mimeinfo->subtype, "related") 806 || !strcasecmp(mimeinfo->subtype, "mixed"))) { 807 context->parent = mimeinfo; 808 context->current = procmime_mimeinfo_next(mimeinfo); 809 messageview_find_part_depth_first(context, type, subtype); 810 } 811 } 812 } 813 814 gint messageview_show(MessageView *messageview, MsgInfo *msginfo, 815 gboolean all_headers) 816 { 817 gchar *file; 818 MimeInfo *mimeinfo, *root; 819 gchar *subject = NULL; 820 cm_return_val_if_fail(msginfo != NULL, -1); 821 822 if (msginfo != messageview->msginfo) 823 messageview->show_full_text = FALSE; 824 825 if (messageview->mimeview->textview && 826 messageview->mimeview->textview->loading) { 827 messageview->mimeview->textview->stop_loading = TRUE; 828 return 0; 829 } 830 831 mimeview_clear(messageview->mimeview); 832 messageview->updating = TRUE; 833 834 if (msginfo->size > 1024*1024) 835 statusbar_print_all(_("Fetching message (%s)..."), 836 to_human_readable(msginfo->size)); 837 838 file = procmsg_get_message_file_path(msginfo); 839 840 if (msginfo->size > 1024*1024) 841 statusbar_pop_all(); 842 843 if (!file) { 844 g_warning("can't get message file path"); 845 textview_show_error(messageview->mimeview->textview); 846 return -1; 847 } 848 849 if (!folder_has_parent_of_type(msginfo->folder, F_QUEUE) && 850 !folder_has_parent_of_type(msginfo->folder, F_DRAFT)) 851 mimeinfo = procmime_scan_file(file); 852 else 853 mimeinfo = procmime_scan_queue_file(file); 854 855 messageview->updating = FALSE; 856 857 if (messageview->deferred_destroy) { 858 g_free(file); 859 messageview_destroy(messageview); 860 return 0; 861 } 862 863 if (!mimeinfo) { 864 textview_show_error(messageview->mimeview->textview); 865 return -1; 866 } 867 868 if (messageview->msginfo != msginfo) { 869 procmsg_msginfo_free(&(messageview->msginfo)); 870 messageview->msginfo = NULL; 871 messageview_set_menu_sensitive(messageview); 872 messageview->msginfo = 873 procmsg_msginfo_get_full_info_from_file(msginfo, file); 874 if (!messageview->msginfo) 875 messageview->msginfo = procmsg_msginfo_copy(msginfo); 876 } else { 877 messageview->msginfo = NULL; 878 messageview_set_menu_sensitive(messageview); 879 messageview->msginfo = msginfo; 880 } 881 882 messageview_register_nav(messageview); 883 messageview_set_position(messageview, 0); 884 885 if (messageview->window) { 886 gtk_window_set_title(GTK_WINDOW(messageview->window), 887 _("Claws Mail - Message View")); 888 GTK_EVENTS_FLUSH(); 889 } 890 mimeview_show_message(messageview->mimeview, mimeinfo, file); 891 892 summary_open_msg(messageview->mainwin->summaryview, FALSE, TRUE); 893 894 messageview_set_position(messageview, 0); 895 896 if (messageview->window && msginfo->subject) { 897 subject = g_strdup(msginfo->subject); 898 if (!g_utf8_validate(subject, -1, NULL)) { 899 g_free(subject); 900 subject = g_malloc(strlen(msginfo->subject)*2 +1); 901 conv_localetodisp(subject, strlen(msginfo->subject)*2 +1, 902 msginfo->subject); 903 } 904 if (g_utf8_validate(subject, -1, NULL)) 905 gtk_window_set_title(GTK_WINDOW(messageview->window), 906 subject); 907 g_free(subject); 908 } 909 910 if (msginfo->folder) { 911 msginfo->folder->last_seen = msginfo->msgnum; 912 } 913 914 main_create_mailing_list_menu(messageview->mainwin, messageview->msginfo); 915 916 if (find_broken_part(mimeinfo) != NULL) { 917 GtkDialogFlags flag = GTK_DIALOG_DESTROY_WITH_PARENT; 918 GtkWidget *dialog = gtk_message_dialog_new(messageview->mainwin, flag, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "Broken MIME part"); 919 g_signal_connect_swapped(dialog, "response", G_CALLBACK(gtk_widget_destroy), dialog); 920 gtk_widget_show(dialog); 921 } 922 923 root = mimeinfo; 924 mimeinfo = procmime_mimeinfo_next(mimeinfo); 925 if (!all_headers && mimeinfo 926 && (mimeinfo->type != MIMETYPE_TEXT 927 || strcasecmp(mimeinfo->subtype, "plain")) 928 && (mimeinfo->type != MIMETYPE_MULTIPART 929 || strcasecmp(mimeinfo->subtype, "signed"))) { 930 if (strcasecmp(mimeinfo->subtype, "html")) { 931 MimeInfoSearch context = { 932 .parent = root, 933 .current = mimeinfo, 934 .found = NULL 935 }; 936 if (mimeview_has_viewer_for_content_type(messageview->mimeview, "text/calendar")) { 937 MimeInfoSearch cal_context = context; 938 messageview_find_part_depth_first(&cal_context, MIMETYPE_TEXT, "calendar"); 939 if (cal_context.found) { /* calendar found */ 940 mimeinfo = cal_context.found; 941 if (messageview_try_select_mimeinfo(messageview, msginfo, mimeinfo)) 942 goto done; 943 } 944 } 945 messageview_find_part_depth_first(&context, MIMETYPE_TEXT, "html"); 946 mimeinfo = root; 947 if (!mimeview_show_part(messageview->mimeview, mimeinfo)) 948 mimeview_select_mimepart_icon(messageview->mimeview, root); 949 goto done; 950 } 951 } 952 if (!all_headers && mimeinfo && 953 mimeinfo->type == MIMETYPE_MULTIPART && 954 mimeview_has_viewer_for_content_type(messageview->mimeview, "text/calendar")) { 955 /* look for a calendar part or it looks really strange */ 956 while (mimeinfo) { 957 if (mimeinfo->type == MIMETYPE_TEXT && 958 !strcasecmp(mimeinfo->subtype, "calendar")) { 959 mimeview_select_mimepart_icon(messageview->mimeview, mimeinfo); 960 goto done; 961 } 962 mimeinfo = procmime_mimeinfo_next(mimeinfo); 963 } 964 } 965 966 mimeview_select_mimepart_icon(messageview->mimeview, root); 967 done: 968 messageview_set_menu_sensitive(messageview); 969 g_free(file); 970 971 return 0; 972 } 973 974 void messageview_reflect_prefs_pixmap_theme(void) 975 { 976 GList *cur; 977 MessageView *msgview; 978 979 for (cur = msgview_list; cur != NULL; cur = cur->next) { 980 msgview = (MessageView*)cur->data; 981 toolbar_update(TOOLBAR_MSGVIEW, msgview); 982 mimeview_update(msgview->mimeview); 983 } 984 } 985 986 void messageview_clear(MessageView *messageview) 987 { 988 if (!messageview) 989 return; 990 procmsg_msginfo_free(&(messageview->msginfo)); 991 messageview->msginfo = NULL; 992 messageview->filtered = FALSE; 993 994 if (messageview->window) { 995 gtk_window_set_title(GTK_WINDOW(messageview->window), 996 _("Claws Mail - Message View")); 997 GTK_EVENTS_FLUSH(); 998 } 999 1000 mimeview_clear(messageview->mimeview); 1001 } 1002 1003 void messageview_destroy(MessageView *messageview) 1004 { 1005 debug_print("destroy messageview\n"); 1006 messageview_list = g_list_remove(messageview_list, messageview); 1007 1008 if (messageview->mainwin->summaryview->messageview == messageview) { 1009 messageview->mainwin->summaryview->displayed = NULL; 1010 messageview->mainwin->summaryview->messageview = NULL; 1011 } 1012 if (messageview->mainwin->summaryview->ext_messageview == messageview) { 1013 messageview->mainwin->summaryview->displayed = NULL; 1014 messageview->mainwin->summaryview->ext_messageview = NULL; 1015 } 1016 if (!messageview->deferred_destroy) 1017 hooks_unregister_hook(MSGINFO_UPDATE_HOOKLIST, 1018 messageview->msginfo_update_callback_id); 1019 1020 if (messageview->updating) { 1021 debug_print("uh oh, better not touch that now (fetching)\n"); 1022 messageview->deferred_destroy = TRUE; 1023 gtk_widget_hide(messageview->window); 1024 return; 1025 } 1026 1027 if (messageview->mimeview->textview 1028 && messageview->mimeview->textview->loading) { 1029 debug_print("uh oh, better not touch that now (loading text)\n"); 1030 messageview->deferred_destroy = TRUE; 1031 messageview->mimeview->textview->stop_loading = TRUE; 1032 gtk_widget_hide(messageview->window); 1033 return; 1034 } 1035 1036 mimeview_destroy(messageview->mimeview); 1037 1038 procmsg_msginfo_free(&(messageview->msginfo)); 1039 toolbar_clear_list(TOOLBAR_MSGVIEW); 1040 if (messageview->toolbar) { 1041 toolbar_destroy(messageview->toolbar); 1042 g_free(messageview->toolbar); 1043 } 1044 1045 message_search_close(messageview); 1046 1047 list_free_strings_full(messageview->trail); 1048 msgview_list = g_list_remove(msgview_list, messageview); 1049 1050 if (messageview->window) 1051 gtk_widget_destroy(messageview->window); 1052 g_free(messageview); 1053 } 1054 1055 void messageview_delete(MessageView *msgview) 1056 { 1057 MsgInfo *msginfo = NULL; 1058 FolderItem *trash = NULL; 1059 PrefsAccount *ac = NULL; 1060 1061 if (msgview->msginfo && msgview->mainwin && msgview->mainwin->summaryview) 1062 msginfo = summary_get_selected_msg(msgview->mainwin->summaryview); 1063 1064 /* need a procmsg_msginfo_equal() */ 1065 if (msginfo && msgview->msginfo && 1066 msginfo->msgnum == msgview->msginfo->msgnum && 1067 msginfo->folder == msgview->msginfo->folder) { 1068 summary_delete_trash(msgview->mainwin->summaryview); 1069 } else { 1070 msginfo = msgview->msginfo; 1071 1072 cm_return_if_fail(msginfo != NULL); 1073 1074 /* We will need to access the original message's msginfo 1075 * later, so we add our own reference. */ 1076 procmsg_msginfo_new_ref(msginfo); 1077 1078 /* to get the trash folder, we have to choose either 1079 * the folder's or account's trash default - we prefer 1080 * the one in the account prefs */ 1081 if (msginfo->folder) { 1082 if (NULL != (ac = account_find_from_item(msginfo->folder))) 1083 trash = account_get_special_folder(ac, F_TRASH); 1084 if (!trash && msginfo->folder->folder) 1085 trash = msginfo->folder->folder->trash; 1086 /* if still not found, use the default */ 1087 if (!trash) 1088 trash = folder_get_default_trash(); 1089 } 1090 1091 cm_return_if_fail(trash != NULL); 1092 1093 if (prefs_common.immediate_exec) 1094 /* TODO: Delete from trash */ 1095 folder_item_move_msg(trash, msginfo); 1096 else { 1097 procmsg_msginfo_set_to_folder(msginfo, trash); 1098 procmsg_msginfo_set_flags(msginfo, MSG_DELETED, 0); 1099 /* NOTE: does not update to next message in summaryview */ 1100 } 1101 1102 procmsg_msginfo_free(&msginfo); 1103 } 1104 } 1105 1106 /* 1107 * \brief update messageview with currently selected message in summaryview 1108 * leave unchanged if summaryview is empty 1109 * \param pointer to MessageView 1110 */ 1111 static void messageview_update(MessageView *msgview, MsgInfo *old_msginfo) 1112 { 1113 SummaryView *summaryview = (SummaryView*)msgview->mainwin->summaryview; 1114 1115 cm_return_if_fail(summaryview != NULL); 1116 1117 if (summaryview->selected) { 1118 MsgInfo *msginfo = summary_get_selected_msg(summaryview); 1119 if (msginfo == NULL || msginfo == old_msginfo) 1120 return; 1121 1122 messageview_show(msgview, msginfo, 1123 msgview->all_headers); 1124 } 1125 } 1126 1127 TextView *messageview_get_current_textview(MessageView *messageview) 1128 { 1129 TextView *text = NULL; 1130 1131 text = messageview->mimeview->textview; 1132 1133 return text; 1134 } 1135 1136 MimeInfo *messageview_get_selected_mime_part(MessageView *messageview) 1137 { 1138 return mimeview_get_selected_part(messageview->mimeview); 1139 } 1140 1141 void messageview_copy_clipboard(MessageView *messageview) 1142 { 1143 gchar *text = messageview_get_selection(messageview); 1144 if (text) { 1145 gtk_clipboard_set_text( 1146 gtk_clipboard_get(GDK_SELECTION_CLIPBOARD), 1147 text, -1); 1148 } 1149 g_free(text); 1150 } 1151 1152 void messageview_select_all(MessageView *messageview) 1153 { 1154 TextView *text; 1155 1156 text = messageview_get_current_textview(messageview); 1157 if (text) { 1158 GtkTextView *textview = GTK_TEXT_VIEW(text->text); 1159 GtkTextBuffer *buffer; 1160 GtkTextIter start, end; 1161 1162 buffer = gtk_text_view_get_buffer(textview); 1163 gtk_text_buffer_get_bounds(buffer, &start, &end); 1164 gtk_text_buffer_select_range(buffer, &start, &end); 1165 } 1166 } 1167 1168 void messageview_set_position(MessageView *messageview, gint pos) 1169 { 1170 TextView *text; 1171 1172 text = messageview_get_current_textview(messageview); 1173 if (text) 1174 textview_set_position(text, pos); 1175 } 1176 1177 gboolean messageview_search_string(MessageView *messageview, const gchar *str, 1178 gboolean case_sens) 1179 { 1180 TextView *text; 1181 1182 if (messageview->mimeview->type == MIMEVIEW_VIEWER) { 1183 MimeViewer *viewer = messageview->mimeview->mimeviewer; 1184 if (viewer && viewer->text_search) { 1185 return viewer->text_search(viewer, FALSE, str, case_sens); 1186 } 1187 } 1188 1189 text = messageview_get_current_textview(messageview); 1190 if (text) 1191 return textview_search_string(text, str, case_sens); 1192 return FALSE; 1193 } 1194 1195 gboolean messageview_search_string_backward(MessageView *messageview, 1196 const gchar *str, 1197 gboolean case_sens) 1198 { 1199 TextView *text; 1200 1201 if (messageview->mimeview->type == MIMEVIEW_VIEWER) { 1202 MimeViewer *viewer = messageview->mimeview->mimeviewer; 1203 if (viewer && viewer->text_search) { 1204 return viewer->text_search(viewer, TRUE, str, case_sens); 1205 } 1206 } 1207 1208 text = messageview_get_current_textview(messageview); 1209 if (text) 1210 return textview_search_string_backward(text, 1211 str, case_sens); 1212 return FALSE; 1213 } 1214 1215 gboolean messageview_is_visible(MessageView *messageview) 1216 { 1217 if (messageview == NULL) 1218 return FALSE; 1219 return messageview->visible; 1220 } 1221 1222 static gint messageview_delete_cb(GtkWidget *widget, GdkEventAny *event, 1223 MessageView *messageview) 1224 { 1225 messageview_destroy(messageview); 1226 return TRUE; 1227 } 1228 1229 static void messageview_size_allocate_cb(GtkWidget *widget, 1230 GtkAllocation *allocation) 1231 { 1232 cm_return_if_fail(allocation != NULL); 1233 1234 gtk_window_get_size(GTK_WINDOW(widget), 1235 &prefs_common.msgwin_width, &prefs_common.msgwin_height); 1236 } 1237 1238 static gboolean key_pressed(GtkWidget *widget, GdkEventKey *event, 1239 MessageView *messageview) 1240 { 1241 if (event && (event->state & (GDK_MOD1_MASK|GDK_CONTROL_MASK)) != 0) 1242 return FALSE; 1243 if (event && (event->state & GDK_SHIFT_MASK) && event->keyval != GDK_KEY_space) 1244 return FALSE; 1245 1246 if (event && (event->keyval == GDK_KEY_KP_Enter || event->keyval == GDK_KEY_Return) && 1247 messageview->window) { 1248 MsgInfo *new_msginfo = summary_get_selected_msg(messageview->mainwin->summaryview); 1249 messageview_show(messageview, new_msginfo, messageview->all_headers); 1250 } 1251 return FALSE; 1252 } 1253 1254 /* 1255 * \brief return selected messageview text, when nothing is 1256 * selected and message was filtered, return complete text 1257 * 1258 * \param pointer to Messageview 1259 * 1260 * \return pointer to text (needs to be free'd by calling func) 1261 */ 1262 gchar *messageview_get_selection(MessageView *msgview) 1263 { 1264 TextView *textview; 1265 gchar *text = NULL; 1266 GtkTextView *edit = NULL; 1267 GtkTextBuffer *textbuf; 1268 gint body_pos = 0; 1269 GtkTextIter start_iter, end_iter; 1270 GtkTextMark *body_start, *body_end; 1271 1272 cm_return_val_if_fail(msgview != NULL, NULL); 1273 1274 if (msgview->mimeview->type == MIMEVIEW_VIEWER) { 1275 MimeViewer *viewer = msgview->mimeview->mimeviewer; 1276 if (viewer && viewer->get_selection) { 1277 text = viewer->get_selection(viewer); 1278 if (text) 1279 return text; 1280 } 1281 } 1282 1283 textview = messageview_get_current_textview(msgview); 1284 cm_return_val_if_fail(textview != NULL, NULL); 1285 1286 edit = GTK_TEXT_VIEW(textview->text); 1287 cm_return_val_if_fail(edit != NULL, NULL); 1288 body_pos = textview->body_pos; 1289 1290 textbuf = gtk_text_view_get_buffer(edit); 1291 1292 if (gtk_text_buffer_get_selection_bounds(textbuf, NULL, NULL)) { 1293 return gtkut_text_view_get_selection(edit); 1294 } else { 1295 if (msgview->filtered) { 1296 gtk_text_buffer_get_iter_at_offset(textbuf, &start_iter, body_pos); 1297 gtk_text_buffer_get_end_iter(textbuf, &end_iter); 1298 } else { 1299 body_start = gtk_text_buffer_get_mark(textbuf, "body_start"); 1300 1301 /* If there is no body_start mark, an attachment is likely 1302 * selected, and we're looking at instructions on what to do 1303 * with it. No point in quoting that, so we'll just return NULL, 1304 * so that original message body is quoted instead down the line. 1305 */ 1306 if (body_start == NULL) { 1307 return NULL; 1308 } 1309 1310 gtk_text_buffer_get_iter_at_mark(textbuf, &start_iter, body_start); 1311 1312 body_end = gtk_text_buffer_get_mark(textbuf, "body_end"); 1313 if (body_end != NULL) /* Just in case */ 1314 gtk_text_buffer_get_iter_at_mark(textbuf, &end_iter, body_end); 1315 else 1316 gtk_text_buffer_get_end_iter(textbuf, &end_iter); 1317 } 1318 1319 return gtk_text_buffer_get_text(textbuf, &start_iter, &end_iter, FALSE); 1320 } 1321 1322 return text; 1323 } 1324 1325 static void save_as_cb(GtkAction *action, gpointer data) 1326 { 1327 messageview_save_as((MessageView *)data); 1328 } 1329 1330 void messageview_save_as(MessageView *messageview) 1331 { 1332 gchar *filename = NULL; 1333 gchar *src, *dest; 1334 gchar *tmp; 1335 gchar *filedir = NULL; 1336 gchar *converted_filename = NULL; 1337 gchar * filepath = NULL; 1338 AlertValue aval = 0; 1339 1340 if (!messageview->msginfo) return; 1341 1342 if (messageview->msginfo->subject) { 1343 Xstrdup_a(filename, messageview->msginfo->subject, return); 1344 subst_for_filename(filename); 1345 } 1346 1347 if (filename && !g_utf8_validate(filename, -1, NULL)) { 1348 converted_filename = conv_codeset_strdup(filename, 1349 conv_get_locale_charset_str(), 1350 CS_UTF_8); 1351 if (!converted_filename) 1352 g_warning("messageview_save_as(): failed to convert character set"); 1353 else 1354 filename = converted_filename; 1355 } 1356 if (!filename) 1357 return; 1358 1359 if (prefs_common.attach_save_dir && *prefs_common.attach_save_dir) 1360 filepath = g_strconcat(prefs_common.attach_save_dir, G_DIR_SEPARATOR_S, 1361 filename, NULL); 1362 dest = filesel_select_file_save(_("Save as"), filepath ? filepath : filename); 1363 if (filepath) 1364 g_free(filepath); 1365 if (converted_filename) 1366 g_free(converted_filename); 1367 if (!dest) 1368 return; 1369 1370 if (is_file_exist(dest)) { 1371 aval = alertpanel(_("Append or Overwrite"), 1372 _("Append or overwrite existing file?"), 1373 NULL, _("_Append"), NULL, _("_Overwrite"), 1374 NULL, _("_Cancel"), ALERTFOCUS_FIRST); 1375 if (aval != 0 && aval != 1) 1376 return; 1377 } 1378 1379 src = procmsg_get_message_file(messageview->msginfo); 1380 tmp = g_path_get_basename(dest); 1381 1382 if (aval == 0) { 1383 if (append_file(src, dest, TRUE) < 0) 1384 alertpanel_error(_("Couldn't save the file '%s'."), tmp); 1385 } else { 1386 if (copy_file(src, dest, TRUE) < 0) 1387 alertpanel_error(_("Couldn't save the file '%s'."), tmp); 1388 } 1389 g_free(src); 1390 1391 filedir = g_path_get_dirname(dest); 1392 if (filedir) { 1393 if (strcmp(filedir, ".")) { 1394 g_free(prefs_common.attach_save_dir); 1395 prefs_common.attach_save_dir = g_filename_to_utf8(filedir, -1, NULL, NULL, NULL); 1396 } 1397 g_free(filedir); 1398 } 1399 g_free(dest); 1400 g_free(tmp); 1401 } 1402 1403 static void close_cb(GtkAction *action, gpointer data) 1404 { 1405 MessageView *messageview = (MessageView *)data; 1406 messageview_destroy(messageview); 1407 } 1408 1409 static void copy_cb(GtkAction *action, gpointer data) 1410 { 1411 MessageView *messageview = (MessageView *)data; 1412 messageview_copy_clipboard(messageview); 1413 } 1414 1415 static void allsel_cb(GtkAction *action, gpointer data) 1416 { 1417 MessageView *messageview = (MessageView *)data; 1418 messageview_select_all(messageview); 1419 } 1420 1421 static void search_cb(GtkAction *action, gpointer data) 1422 { 1423 MessageView *messageview = (MessageView *)data; 1424 message_search(messageview); 1425 } 1426 1427 static void prev_cb(GtkAction *action, gpointer data) 1428 { 1429 MessageView *messageview = (MessageView *)data; 1430 messageview->updating = TRUE; 1431 summary_select_prev(messageview->mainwin->summaryview); 1432 messageview->updating = FALSE; 1433 1434 if (messageview->deferred_destroy) { 1435 debug_print("messageview got away!\n"); 1436 messageview_destroy(messageview); 1437 return; 1438 } 1439 if (messageview->mainwin->summaryview->selected) { 1440 MsgInfo * msginfo = summary_get_selected_msg(messageview->mainwin->summaryview); 1441 1442 if (msginfo) 1443 messageview_show(messageview, msginfo, 1444 messageview->all_headers); 1445 } else { 1446 gtk_widget_destroy(messageview->window); 1447 } 1448 } 1449 1450 static void next_cb(GtkAction *action, gpointer data) 1451 { 1452 MessageView *messageview = (MessageView *)data; 1453 messageview->updating = TRUE; 1454 summary_select_next(messageview->mainwin->summaryview); 1455 messageview->updating = FALSE; 1456 1457 if (messageview->deferred_destroy) { 1458 debug_print("messageview got away!\n"); 1459 messageview_destroy(messageview); 1460 return; 1461 } 1462 if (messageview->mainwin->summaryview->selected) { 1463 MsgInfo * msginfo = summary_get_selected_msg(messageview->mainwin->summaryview); 1464 1465 if (msginfo) 1466 messageview_show(messageview, msginfo, 1467 messageview->all_headers); 1468 } else { 1469 gtk_widget_destroy(messageview->window); 1470 } 1471 } 1472 1473 static void prev_unread_cb(GtkAction *action, gpointer data) 1474 { 1475 MessageView *messageview = (MessageView *)data; 1476 messageview->updating = TRUE; 1477 summary_select_prev_unread(messageview->mainwin->summaryview); 1478 messageview->updating = FALSE; 1479 1480 if (messageview->deferred_destroy) { 1481 debug_print("messageview got away!\n"); 1482 messageview_destroy(messageview); 1483 return; 1484 } 1485 if (messageview->mainwin->summaryview->selected) { 1486 MsgInfo * msginfo = summary_get_selected_msg(messageview->mainwin->summaryview); 1487 1488 if (msginfo) 1489 messageview_show(messageview, msginfo, 1490 messageview->all_headers); 1491 } else { 1492 gtk_widget_destroy(messageview->window); 1493 } 1494 } 1495 1496 static void next_unread_cb(GtkAction *action, gpointer data) 1497 { 1498 MessageView *messageview = (MessageView *)data; 1499 messageview->updating = TRUE; 1500 summary_select_next_unread(messageview->mainwin->summaryview); 1501 messageview->updating = FALSE; 1502 1503 if (messageview->deferred_destroy) { 1504 debug_print("messageview got away!\n"); 1505 messageview_destroy(messageview); 1506 return; 1507 } 1508 if (messageview->mainwin->summaryview->selected) { 1509 MsgInfo * msginfo = summary_get_selected_msg(messageview->mainwin->summaryview); 1510 1511 if (msginfo) 1512 messageview_show(messageview, msginfo, 1513 messageview->all_headers); 1514 } else { 1515 gtk_widget_destroy(messageview->window); 1516 } 1517 } 1518 1519 static void prev_new_cb(GtkAction *action, gpointer data) 1520 { 1521 MessageView *messageview = (MessageView *)data; 1522 messageview->updating = TRUE; 1523 summary_select_prev_new(messageview->mainwin->summaryview); 1524 messageview->updating = FALSE; 1525 1526 if (messageview->deferred_destroy) { 1527 debug_print("messageview got away!\n"); 1528 messageview_destroy(messageview); 1529 return; 1530 } 1531 if (messageview->mainwin->summaryview->selected) { 1532 MsgInfo * msginfo = summary_get_selected_msg(messageview->mainwin->summaryview); 1533 1534 if (msginfo) 1535 messageview_show(messageview, msginfo, 1536 messageview->all_headers); 1537 } else { 1538 gtk_widget_destroy(messageview->window); 1539 } 1540 } 1541 1542 static void next_new_cb(GtkAction *action, gpointer data) 1543 { 1544 MessageView *messageview = (MessageView *)data; 1545 messageview->updating = TRUE; 1546 summary_select_next_new(messageview->mainwin->summaryview); 1547 messageview->updating = FALSE; 1548 1549 if (messageview->deferred_destroy) { 1550 debug_print("messageview got away!\n"); 1551 messageview_destroy(messageview); 1552 return; 1553 } 1554 if (messageview->mainwin->summaryview->selected) { 1555 MsgInfo * msginfo = summary_get_selected_msg(messageview->mainwin->summaryview); 1556 1557 if (msginfo) 1558 messageview_show(messageview, msginfo, 1559 messageview->all_headers); 1560 } else { 1561 gtk_widget_destroy(messageview->window); 1562 } 1563 } 1564 1565 static void prev_marked_cb(GtkAction *action, gpointer data) 1566 { 1567 MessageView *messageview = (MessageView *)data; 1568 messageview->updating = TRUE; 1569 summary_select_prev_marked(messageview->mainwin->summaryview); 1570 messageview->updating = FALSE; 1571 1572 if (messageview->deferred_destroy) { 1573 debug_print("messageview got away!\n"); 1574 messageview_destroy(messageview); 1575 return; 1576 } 1577 if (messageview->mainwin->summaryview->selected) { 1578 MsgInfo * msginfo = summary_get_selected_msg(messageview->mainwin->summaryview); 1579 1580 if (msginfo) 1581 messageview_show(messageview, msginfo, 1582 messageview->all_headers); 1583 } else { 1584 gtk_widget_destroy(messageview->window); 1585 } 1586 } 1587 1588 static void next_marked_cb(GtkAction *action, gpointer data) 1589 { 1590 MessageView *messageview = (MessageView *)data; 1591 messageview->updating = TRUE; 1592 summary_select_next_marked(messageview->mainwin->summaryview); 1593 messageview->updating = FALSE; 1594 1595 if (messageview->deferred_destroy) { 1596 debug_print("messageview got away!\n"); 1597 messageview_destroy(messageview); 1598 return; 1599 } 1600 if (messageview->mainwin->summaryview->selected) { 1601 MsgInfo * msginfo = summary_get_selected_msg(messageview->mainwin->summaryview); 1602 1603 if (msginfo) 1604 messageview_show(messageview, msginfo, 1605 messageview->all_headers); 1606 } else { 1607 gtk_widget_destroy(messageview->window); 1608 } 1609 } 1610 1611 static void prev_labeled_cb(GtkAction *action, gpointer data) 1612 { 1613 MessageView *messageview = (MessageView *)data; 1614 messageview->updating = TRUE; 1615 summary_select_prev_labeled(messageview->mainwin->summaryview); 1616 messageview->updating = FALSE; 1617 1618 if (messageview->deferred_destroy) { 1619 debug_print("messageview got away!\n"); 1620 messageview_destroy(messageview); 1621 return; 1622 } 1623 if (messageview->mainwin->summaryview->selected) { 1624 MsgInfo * msginfo = summary_get_selected_msg(messageview->mainwin->summaryview); 1625 1626 if (msginfo) 1627 messageview_show(messageview, msginfo, 1628 messageview->all_headers); 1629 } else { 1630 gtk_widget_destroy(messageview->window); 1631 } 1632 } 1633 1634 static void next_labeled_cb(GtkAction *action, gpointer data) 1635 { 1636 MessageView *messageview = (MessageView *)data; 1637 messageview->updating = TRUE; 1638 summary_select_next_labeled(messageview->mainwin->summaryview); 1639 messageview->updating = FALSE; 1640 1641 if (messageview->deferred_destroy) { 1642 debug_print("messageview got away!\n"); 1643 messageview_destroy(messageview); 1644 return; 1645 } 1646 if (messageview->mainwin->summaryview->selected) { 1647 MsgInfo * msginfo = summary_get_selected_msg(messageview->mainwin->summaryview); 1648 1649 if (msginfo) 1650 messageview_show(messageview, msginfo, 1651 messageview->all_headers); 1652 } else { 1653 gtk_widget_destroy(messageview->window); 1654 } 1655 } 1656 1657 static void prev_history_cb(GtkAction *action, gpointer data) 1658 { 1659 MessageView *messageview = (MessageView *)data; 1660 MsgInfo *info = messageview_nav_get_prev(messageview); 1661 if (info) { 1662 messageview->updating = TRUE; 1663 messageview_show(messageview, info, 1664 messageview->all_headers); 1665 messageview->updating = FALSE; 1666 procmsg_msginfo_free(&info); 1667 if (messageview->deferred_destroy) { 1668 debug_print("messageview got away!\n"); 1669 messageview_destroy(messageview); 1670 return; 1671 } 1672 } 1673 } 1674 1675 static void next_history_cb(GtkAction *action, gpointer data) 1676 { 1677 MessageView *messageview = (MessageView *)data; 1678 MsgInfo *info = messageview_nav_get_next(messageview); 1679 if (info) { 1680 messageview->updating = TRUE; 1681 messageview_show(messageview, info, 1682 messageview->all_headers); 1683 messageview->updating = FALSE; 1684 procmsg_msginfo_free(&info); 1685 if (messageview->deferred_destroy) { 1686 debug_print("messageview got away!\n"); 1687 messageview_destroy(messageview); 1688 return; 1689 } 1690 } 1691 } 1692 1693 static void parent_cb(GtkAction *action, gpointer data) 1694 { 1695 MessageView *messageview = (MessageView *)data; 1696 messageview->updating = TRUE; 1697 summary_select_parent(messageview->mainwin->summaryview); 1698 messageview->updating = FALSE; 1699 1700 if (messageview->deferred_destroy) { 1701 debug_print("messageview got away!\n"); 1702 messageview_destroy(messageview); 1703 return; 1704 } 1705 if (messageview->mainwin->summaryview->selected) { 1706 MsgInfo * msginfo = summary_get_selected_msg(messageview->mainwin->summaryview); 1707 1708 if (msginfo) 1709 messageview_show(messageview, msginfo, 1710 messageview->all_headers); 1711 } else { 1712 gtk_widget_destroy(messageview->window); 1713 } 1714 } 1715 1716 static void goto_unread_folder_cb(GtkAction *action, gpointer data) 1717 { 1718 MessageView *messageview = (MessageView *)data; 1719 1720 messageview->updating = TRUE; 1721 folderview_select_next_with_flag(messageview->mainwin->folderview, MSG_UNREAD); 1722 messageview->updating = FALSE; 1723 1724 if (messageview->deferred_destroy) { 1725 debug_print("messageview got away!\n"); 1726 messageview_destroy(messageview); 1727 return; 1728 } 1729 if (messageview->mainwin->summaryview->selected) { 1730 MsgInfo * msginfo = summary_get_selected_msg(messageview->mainwin->summaryview); 1731 1732 if (msginfo) 1733 messageview_show(messageview, msginfo, 1734 messageview->all_headers); 1735 } else { 1736 gtk_widget_destroy(messageview->window); 1737 } 1738 } 1739 1740 static void goto_folder_cb(GtkAction *action, gpointer data) 1741 { 1742 MessageView *messageview = (MessageView *)data; 1743 FolderItem *to_folder; 1744 1745 to_folder = foldersel_folder_sel(NULL, FOLDER_SEL_ALL, NULL, FALSE, 1746 _("Select folder to go to")); 1747 1748 if (to_folder) { 1749 folderview_select(messageview->mainwin->folderview, to_folder); 1750 1751 if (messageview->deferred_destroy) { 1752 debug_print("messageview got away!\n"); 1753 messageview_destroy(messageview); 1754 return; 1755 } 1756 if (messageview->mainwin->summaryview->selected) { 1757 MsgInfo * msginfo = summary_get_selected_msg(messageview->mainwin->summaryview); 1758 1759 if (msginfo) 1760 messageview_show(messageview, msginfo, 1761 messageview->all_headers); 1762 } else { 1763 gtk_widget_destroy(messageview->window); 1764 } 1765 } 1766 } 1767 1768 static void set_charset_cb(GtkAction *action, GtkRadioAction *current, gpointer data) 1769 { 1770 MessageView *messageview = (MessageView *)data; 1771 gboolean active = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (current)); 1772 gint value = gtk_radio_action_get_current_value (GTK_RADIO_ACTION (current)); 1773 const gchar *charset; 1774 1775 if (active) { 1776 charset = conv_get_charset_str((CharSet)value); 1777 g_free(messageview->forced_charset); 1778 messageview->forced_charset = g_strdup(charset); 1779 procmime_force_charset(charset); 1780 1781 messageview_show(messageview, messageview->msginfo, FALSE); 1782 } 1783 } 1784 1785 static void set_decode_cb(GtkAction *action, GtkRadioAction *current, gpointer data) 1786 { 1787 MessageView *messageview = (MessageView *)data; 1788 gboolean active = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (current)); 1789 gint value = gtk_radio_action_get_current_value (GTK_RADIO_ACTION (current)); 1790 1791 if (active) { 1792 messageview->forced_encoding = (EncodingType)value; 1793 1794 messageview_show(messageview, messageview->msginfo, FALSE); 1795 debug_print("forced encoding: %d\n", value); 1796 } 1797 } 1798 1799 1800 static void view_source_cb(GtkAction *action, gpointer data) 1801 { 1802 MessageView *messageview = (MessageView *)data; 1803 SourceWindow *srcwin; 1804 1805 if (!messageview->msginfo) return; 1806 1807 srcwin = source_window_create(); 1808 source_window_show(srcwin); 1809 source_window_show_msg(srcwin, messageview->msginfo); 1810 } 1811 1812 static void show_all_header_cb(GtkToggleAction *action, gpointer data) 1813 { 1814 MessageView *messageview = (MessageView *)data; 1815 MsgInfo *msginfo = messageview->msginfo; 1816 1817 if (messageview->mimeview->textview && 1818 messageview->mimeview->textview->loading) { 1819 return; 1820 } 1821 if (messageview->updating) 1822 return; 1823 1824 messageview->all_headers = prefs_common.show_all_headers = 1825 gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)); 1826 if (!msginfo) return; 1827 messageview->msginfo = NULL; 1828 messageview_show(messageview, msginfo, messageview->all_headers); 1829 procmsg_msginfo_free(&msginfo); 1830 main_window_set_menu_sensitive(messageview->mainwin); 1831 summary_redisplay_msg(messageview->mainwin->summaryview); 1832 } 1833 1834 static void msg_hide_quotes_cb(GtkToggleAction *action, gpointer data) 1835 { 1836 MessageView *messageview = (MessageView *)data; 1837 MsgInfo *msginfo = messageview->msginfo; 1838 static gboolean updating_menu = FALSE; 1839 1840 if (updating_menu) 1841 return; 1842 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))) { 1843 const gchar *a_name = gtk_action_get_name(GTK_ACTION(action)); 1844 if (!strcmp(a_name, "View/Quotes/CollapseAll")) prefs_common.hide_quotes = 1; 1845 else if (!strcmp(a_name, "View/Quotes/Collapse2")) prefs_common.hide_quotes = 2; 1846 else if (!strcmp(a_name, "View/Quotes/Collapse3")) prefs_common.hide_quotes = 3; 1847 } else 1848 prefs_common.hide_quotes = 0; 1849 1850 updating_menu=TRUE; 1851 1852 cm_toggle_menu_set_active_full(messageview->ui_manager, "Menu/View/Quotes/CollapseAll", (prefs_common.hide_quotes == 1)); 1853 cm_toggle_menu_set_active_full(messageview->ui_manager, "Menu/View/Quotes/Collapse2", (prefs_common.hide_quotes == 2)); 1854 cm_toggle_menu_set_active_full(messageview->ui_manager, "Menu/View/Quotes/Collapse3", (prefs_common.hide_quotes == 3)); 1855 1856 updating_menu=FALSE; 1857 if (!msginfo) return; 1858 messageview->msginfo = NULL; 1859 messageview_show(messageview, msginfo, 1860 messageview->all_headers); 1861 procmsg_msginfo_free(&msginfo); 1862 1863 /* update main window */ 1864 main_window_set_menu_sensitive(messageview->mainwin); 1865 summary_redisplay_msg(messageview->mainwin->summaryview); 1866 } 1867 #undef SET_CHECK_MENU_ACTIVE 1868 1869 static void compose_cb(GtkAction *action, gpointer data) 1870 { 1871 MessageView *messageview = (MessageView *)data; 1872 PrefsAccount *ac = NULL; 1873 FolderItem *item = NULL; 1874 1875 if (messageview->msginfo) 1876 item = messageview->msginfo->folder; 1877 if (item) 1878 ac = account_find_from_item(item); 1879 1880 compose_new(ac, NULL, NULL); 1881 } 1882 1883 #define DO_ACTION(name, act) { if (!strcmp(a_name, name)) action = act; } 1884 1885 static void reply_cb(GtkAction *gaction, gpointer data) 1886 { 1887 MessageView *messageview = (MessageView *)data; 1888 GSList *msginfo_list = NULL; 1889 gint action = COMPOSE_REPLY; 1890 const gchar *a_name = gtk_action_get_name(gaction); 1891 1892 cm_return_if_fail(messageview->msginfo); 1893 1894 DO_ACTION("Message/Reply", COMPOSE_REPLY); 1895 DO_ACTION("Message/ReplyTo/All", COMPOSE_REPLY_TO_ALL); 1896 DO_ACTION("Message/ReplyTo/Sender", COMPOSE_REPLY_TO_SENDER); 1897 DO_ACTION("Message/ReplyTo/List", COMPOSE_REPLY_TO_LIST); 1898 DO_ACTION("Message/Forward", COMPOSE_FORWARD_INLINE); 1899 DO_ACTION("Message/ForwardAtt", COMPOSE_FORWARD_AS_ATTACH); 1900 DO_ACTION("Message/Redirect", COMPOSE_REDIRECT); 1901 1902 msginfo_list = g_slist_append(msginfo_list, messageview->msginfo); 1903 compose_reply_from_messageview(messageview, msginfo_list, action); 1904 g_slist_free(msginfo_list); 1905 } 1906 1907 static void addressbook_open_cb(GtkAction *action, gpointer data) 1908 { 1909 addressbook_open(NULL); 1910 } 1911 1912 static void add_address_cb(GtkAction *action, gpointer data) 1913 { 1914 MessageView *messageview = (MessageView *)data; 1915 MsgInfo *msginfo, *full_msginfo; 1916 gchar *from; 1917 1918 if (!messageview->msginfo || !messageview->msginfo->from) 1919 return; 1920 1921 msginfo = messageview->msginfo; 1922 Xstrdup_a(from, msginfo->from, return); 1923 eliminate_address_comment(from); 1924 extract_address(from); 1925 1926 full_msginfo = procmsg_msginfo_get_full_info(msginfo); 1927 1928 procmsg_msginfo_free(&full_msginfo); 1929 1930 addressbook_add_contact(msginfo->fromname, from, NULL, NULL); 1931 } 1932 1933 static gboolean messageview_update_msg(gpointer source, gpointer data) 1934 { 1935 MsgInfoUpdate *msginfo_update = (MsgInfoUpdate *) source; 1936 MessageView *messageview = (MessageView *)data; 1937 MsgInfo *old_msginfo = messageview->msginfo; 1938 1939 if (messageview->msginfo != msginfo_update->msginfo) 1940 return FALSE; 1941 1942 if ((msginfo_update->flags & MSGINFO_UPDATE_DELETED) || 1943 MSG_IS_DELETED(old_msginfo->flags)) { 1944 if (messageview->new_window) { 1945 if (old_msginfo->folder && old_msginfo->folder->total_msgs == 0) { 1946 messageview_clear(messageview); 1947 textview_show_info(messageview->mimeview->textview, 1948 _("\n There are no messages in this folder")); 1949 return FALSE; 1950 } 1951 1952 if (!OPEN_SELECTED_ON_DELETEMOVE && !OPEN_SELECTED_ON_PREVNEXT) { 1953 messageview_clear(messageview); 1954 textview_show_info(messageview->mimeview->textview, 1955 MSG_IS_DELETED(old_msginfo->flags) ? 1956 _("\n Message has been deleted") : 1957 _("\n Message has been deleted or moved to another folder")); 1958 } else 1959 messageview->update_needed = TRUE; 1960 } else { 1961 messageview_clear(messageview); 1962 messageview_update(messageview, old_msginfo); 1963 } 1964 } 1965 1966 return FALSE; 1967 } 1968 1969 void messageview_set_menu_sensitive(MessageView *messageview) 1970 { 1971 if (!messageview || !messageview->ui_manager) 1972 return; 1973 1974 cm_toggle_menu_set_active_full(messageview->ui_manager, "Menu/View/Quotes/CollapseAll", (prefs_common.hide_quotes == 1)); 1975 cm_toggle_menu_set_active_full(messageview->ui_manager, "Menu/View/Quotes/Collapse2", (prefs_common.hide_quotes == 2)); 1976 cm_toggle_menu_set_active_full(messageview->ui_manager, "Menu/View/Quotes/Collapse3", (prefs_common.hide_quotes == 3)); 1977 cm_menu_set_sensitive_full(messageview->ui_manager, "Menu/View/Goto/PrevHistory", messageview_nav_has_prev(messageview)); 1978 cm_menu_set_sensitive_full(messageview->ui_manager, "Menu/View/Goto/NextHistory", messageview_nav_has_next(messageview)); 1979 } 1980 1981 static void save_part_as_cb(GtkAction *action, gpointer data) 1982 { 1983 MessageView *messageview = (MessageView *)data; 1984 1985 if (messageview->mimeview) 1986 mimeview_save_as(messageview->mimeview); 1987 } 1988 1989 static void view_part_as_text_cb(GtkAction *action, gpointer data) 1990 { 1991 MessageView *messageview = (MessageView *)data; 1992 1993 if (messageview->mimeview) 1994 mimeview_display_as_text(messageview->mimeview); 1995 } 1996 1997 static void open_part_cb(GtkAction *action, gpointer data) 1998 { 1999 MessageView *messageview = (MessageView *)data; 2000 2001 if (messageview->mimeview) 2002 mimeview_launch(messageview->mimeview, NULL); 2003 } 2004 2005 static void open_part_with_cb(GtkAction *action, gpointer data) 2006 { 2007 MessageView *messageview = (MessageView *)data; 2008 2009 if (messageview->mimeview) 2010 mimeview_open_with(messageview->mimeview); 2011 } 2012 2013 static void goto_next_part_cb(GtkAction *action, gpointer data) 2014 { 2015 MessageView *messageview = (MessageView *)data; 2016 2017 if (messageview->mimeview) 2018 mimeview_select_next_part(messageview->mimeview); 2019 } 2020 2021 static void goto_prev_part_cb(GtkAction *action, gpointer data) 2022 { 2023 MessageView *messageview = (MessageView *)data; 2024 2025 if (messageview->mimeview) 2026 mimeview_select_prev_part(messageview->mimeview); 2027 } 2028