2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2006 Hiroyuki Yamamoto and the Sylpheed-Claws team
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.
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.
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
27 #include <glib/gi18n.h>
28 #include <gdk/gdkkeysyms.h>
29 #include <gtk/gtknotebook.h>
30 #include <gtk/gtkscrolledwindow.h>
31 #include <gtk/gtkctree.h>
32 #include <gtk/gtkvbox.h>
33 #include <gtk/gtkhbox.h>
34 #include <gtk/gtkvpaned.h>
35 #include <gtk/gtktext.h>
36 #include <gtk/gtksignal.h>
37 #include <gtk/gtkmenu.h>
38 #include <gtk/gtkdnd.h>
39 #include <gtk/gtkselection.h>
40 #include <gtk/gtktooltips.h>
41 #include <gtk/gtkcontainer.h>
42 #include <gtk/gtkbutton.h>
45 #ifndef HAVE_APACHE_FNMATCH
46 /* kludge: apache's fnmatch clashes with <regex.h>, don't include
55 #include "summaryview.h"
58 #include "alertpanel.h"
59 #include "inputdialog.h"
62 #include "prefs_common.h"
63 #include "procheader.h"
64 #include "stock_pixmap.h"
65 #include "gtk/gtkvscrollbutton.h"
66 #include "gtk/logwindow.h"
76 #define N_MIMEVIEW_COLS 3
78 static void mimeview_set_multipart_tree (MimeView
*mimeview
,
80 GtkCTreeNode
*parent
);
81 static GtkCTreeNode
*mimeview_append_part (MimeView
*mimeview
,
83 GtkCTreeNode
*parent
);
84 static void mimeview_show_message_part (MimeView
*mimeview
,
86 static void mimeview_change_view_type (MimeView
*mimeview
,
88 gchar
*mimeview_get_filename_for_part (MimeInfo
*partinfo
,
91 static gboolean
mimeview_write_part (const gchar
*filename
,
94 static void mimeview_selected (GtkCTree
*ctree
,
98 static void mimeview_start_drag (GtkWidget
*widget
,
102 static gint
mimeview_button_pressed (GtkWidget
*widget
,
103 GdkEventButton
*event
,
105 static gint
mimeview_key_pressed (GtkWidget
*widget
,
109 static void mimeview_drag_data_get (GtkWidget
*widget
,
110 GdkDragContext
*drag_context
,
111 GtkSelectionData
*selection_data
,
116 static void mimeview_display_as_text (MimeView
*mimeview
);
117 static void mimeview_save_as (MimeView
*mimeview
);
118 static void mimeview_save_all (MimeView
*mimeview
);
119 static void mimeview_launch (MimeView
*mimeview
);
120 static void mimeview_open_with (MimeView
*mimeview
);
121 static void mimeview_open_part_with (MimeView
*mimeview
,
123 static void mimeview_view_file (const gchar
*filename
,
125 const gchar
*cmdline
,
127 static gboolean
icon_clicked_cb (GtkWidget
*button
,
128 GdkEventButton
*event
,
130 static void icon_selected (MimeView
*mimeview
,
133 static gint
icon_key_pressed (GtkWidget
*button
,
136 static void toggle_icon (GtkToggleButton
*button
,
138 static void icon_list_append_icon (MimeView
*mimeview
,
140 static void icon_list_create (MimeView
*mimeview
,
142 static void icon_list_clear (MimeView
*mimeview
);
143 static void icon_list_toggle_by_mime_info (MimeView
*mimeview
,
145 static gboolean
icon_list_select_by_number(MimeView
*mimeview
,
147 static void mime_toggle_button_cb (GtkWidget
*button
,
149 static gboolean
part_button_pressed (MimeView
*mimeview
,
150 GdkEventButton
*event
,
152 static void icon_scroll_size_allocate_cb(GtkWidget
*widget
,
153 GtkAllocation
*layout_size
,
156 static GtkItemFactoryEntry mimeview_popup_entries
[] =
158 {N_("/_Open"), NULL
, mimeview_launch
, 0, NULL
},
159 {N_("/Open _with..."), NULL
, mimeview_open_with
, 0, NULL
},
160 {N_("/_Display as text"), NULL
, mimeview_display_as_text
, 0, NULL
},
161 {N_("/_Save as..."), NULL
, mimeview_save_as
, 0, NULL
},
162 {N_("/Save _all..."), NULL
, mimeview_save_all
, 0, NULL
},
165 static GtkTargetEntry mimeview_mime_types
[] =
167 {"text/uri-list", 0, 0}
170 GSList
*mimeviewer_factories
;
173 MimeView
*mimeview_create(MainWindow
*mainwin
)
178 GtkWidget
*scrolledwin
;
180 GtkWidget
*mime_notebook
;
181 GtkWidget
*popupmenu
;
182 GtkWidget
*ctree_mainbox
;
184 GtkWidget
*mime_toggle
;
185 GtkWidget
*icon_mainbox
;
186 GtkWidget
*icon_scroll
;
187 GtkWidget
*icon_vbox
;
189 GtkWidget
*scrollbutton
;
191 GtkTooltips
*tooltips
;
192 GtkItemFactory
*popupfactory
;
193 NoticeView
*siginfoview
;
194 gchar
*titles
[N_MIMEVIEW_COLS
];
198 debug_print("Creating MIME view...\n");
199 mimeview
= g_new0(MimeView
, 1);
201 titles
[COL_MIMETYPE
] = _("MIME Type");
202 titles
[COL_SIZE
] = _("Size");
203 titles
[COL_NAME
] = _("Name");
205 scrolledwin
= gtk_scrolled_window_new(NULL
, NULL
);
206 gtk_widget_show(scrolledwin
);
207 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwin
),
208 GTK_POLICY_AUTOMATIC
,
209 GTK_POLICY_AUTOMATIC
);
211 ctree
= gtk_sctree_new_with_titles(N_MIMEVIEW_COLS
, 0, titles
);
212 gtk_widget_show(ctree
);
213 gtk_clist_set_selection_mode(GTK_CLIST(ctree
), GTK_SELECTION_BROWSE
);
214 gtk_ctree_set_line_style(GTK_CTREE(ctree
), GTK_CTREE_LINES_NONE
);
215 gtk_clist_set_column_justification(GTK_CLIST(ctree
), COL_SIZE
,
217 gtk_clist_set_column_width(GTK_CLIST(ctree
), COL_MIMETYPE
, 240);
218 gtk_clist_set_column_width(GTK_CLIST(ctree
), COL_SIZE
, 90);
219 for (i
= 0; i
< N_MIMEVIEW_COLS
; i
++)
220 GTK_WIDGET_UNSET_FLAGS(GTK_CLIST(ctree
)->column
[i
].button
,
222 gtk_container_add(GTK_CONTAINER(scrolledwin
), ctree
);
224 g_signal_connect(G_OBJECT(ctree
), "tree_select_row",
225 G_CALLBACK(mimeview_selected
), mimeview
);
226 g_signal_connect(G_OBJECT(ctree
), "button_release_event",
227 G_CALLBACK(mimeview_button_pressed
), mimeview
);
228 g_signal_connect(G_OBJECT(ctree
), "key_press_event",
229 G_CALLBACK(mimeview_key_pressed
), mimeview
);
230 g_signal_connect(G_OBJECT (ctree
),"start_drag",
231 G_CALLBACK (mimeview_start_drag
), mimeview
);
232 g_signal_connect(G_OBJECT(ctree
), "drag_data_get",
233 G_CALLBACK(mimeview_drag_data_get
), mimeview
);
235 mime_notebook
= gtk_notebook_new();
236 gtk_widget_show(mime_notebook
);
237 GTK_WIDGET_UNSET_FLAGS(mime_notebook
, GTK_CAN_FOCUS
);
238 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(mime_notebook
), FALSE
);
239 gtk_notebook_set_show_border(GTK_NOTEBOOK(mime_notebook
), FALSE
);
241 icon_vbox
= gtk_vbox_new(FALSE
, 2);
242 gtk_widget_show(icon_vbox
);
243 icon_scroll
= gtk_layout_new(NULL
, NULL
);
244 gtk_widget_show(icon_scroll
);
245 gtk_layout_put(GTK_LAYOUT(icon_scroll
), icon_vbox
, 0, 0);
246 scrollbutton
= gtk_vscrollbutton_new(gtk_layout_get_vadjustment(GTK_LAYOUT(icon_scroll
)));
247 gtk_widget_show(scrollbutton
);
249 mime_toggle
= gtk_toggle_button_new();
250 gtk_widget_show(mime_toggle
);
251 arrow
= gtk_arrow_new(GTK_ARROW_LEFT
, GTK_SHADOW_NONE
);
252 gtk_widget_show(arrow
);
253 gtk_container_add(GTK_CONTAINER(mime_toggle
), arrow
);
254 g_signal_connect(G_OBJECT(mime_toggle
), "toggled",
255 G_CALLBACK(mime_toggle_button_cb
), mimeview
);
257 icon_mainbox
= gtk_vbox_new(FALSE
, 0);
258 gtk_widget_show(icon_mainbox
);
259 gtk_box_pack_start(GTK_BOX(icon_mainbox
), mime_toggle
, FALSE
, FALSE
, 0);
260 gtk_box_pack_start(GTK_BOX(icon_mainbox
), icon_scroll
, TRUE
, TRUE
, 3);
261 gtk_box_pack_end(GTK_BOX(icon_mainbox
), scrollbutton
, FALSE
, FALSE
, 0);
262 g_signal_connect(G_OBJECT(icon_mainbox
), "size_allocate",
263 G_CALLBACK(icon_scroll_size_allocate_cb
), mimeview
);
265 ctree_mainbox
= gtk_hbox_new(FALSE
, 0);
266 gtk_box_pack_start(GTK_BOX(ctree_mainbox
), scrolledwin
, TRUE
, TRUE
, 0);
268 n_entries
= sizeof(mimeview_popup_entries
) /
269 sizeof(mimeview_popup_entries
[0]);
270 popupmenu
= menu_create_items(mimeview_popup_entries
, n_entries
,
271 "<MimeView>", &popupfactory
, mimeview
);
272 tooltips
= gtk_tooltips_new();
273 gtk_tooltips_set_delay(tooltips
, 0);
275 vbox
= gtk_vbox_new(FALSE
, 0);
276 gtk_widget_show(vbox
);
277 siginfoview
= noticeview_create(mainwin
);
278 noticeview_hide(siginfoview
);
279 noticeview_set_icon_clickable(siginfoview
, TRUE
);
280 gtk_box_pack_start(GTK_BOX(vbox
), mime_notebook
, TRUE
, TRUE
, 0);
281 gtk_box_pack_end(GTK_BOX(vbox
), GTK_WIDGET_PTR(siginfoview
), FALSE
, FALSE
, 0);
283 paned
= gtk_vpaned_new();
284 gtk_widget_show(paned
);
285 gtk_paned_set_gutter_size(GTK_PANED(paned
), 0);
286 gtk_paned_pack1(GTK_PANED(paned
), ctree_mainbox
, FALSE
, TRUE
);
287 gtk_paned_pack2(GTK_PANED(paned
), vbox
, TRUE
, TRUE
);
289 hbox
= gtk_hbox_new(FALSE
, 0);
290 gtk_box_pack_start(GTK_BOX(hbox
), paned
, TRUE
, TRUE
, 0);
291 gtk_box_pack_start(GTK_BOX(hbox
), icon_mainbox
, FALSE
, FALSE
, 0);
293 gtk_widget_show(hbox
);
294 gtk_widget_hide(ctree_mainbox
);
296 mimeview
->hbox
= hbox
;
297 mimeview
->paned
= paned
;
298 mimeview
->scrolledwin
= scrolledwin
;
299 mimeview
->ctree
= ctree
;
300 mimeview
->mime_notebook
= mime_notebook
;
301 mimeview
->popupmenu
= popupmenu
;
302 mimeview
->popupfactory
= popupfactory
;
304 mimeview
->ctree_mainbox
= ctree_mainbox
;
305 mimeview
->icon_scroll
= icon_scroll
;
306 mimeview
->icon_vbox
= icon_vbox
;
307 mimeview
->icon_mainbox
= icon_mainbox
;
308 mimeview
->icon_count
= 0;
309 mimeview
->mainwin
= mainwin
;
310 mimeview
->tooltips
= tooltips
;
311 mimeview
->oldsize
= 60;
312 mimeview
->mime_toggle
= mime_toggle
;
313 mimeview
->siginfoview
= siginfoview
;
315 mimeview
->target_list
= gtk_target_list_new(mimeview_mime_types
, 1);
317 mimeviews
= g_slist_prepend(mimeviews
, mimeview
);
322 void mimeview_init(MimeView
*mimeview
)
324 textview_init(mimeview
->textview
);
326 gtk_container_add(GTK_CONTAINER(mimeview
->mime_notebook
),
327 GTK_WIDGET_PTR(mimeview
->textview
));
330 void mimeview_show_message(MimeView
*mimeview
, MimeInfo
*mimeinfo
,
333 GtkCTree
*ctree
= GTK_CTREE(mimeview
->ctree
);
336 mimeview_clear(mimeview
);
338 g_return_if_fail(file
!= NULL
);
339 g_return_if_fail(mimeinfo
!= NULL
);
341 mimeview
->mimeinfo
= mimeinfo
;
343 mimeview
->file
= g_strdup(file
);
345 g_signal_handlers_block_by_func(G_OBJECT(ctree
), mimeview_selected
,
348 mimeview_set_multipart_tree(mimeview
, mimeinfo
, NULL
);
349 icon_list_create(mimeview
, mimeinfo
);
351 g_signal_handlers_unblock_by_func(G_OBJECT(ctree
),
352 mimeview_selected
, mimeview
);
354 node
= GTK_CTREE_NODE(GTK_CLIST(ctree
)->row_list
);
356 gtk_ctree_select(ctree
, node
);
357 icon_list_toggle_by_mime_info
358 (mimeview
, gtk_ctree_node_get_row_data(ctree
, node
));
359 gtkut_ctree_set_focus_row(ctree
, node
);
364 static void mimeview_check_sig_cancel_now(MimeView
*mimeview
);
367 static void mimeview_free_mimeinfo(MimeView
*mimeview
)
369 gboolean defer
= FALSE
;
371 defer
= (mimeview
->check_data
!= NULL
);
373 mimeview
->check_data
->free_after_use
= TRUE
;
375 if (mimeview
->mimeinfo
!= NULL
&& !defer
) {
376 procmime_mimeinfo_free_all(mimeview
->mimeinfo
);
377 mimeview
->mimeinfo
= NULL
;
380 debug_print("deferring free(mimeinfo) and cancelling check\n");
381 mimeview_check_sig_cancel_now(mimeview
);
386 void mimeview_destroy(MimeView
*mimeview
)
390 for (cur
= mimeview
->viewers
; cur
!= NULL
; cur
= g_slist_next(cur
)) {
391 MimeViewer
*viewer
= (MimeViewer
*) cur
->data
;
392 viewer
->destroy_viewer(viewer
);
394 g_slist_free(mimeview
->viewers
);
395 gtk_target_list_unref(mimeview
->target_list
);
397 mimeview_free_mimeinfo(mimeview
);
399 if (mimeview
->check_data
) {
400 mimeview
->check_data
->destroy_mimeview
= TRUE
;
401 debug_print("deferring destroy\n");
405 g_free(mimeview
->file
);
407 mimeviews
= g_slist_remove(mimeviews
, mimeview
);
412 MimeInfo
*mimeview_get_selected_part(MimeView
*mimeview
)
414 return gtk_ctree_node_get_row_data
415 (GTK_CTREE(mimeview
->ctree
), mimeview
->opened
);
418 static void mimeview_set_multipart_tree(MimeView
*mimeview
,
420 GtkCTreeNode
*parent
)
424 g_return_if_fail(mimeinfo
!= NULL
);
426 while (mimeinfo
!= NULL
) {
427 node
= mimeview_append_part(mimeview
, mimeinfo
, parent
);
429 if (mimeinfo
->node
->children
)
430 mimeview_set_multipart_tree(mimeview
, (MimeInfo
*) mimeinfo
->node
->children
->data
, node
);
431 mimeinfo
= mimeinfo
->node
->next
!= NULL
? (MimeInfo
*) mimeinfo
->node
->next
->data
: NULL
;
435 static const gchar
*get_real_part_name(MimeInfo
*partinfo
)
437 const gchar
*name
= NULL
;
439 name
= procmime_mimeinfo_get_parameter(partinfo
, "filename");
441 name
= procmime_mimeinfo_get_parameter(partinfo
, "name");
446 static const gchar
*get_part_name(MimeInfo
*partinfo
)
450 name
= get_real_part_name(partinfo
);
457 static const gchar
*get_part_description(MimeInfo
*partinfo
)
459 if (partinfo
->description
)
460 return partinfo
->description
;
462 return get_part_name(partinfo
);
465 static GtkCTreeNode
*mimeview_append_part(MimeView
*mimeview
,
467 GtkCTreeNode
*parent
)
469 GtkCTree
*ctree
= GTK_CTREE(mimeview
->ctree
);
471 static gchar content_type
[64];
472 gchar
*str
[N_MIMEVIEW_COLS
];
474 if (partinfo
->type
!= MIMETYPE_UNKNOWN
&& partinfo
->subtype
) {
475 g_snprintf(content_type
, 64, "%s/%s", procmime_get_media_type_str(partinfo
->type
), partinfo
->subtype
);
477 g_snprintf(content_type
, 64, "UNKNOWN");
480 str
[COL_MIMETYPE
] = content_type
;
481 str
[COL_SIZE
] = to_human_readable(partinfo
->length
);
482 if (prefs_common
.attach_desc
)
483 str
[COL_NAME
] = (gchar
*) get_part_description(partinfo
);
485 str
[COL_NAME
] = (gchar
*) get_part_name(partinfo
);
487 node
= gtk_sctree_insert_node(ctree
, parent
, NULL
, str
, 0,
488 NULL
, NULL
, NULL
, NULL
,
490 gtk_ctree_node_set_row_data(ctree
, node
, partinfo
);
495 static void mimeview_show_message_part(MimeView
*mimeview
, MimeInfo
*partinfo
)
500 if (!partinfo
) return;
502 fname
= mimeview
->file
;
505 if ((fp
= g_fopen(fname
, "rb")) == NULL
) {
506 FILE_OP_ERROR(fname
, "fopen");
510 if (fseek(fp
, partinfo
->offset
, SEEK_SET
) < 0) {
511 FILE_OP_ERROR(mimeview
->file
, "fseek");
516 mimeview_change_view_type(mimeview
, MIMEVIEW_TEXT
);
517 textview_show_part(mimeview
->textview
, partinfo
, fp
);
522 static MimeViewer
*get_viewer_for_content_type(MimeView
*mimeview
, const gchar
*content_type
)
525 MimeViewerFactory
*factory
= NULL
;
526 MimeViewer
*viewer
= NULL
;
529 * FNM_CASEFOLD is a GNU extension
530 * if its not defined copy the string to the stack and
531 * convert the copy to lower case
534 #define FNM_CASEFOLD 0
535 Xstrdup_a(content_type
, content_type
, return NULL
);
536 g_strdown((gchar
*)content_type
);
539 for (cur
= mimeviewer_factories
; cur
!= NULL
; cur
= g_slist_next(cur
)) {
540 MimeViewerFactory
*curfactory
= cur
->data
;
543 while (curfactory
->content_types
[i
] != NULL
) {
544 if(!fnmatch(curfactory
->content_types
[i
], content_type
, FNM_CASEFOLD
)) {
545 debug_print("%s\n", curfactory
->content_types
[i
]);
546 factory
= curfactory
;
557 for (cur
= mimeview
->viewers
; cur
!= NULL
; cur
= g_slist_next(cur
)) {
558 MimeViewer
*curviewer
= cur
->data
;
560 if (curviewer
->factory
== factory
)
563 viewer
= factory
->create_viewer();
564 gtk_container_add(GTK_CONTAINER(mimeview
->mime_notebook
),
565 GTK_WIDGET(viewer
->get_widget(viewer
)));
567 mimeview
->viewers
= g_slist_append(mimeview
->viewers
, viewer
);
572 static MimeViewer
*get_viewer_for_mimeinfo(MimeView
*mimeview
, MimeInfo
*partinfo
)
574 gchar
*content_type
= NULL
;
575 MimeViewer
*viewer
= NULL
;
577 if ((partinfo
->type
== MIMETYPE_APPLICATION
) &&
578 (!g_ascii_strcasecmp(partinfo
->subtype
, "octet-stream"))) {
579 const gchar
*filename
;
581 filename
= procmime_mimeinfo_get_parameter(partinfo
, "filename");
582 if (filename
== NULL
)
583 filename
= procmime_mimeinfo_get_parameter(partinfo
, "name");
584 if (filename
!= NULL
)
585 content_type
= procmime_get_mime_type(filename
);
587 content_type
= procmime_get_content_type_str(partinfo
->type
, partinfo
->subtype
);
590 if (content_type
!= NULL
) {
591 viewer
= get_viewer_for_content_type(mimeview
, content_type
);
592 g_free(content_type
);
598 gboolean
mimeview_show_part(MimeView
*mimeview
, MimeInfo
*partinfo
)
602 viewer
= get_viewer_for_mimeinfo(mimeview
, partinfo
);
603 if (viewer
== NULL
) {
604 if (mimeview
->mimeviewer
!= NULL
)
605 mimeview
->mimeviewer
->clear_viewer(mimeview
->mimeviewer
);
606 mimeview
->mimeviewer
= NULL
;
610 if (mimeview
->mimeviewer
!= NULL
)
611 mimeview
->mimeviewer
->clear_viewer(mimeview
->mimeviewer
);
613 if (mimeview
->mimeviewer
!= viewer
) {
614 mimeview
->mimeviewer
= viewer
;
615 mimeview_change_view_type(mimeview
, MIMEVIEW_VIEWER
);
617 viewer
->mimeview
= mimeview
;
618 viewer
->show_mimepart(viewer
, mimeview
->file
, partinfo
);
623 static void mimeview_change_view_type(MimeView
*mimeview
, MimeViewType type
)
625 TextView
*textview
= mimeview
->textview
;
627 if ((mimeview
->type
!= MIMEVIEW_VIEWER
) &&
628 (mimeview
->type
== type
)) return;
632 gtk_notebook_set_current_page(GTK_NOTEBOOK(mimeview
->mime_notebook
),
633 gtk_notebook_page_num(GTK_NOTEBOOK(mimeview
->mime_notebook
),
634 GTK_WIDGET_PTR(textview
)));
636 case MIMEVIEW_VIEWER
:
637 gtk_notebook_set_current_page(GTK_NOTEBOOK(mimeview
->mime_notebook
),
638 gtk_notebook_page_num(GTK_NOTEBOOK(mimeview
->mime_notebook
),
639 GTK_WIDGET(mimeview
->mimeviewer
->get_widget(mimeview
->mimeviewer
))));
645 mimeview
->type
= type
;
648 void mimeview_clear(MimeView
*mimeview
)
650 GtkCList
*clist
= NULL
;
655 if (g_slist_find(mimeviews
, mimeview
) == NULL
)
658 clist
= GTK_CLIST(mimeview
->ctree
);
660 noticeview_hide(mimeview
->siginfoview
);
662 gtk_clist_clear(clist
);
663 textview_clear(mimeview
->textview
);
664 if (mimeview
->mimeviewer
!= NULL
)
665 mimeview
->mimeviewer
->clear_viewer(mimeview
->mimeviewer
);
667 mimeview_free_mimeinfo(mimeview
);
669 mimeview
->mimeinfo
= NULL
;
671 mimeview
->opened
= NULL
;
673 g_free(mimeview
->file
);
674 mimeview
->file
= NULL
;
676 icon_list_clear(mimeview
);
677 mimeview_change_view_type(mimeview
, MIMEVIEW_TEXT
);
680 static void check_signature_cb(GtkWidget
*widget
, gpointer user_data
);
681 void mimeview_check_signature(MimeView
*mimeview
);
682 static void display_full_info_cb(GtkWidget
*widget
, gpointer user_data
);
684 static void update_signature_noticeview(MimeView
*mimeview
, MimeInfo
*mimeinfo
,
685 gboolean special
, SignatureStatus code
)
687 gchar
*text
= NULL
, *button_text
= NULL
;
689 StockPixmap icon
= STOCK_PIXMAP_PRIVACY_SIGNED
;
690 SignatureStatus mycode
= SIGNATURE_UNCHECKED
;
692 g_return_if_fail(mimeview
!= NULL
);
693 g_return_if_fail(mimeinfo
!= NULL
);
698 mycode
= privacy_mimeinfo_get_sig_status(mimeinfo
);
701 case SIGNATURE_UNCHECKED
:
702 button_text
= _("Check signature");
703 func
= check_signature_cb
;
704 icon
= STOCK_PIXMAP_PRIVACY_SIGNED
;
707 button_text
= _("View full information");
708 func
= display_full_info_cb
;
709 icon
= STOCK_PIXMAP_PRIVACY_PASSED
;
712 button_text
= _("View full information");
713 func
= display_full_info_cb
;
714 icon
= STOCK_PIXMAP_PRIVACY_WARN
;
716 case SIGNATURE_INVALID
:
717 button_text
= _("View full information");
718 func
= display_full_info_cb
;
719 icon
= STOCK_PIXMAP_PRIVACY_FAILED
;
721 case SIGNATURE_CHECK_FAILED
:
722 button_text
= _("Check again");
723 func
= check_signature_cb
;
724 icon
= STOCK_PIXMAP_PRIVACY_UNKNOWN
;
725 case SIGNATURE_CHECK_TIMEOUT
:
726 button_text
= _("Check again");
727 func
= check_signature_cb
;
728 icon
= STOCK_PIXMAP_PRIVACY_UNKNOWN
;
732 if (mycode
== SIGNATURE_UNCHECKED
) {
733 gchar
*tmp
= privacy_mimeinfo_sig_info_short(mimeinfo
);
734 text
= g_strdup_printf("%s %s",
735 tmp
, _("Click the icon or hit 'C' to check it."));
737 } else if (mycode
!= SIGNATURE_CHECK_TIMEOUT
) {
738 text
= privacy_mimeinfo_sig_info_short(mimeinfo
);
739 } else if (mycode
== SIGNATURE_CHECK_TIMEOUT
) {
740 text
= g_strdup(_("Timeout checking the signature. Click the icon or hit 'C' to try again."));
743 noticeview_set_text(mimeview
->siginfoview
, text
);
744 gtk_label_set_selectable(GTK_LABEL(mimeview
->siginfoview
->text
), TRUE
);
747 noticeview_set_button_text(mimeview
->siginfoview
, NULL
);
748 noticeview_set_button_press_callback(
749 mimeview
->siginfoview
,
751 (gpointer
) mimeview
);
752 noticeview_set_icon(mimeview
->siginfoview
, icon
);
753 noticeview_set_tooltip(mimeview
->siginfoview
, button_text
);
758 /* reset all thread stuff, and do the cleanups we've been left to do */
759 static void mimeview_check_data_reset(MimeView
*mimeview
)
761 if (!mimeview
->check_data
)
764 if (mimeview
->check_data
->free_after_use
) {
765 debug_print("freeing deferred mimeinfo\n");
766 procmime_mimeinfo_free_all(mimeview
->check_data
->siginfo
);
768 if (mimeview
->check_data
->destroy_mimeview
) {
769 debug_print("freeing deferred mimeview\n");
770 g_free(mimeview
->file
);
772 mimeviews
= g_slist_remove(mimeviews
, mimeview
);
775 g_free(mimeview
->check_data
);
776 mimeview
->check_data
= NULL
;
779 /* GUI update once the checker thread is done or killed */
780 static gboolean
mimeview_check_sig_thread_cb(void *data
)
782 MimeView
*mimeview
= (MimeView
*) data
;
783 MimeInfo
*mimeinfo
= mimeview
->siginfo
;
785 debug_print("mimeview_check_sig_thread_cb\n");
787 if (mimeinfo
== NULL
) {
788 /* message changed !? */
789 g_warning("no more siginfo!\n");
793 if (!mimeview
->check_data
) {
794 g_warning("nothing to check\n");
798 if (mimeview
->check_data
->siginfo
!= mimeinfo
) {
799 /* message changed !? */
800 g_warning("different siginfo!\n");
804 if (mimeview
->check_data
->destroy_mimeview
||
805 mimeview
->check_data
->free_after_use
) {
806 debug_print("not bothering, we're changing message\n");
811 if (mimeview
->check_data
->timeout
)
812 update_signature_noticeview(mimeview
, mimeview
->siginfo
,
813 TRUE
, SIGNATURE_CHECK_TIMEOUT
);
815 update_signature_noticeview(mimeview
, mimeview
->siginfo
,
817 icon_list_clear(mimeview
);
818 icon_list_create(mimeview
, mimeview
->mimeinfo
);
821 mimeview_check_data_reset(mimeview
);
825 /* sig checker thread */
826 static void *mimeview_check_sig_worker_thread(void *data
)
828 MimeView
*mimeview
= (MimeView
*)data
;
829 MimeInfo
*mimeinfo
= mimeview
->siginfo
;
831 debug_print("checking...\n");
833 if (!mimeview
->check_data
)
836 if (mimeinfo
&& mimeinfo
== mimeview
->check_data
->siginfo
)
837 privacy_mimeinfo_check_signature(mimeinfo
);
839 /* that's strange! we changed message without
841 g_warning("different siginfo!\n");
842 mimeview_check_data_reset(mimeview
);
846 /* use g_timeout so that GUI updates is done from the
848 g_timeout_add(0,mimeview_check_sig_thread_cb
,mimeview
);
853 /* killer thread - acts when the checker didn't work fast
855 static void *mimeview_check_sig_cancel_thread(void *data
)
857 MimeView
*mimeview
= (MimeView
*)data
;
859 if (!mimeview
->check_data
)
860 return NULL
; /* nothing to kill ! */
862 /* wait for a few seconds... */
863 debug_print("waiting a while\n");
867 if (!mimeview
->check_data
)
868 return NULL
; /* nothing to kill, it's done in time :) */
870 /* too late, go away checker thread */
871 debug_print("killing checker thread\n");
872 pthread_cancel(mimeview
->check_data
->th
);
874 /* tell upstream it was a timeout */
875 mimeview
->check_data
->timeout
= TRUE
;
876 /* use g_timeout so that GUI updates is done from the
878 g_timeout_add(0,mimeview_check_sig_thread_cb
,mimeview
);
883 /* get rid of the checker thread right now - used when changing the
884 * displayed message for example. */
885 static void mimeview_check_sig_cancel_now(MimeView
*mimeview
)
887 if (!mimeview
->check_data
)
889 debug_print("killing checker thread NOW\n");
890 pthread_cancel(mimeview
->check_data
->th
);
892 /* tell upstream it was a timeout */
893 mimeview
->check_data
->timeout
= TRUE
;
894 mimeview_check_sig_thread_cb(mimeview
);
898 /* creates a thread to check the signature, and a second one
899 * to kill the first one after a timeout */
900 static void mimeview_check_sig_in_thread(MimeView
*mimeview
)
903 pthread_attr_t detach
, detach2
;
905 if (mimeview
->check_data
) {
906 g_warning("already checking it");
910 mimeview
->check_data
= g_new0(SigCheckData
, 1);
911 mimeview
->check_data
->siginfo
= mimeview
->siginfo
;
912 debug_print("creating thread\n");
914 pthread_attr_init(&detach
);
915 pthread_attr_setdetachstate(&detach
, TRUE
);
917 pthread_attr_init(&detach2
);
918 pthread_attr_setdetachstate(&detach2
, TRUE
);
920 /* create the checker thread */
921 if (pthread_create(&th
, &detach
,
922 mimeview_check_sig_worker_thread
,
924 /* arh. We'll do it synchronously. */
925 g_warning("can't create thread");
926 g_free(mimeview
->check_data
);
927 mimeview
->check_data
= NULL
;
930 mimeview
->check_data
->th
= th
;
932 /* create the killer thread */
933 pthread_create(&th2
, &detach2
,
934 mimeview_check_sig_cancel_thread
,
939 static void check_signature_cb(GtkWidget
*widget
, gpointer user_data
)
941 MimeView
*mimeview
= (MimeView
*) user_data
;
942 MimeInfo
*mimeinfo
= mimeview
->siginfo
;
944 if (mimeinfo
== NULL
)
947 if (mimeview
->check_data
)
950 noticeview_set_text(mimeview
->siginfoview
, _("Checking signature..."));
952 #if (defined USE_PTHREAD && defined __GLIBC__ && (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 3)))
953 /* let's do it non-blocking */
954 mimeview_check_sig_in_thread(mimeview
);
955 if (!mimeview
->check_data
) /* let's check syncronously */
958 debug_print("checking without thread\n");
959 privacy_mimeinfo_check_signature(mimeinfo
);
960 update_signature_noticeview(mimeview
, mimeview
->siginfo
, FALSE
, 0);
961 icon_list_clear(mimeview
);
962 icon_list_create(mimeview
, mimeview
->mimeinfo
);
966 void mimeview_check_signature(MimeView
*mimeview
)
968 check_signature_cb(NULL
, mimeview
);
971 static void redisplay_email(GtkWidget
*widget
, gpointer user_data
)
973 MimeView
*mimeview
= (MimeView
*) user_data
;
974 GtkCTreeNode
*node
= mimeview
->opened
;
975 mimeview
->opened
= NULL
;
976 mimeview_selected(GTK_CTREE(mimeview
->ctree
), node
, 0, mimeview
);
979 static void display_full_info_cb(GtkWidget
*widget
, gpointer user_data
)
981 MimeView
*mimeview
= (MimeView
*) user_data
;
984 siginfo
= privacy_mimeinfo_sig_info_full(mimeview
->siginfo
);
985 textview_set_text(mimeview
->textview
, siginfo
);
987 noticeview_set_button_text(mimeview
->siginfoview
, NULL
);
988 noticeview_set_button_press_callback(
989 mimeview
->siginfoview
,
990 G_CALLBACK(redisplay_email
),
991 (gpointer
) mimeview
);
992 noticeview_set_tooltip(mimeview
->siginfoview
, _("Go back to email"));
995 static void update_signature_info(MimeView
*mimeview
, MimeInfo
*selected
)
998 MimeInfo
*first_text
;
1000 g_return_if_fail(mimeview
!= NULL
);
1001 g_return_if_fail(selected
!= NULL
);
1003 if (selected
->type
== MIMETYPE_MESSAGE
1004 && !g_ascii_strcasecmp(selected
->subtype
, "rfc822")) {
1005 /* if the first text part is signed, check that */
1006 first_text
= selected
;
1007 while (first_text
&& first_text
->type
!= MIMETYPE_TEXT
) {
1008 first_text
= procmime_mimeinfo_next(first_text
);
1011 update_signature_info(mimeview
, first_text
);
1017 while (siginfo
!= NULL
) {
1018 if (privacy_mimeinfo_is_signed(siginfo
))
1020 siginfo
= procmime_mimeinfo_parent(siginfo
);
1022 mimeview
->siginfo
= siginfo
;
1024 if (siginfo
== NULL
) {
1025 noticeview_hide(mimeview
->siginfoview
);
1029 update_signature_noticeview(mimeview
, siginfo
, FALSE
, 0);
1030 noticeview_show(mimeview
->siginfoview
);
1033 static void mimeview_selected(GtkCTree
*ctree
, GtkCTreeNode
*node
, gint column
,
1037 if (mimeview
->opened
== node
) return;
1038 mimeview
->opened
= node
;
1039 mimeview
->spec_part
= NULL
;
1040 gtk_ctree_node_moveto(ctree
, node
, -1, 0.5, 0);
1042 partinfo
= gtk_ctree_node_get_row_data(ctree
, node
);
1043 if (!partinfo
) return;
1045 /* ungrab the mouse event */
1046 if (GTK_WIDGET_HAS_GRAB(ctree
)) {
1047 gtk_grab_remove(GTK_WIDGET(ctree
));
1048 if (gdk_pointer_is_grabbed())
1049 gdk_pointer_ungrab(GDK_CURRENT_TIME
);
1052 mimeview
->textview
->default_text
= FALSE
;
1054 update_signature_info(mimeview
, partinfo
);
1056 if (!mimeview_show_part(mimeview
, partinfo
)) {
1057 switch (partinfo
->type
) {
1059 case MIMETYPE_MESSAGE
:
1060 case MIMETYPE_MULTIPART
:
1061 mimeview_show_message_part(mimeview
, partinfo
);
1065 mimeview
->textview
->default_text
= TRUE
;
1066 mimeview_change_view_type(mimeview
, MIMEVIEW_TEXT
);
1067 textview_clear(mimeview
->textview
);
1068 textview_show_mime_part(mimeview
->textview
, partinfo
);
1074 static void mimeview_start_drag(GtkWidget
*widget
, gint button
,
1075 GdkEvent
*event
, MimeView
*mimeview
)
1077 GdkDragContext
*context
;
1080 g_return_if_fail(mimeview
!= NULL
);
1082 partinfo
= mimeview_get_selected_part(mimeview
);
1083 if (partinfo
->disposition
== DISPOSITIONTYPE_INLINE
) return;
1085 context
= gtk_drag_begin(widget
, mimeview
->target_list
,
1086 GDK_ACTION_COPY
, button
, event
);
1087 gtk_drag_set_icon_default(context
);
1090 static gint
mimeview_button_pressed(GtkWidget
*widget
, GdkEventButton
*event
,
1093 GtkCList
*clist
= GTK_CLIST(widget
);
1096 if (!event
) return FALSE
;
1098 if (event
->button
== 2 || event
->button
== 3) {
1099 if (!gtk_clist_get_selection_info(clist
, event
->x
, event
->y
,
1102 gtk_clist_unselect_all(clist
);
1103 gtk_clist_select_row(clist
, row
, column
);
1104 gtkut_clist_set_focus_row(clist
, row
);
1106 part_button_pressed(mimeview
, event
, mimeview_get_selected_part(mimeview
));
1111 /* from gdkevents.c */
1112 #define DOUBLE_CLICK_TIME 250
1114 static gboolean
part_button_pressed(MimeView
*mimeview
, GdkEventButton
*event
,
1117 static MimeInfo
*lastinfo
;
1118 static guint32 lasttime
;
1120 if (event
->button
== 2 ||
1121 (event
->button
== 1 && (event
->time
- lasttime
) < DOUBLE_CLICK_TIME
&& lastinfo
== partinfo
)) {
1122 /* call external program for image, audio or html */
1123 mimeview_launch(mimeview
);
1125 } else if (event
->button
== 3) {
1126 if (partinfo
&& (partinfo
->type
== MIMETYPE_MESSAGE
||
1127 partinfo
->type
== MIMETYPE_IMAGE
||
1128 partinfo
->type
== MIMETYPE_MULTIPART
))
1129 menu_set_sensitive(mimeview
->popupfactory
,
1130 "/Display as text", FALSE
);
1132 menu_set_sensitive(mimeview
->popupfactory
,
1133 "/Display as text", TRUE
);
1135 partinfo
->type
== MIMETYPE_APPLICATION
&&
1136 !g_ascii_strcasecmp(partinfo
->subtype
, "octet-stream"))
1137 menu_set_sensitive(mimeview
->popupfactory
,
1140 menu_set_sensitive(mimeview
->popupfactory
,
1143 g_object_set_data(G_OBJECT(mimeview
->popupmenu
),
1144 "pop_partinfo", partinfo
);
1146 gtk_menu_popup(GTK_MENU(mimeview
->popupmenu
),
1147 NULL
, NULL
, NULL
, NULL
,
1148 event
->button
, event
->time
);
1152 lastinfo
= partinfo
;
1153 lasttime
= event
->time
;
1158 void mimeview_pass_key_press_event(MimeView
*mimeview
, GdkEventKey
*event
)
1160 mimeview_key_pressed(mimeview
->ctree
, event
, mimeview
);
1163 #define BREAK_ON_MODIFIER_KEY() \
1164 if ((event->state & (GDK_MOD1_MASK|GDK_CONTROL_MASK)) != 0) break
1166 #define KEY_PRESS_EVENT_STOP() \
1167 g_signal_stop_emission_by_name(G_OBJECT(ctree), \
1170 static gint
mimeview_key_pressed(GtkWidget
*widget
, GdkEventKey
*event
,
1173 SummaryView
*summaryview
;
1174 GtkCTree
*ctree
= GTK_CTREE(widget
);
1177 if (!event
) return FALSE
;
1178 if (!mimeview
->opened
) return FALSE
;
1180 summaryview
= mimeview
->messageview
->mainwin
->summaryview
;
1182 if (summaryview
&& quicksearch_has_focus(summaryview
->quicksearch
))
1185 switch (event
->keyval
) {
1187 if (textview_scroll_page(mimeview
->textview
, FALSE
))
1190 node
= GTK_CTREE_NODE_NEXT(mimeview
->opened
);
1192 gtk_sctree_unselect_all(GTK_SCTREE(ctree
));
1193 gtk_sctree_select(GTK_SCTREE(ctree
), node
);
1198 textview_scroll_page(mimeview
->textview
, TRUE
);
1201 textview_scroll_one_line(mimeview
->textview
,
1202 (event
->state
& GDK_MOD1_MASK
) != 0);
1206 BREAK_ON_MODIFIER_KEY();
1207 if (!GTK_CTREE_NODE_NEXT(mimeview
->opened
)) break;
1208 KEY_PRESS_EVENT_STOP();
1209 g_signal_emit_by_name(G_OBJECT(ctree
), "scroll_vertical",
1210 GTK_SCROLL_STEP_FORWARD
, 0.0);
1214 BREAK_ON_MODIFIER_KEY();
1215 if (!GTK_CTREE_NODE_PREV(mimeview
->opened
)) break;
1216 KEY_PRESS_EVENT_STOP();
1217 g_signal_emit_by_name(G_OBJECT(ctree
), "scroll_vertical",
1218 GTK_SCROLL_STEP_BACKWARD
, 0.0);
1221 BREAK_ON_MODIFIER_KEY();
1222 KEY_PRESS_EVENT_STOP();
1223 mimeview_save_as(mimeview
);
1226 BREAK_ON_MODIFIER_KEY();
1227 KEY_PRESS_EVENT_STOP();
1228 mimeview_display_as_text(mimeview
);
1231 BREAK_ON_MODIFIER_KEY();
1232 KEY_PRESS_EVENT_STOP();
1233 mimeview_launch(mimeview
);
1236 BREAK_ON_MODIFIER_KEY();
1237 KEY_PRESS_EVENT_STOP();
1238 mimeview_open_with(mimeview
);
1241 BREAK_ON_MODIFIER_KEY();
1242 KEY_PRESS_EVENT_STOP();
1243 mimeview_check_signature(mimeview
);
1249 if (!mimeview
->messageview
->mainwin
) return FALSE
;
1251 summary_pass_key_press_event(summaryview
, event
);
1255 static void mimeview_drag_data_get(GtkWidget
*widget
,
1256 GdkDragContext
*drag_context
,
1257 GtkSelectionData
*selection_data
,
1262 gchar
*filename
= NULL
, *uriname
, *tmp
;
1265 if (!mimeview
->opened
) return;
1266 if (!mimeview
->file
) return;
1268 partinfo
= mimeview_get_selected_part(mimeview
);
1269 if (!partinfo
) return;
1271 if (strlen(get_part_name(partinfo
)) > 0) {
1272 filename
= g_path_get_basename(get_part_name(partinfo
));
1273 if (*filename
== '\0') return;
1274 } else if (partinfo
->type
== MIMETYPE_MESSAGE
1275 && !g_ascii_strcasecmp(partinfo
->subtype
, "rfc822")) {
1277 GPtrArray
*headers
= NULL
;
1280 fp
= g_fopen(partinfo
->data
.filename
, "rb");
1281 fseek(fp
, partinfo
->offset
, SEEK_SET
);
1282 headers
= procheader_get_header_array_asis(fp
);
1285 for (i
= 0; i
< headers
->len
; i
++) {
1286 Header
*header
= g_ptr_array_index(headers
, i
);
1287 if (procheader_headername_equal(header
->name
, "Subject")) {
1288 unfold_line(header
->body
);
1289 name
= g_strconcat(header
->body
, ".txt", NULL
);
1290 subst_for_filename(name
);
1293 procheader_header_array_destroy(headers
);
1297 filename
= g_path_get_basename(name
);
1300 if (filename
== NULL
)
1301 filename
= g_path_get_basename("Unnamed part");
1304 tmp
= g_filename_from_utf8(filename
, -1, NULL
, NULL
, NULL
);
1307 g_warning("filename not in UTF-8");
1308 tmp
= g_strdup("Unnamed part");
1310 filename
= g_strconcat(get_mime_tmp_dir(), G_DIR_SEPARATOR_S
,
1315 if (procmime_get_part(filename
, partinfo
) < 0)
1317 (_("Can't save the part of multipart message."));
1318 uriname
= g_strconcat("file://", filename
, "\r\n", NULL
);
1320 gtk_selection_data_set(selection_data
, selection_data
->target
, 8,
1321 (guchar
*)uriname
, strlen(uriname
));
1328 * Returns a filename (with path) for an attachment
1329 * \param partinfo The attachment to save
1330 * \param basedir The target directory
1331 * \param number Used for dummy filename if attachment is unnamed
1333 gchar
*mimeview_get_filename_for_part(MimeInfo
*partinfo
,
1334 const gchar
*basedir
,
1340 filename
= g_strdup(get_part_name(partinfo
));
1341 if (!filename
|| !*filename
)
1342 filename
= g_strdup_printf("noname.%d", number
);
1344 if (!g_utf8_validate(filename
, -1, NULL
)) {
1345 gchar
*tmp
= conv_filename_to_utf8(filename
);
1350 subst_for_filename(filename
);
1352 fullname
= g_strconcat
1353 (basedir
, G_DIR_SEPARATOR_S
, (filename
[0] == G_DIR_SEPARATOR
)
1354 ? &filename
[1] : filename
, NULL
);
1357 filename
= conv_filename_from_utf8(fullname
);
1363 * Write a single attachment to file
1364 * \param filename Filename with path
1365 * \param partinfo Attachment to save
1367 static gboolean
mimeview_write_part(const gchar
*filename
,
1372 dir
= g_path_get_dirname(filename
);
1373 if (!is_dir_exist(dir
))
1377 if (is_file_exist(filename
)) {
1382 if (!g_utf8_validate(filename
, -1, NULL
))
1383 tmp
= conv_filename_to_utf8(filename
);
1385 tmp
= g_strdup(filename
);
1387 res
= g_strdup_printf(_("Overwrite existing file '%s'?"),
1390 aval
= alertpanel(_("Overwrite"), res
, GTK_STOCK_CANCEL
,
1391 GTK_STOCK_OK
, NULL
);
1393 if (G_ALERTALTERNATE
!= aval
) return FALSE
;
1396 if (procmime_get_part(filename
, partinfo
) < 0) {
1398 (_("Can't save the part of multipart message."));
1406 * Menu callback: Save all attached files
1407 * \param mimeview Current display
1409 static void mimeview_save_all(MimeView
*mimeview
)
1413 gchar
*startdir
= NULL
;
1416 if (!mimeview
->opened
) return;
1417 if (!mimeview
->file
) return;
1418 if (!mimeview
->mimeinfo
) return;
1420 partinfo
= mimeview
->mimeinfo
;
1421 if (prefs_common
.attach_save_dir
)
1422 startdir
= g_strconcat(prefs_common
.attach_save_dir
,
1423 G_DIR_SEPARATOR_S
, NULL
);
1425 dirname
= filesel_select_file_save_folder(_("Select destination folder"), startdir
);
1431 if (!is_dir_exist (dirname
)) {
1432 alertpanel_error(_("'%s' is not a directory."),
1438 if (dirname
[strlen(dirname
)-1] == G_DIR_SEPARATOR
)
1439 dirname
[strlen(dirname
)-1] = '\0';
1441 /* Skip the first part, that is sometimes DISPOSITIONTYPE_UNKNOWN */
1442 if (partinfo
&& partinfo
->type
== MIMETYPE_MESSAGE
)
1443 partinfo
= procmime_mimeinfo_next(partinfo
);
1444 if (partinfo
&& partinfo
->type
== MIMETYPE_MULTIPART
) {
1445 partinfo
= procmime_mimeinfo_next(partinfo
);
1446 if (partinfo
&& partinfo
->type
== MIMETYPE_TEXT
)
1447 partinfo
= procmime_mimeinfo_next(partinfo
);
1450 while (partinfo
!= NULL
) {
1451 if (partinfo
->type
!= MIMETYPE_MESSAGE
&&
1452 partinfo
->type
!= MIMETYPE_MULTIPART
&&
1453 (partinfo
->disposition
!= DISPOSITIONTYPE_INLINE
1454 || get_real_part_name(partinfo
) != NULL
)) {
1455 gchar
*filename
= mimeview_get_filename_for_part
1456 (partinfo
, dirname
, number
++);
1458 mimeview_write_part(filename
, partinfo
);
1461 partinfo
= procmime_mimeinfo_next(partinfo
);
1464 g_free(prefs_common
.attach_save_dir
);
1466 prefs_common
.attach_save_dir
= g_strdup(dirname
);
1469 static MimeInfo
*mimeview_get_part_to_use(MimeView
*mimeview
)
1471 MimeInfo
*partinfo
= NULL
;
1472 if (mimeview
->spec_part
) {
1473 partinfo
= mimeview
->spec_part
;
1474 mimeview
->spec_part
= NULL
;
1476 partinfo
= mimeview_get_selected_part(mimeview
);
1478 partinfo
= (MimeInfo
*) g_object_get_data
1479 (G_OBJECT(mimeview
->popupmenu
),
1481 g_object_set_data(G_OBJECT(mimeview
->popupmenu
),
1482 "pop_partinfo", NULL
);
1489 * Menu callback: Save the selected attachment
1490 * \param mimeview Current display
1492 static void mimeview_save_as(MimeView
*mimeview
)
1495 gchar
*filepath
= NULL
;
1496 gchar
*filedir
= NULL
;
1498 gchar
*partname
= NULL
;
1500 if (!mimeview
->opened
) return;
1501 if (!mimeview
->file
) return;
1503 partinfo
= mimeview_get_part_to_use(mimeview
);
1505 g_return_if_fail(partinfo
!= NULL
);
1507 if (get_part_name(partinfo
) == NULL
) {
1510 partname
= g_strdup(get_part_name(partinfo
));
1512 if (!g_utf8_validate(partname
, -1, NULL
)) {
1513 gchar
*tmp
= conv_filename_to_utf8(partname
);
1518 subst_for_filename(partname
);
1520 if (prefs_common
.attach_save_dir
)
1521 filepath
= g_strconcat(prefs_common
.attach_save_dir
,
1522 G_DIR_SEPARATOR_S
, partname
, NULL
);
1524 filepath
= g_strdup(partname
);
1528 filename
= filesel_select_file_save(_("Save as"), filepath
);
1534 mimeview_write_part(filename
, partinfo
);
1536 filedir
= g_path_get_dirname(filename
);
1537 if (filedir
&& strcmp(filedir
, ".")) {
1538 g_free(prefs_common
.attach_save_dir
);
1539 prefs_common
.attach_save_dir
= g_strdup(filedir
);
1546 static void mimeview_display_as_text(MimeView
*mimeview
)
1550 if (!mimeview
->opened
) return;
1552 partinfo
= mimeview_get_part_to_use(mimeview
);
1554 g_return_if_fail(partinfo
!= NULL
);
1555 mimeview_show_message_part(mimeview
, partinfo
);
1558 static void mimeview_launch(MimeView
*mimeview
)
1563 if (!mimeview
->opened
) return;
1564 if (!mimeview
->file
) return;
1566 partinfo
= mimeview_get_part_to_use(mimeview
);
1568 g_return_if_fail(partinfo
!= NULL
);
1570 filename
= procmime_get_tmp_file_name(partinfo
);
1572 if (procmime_get_part(filename
, partinfo
) < 0)
1574 (_("Can't save the part of multipart message."));
1576 mimeview_view_file(filename
, partinfo
, NULL
, mimeview
);
1581 static void mimeview_open_with(MimeView
*mimeview
)
1585 if (!mimeview
) return;
1586 if (!mimeview
->opened
) return;
1587 if (!mimeview
->file
) return;
1589 partinfo
= mimeview_get_part_to_use(mimeview
);
1591 mimeview_open_part_with(mimeview
, partinfo
);
1594 static void mimeview_open_part_with(MimeView
*mimeview
, MimeInfo
*partinfo
)
1598 gchar
*mime_command
= NULL
;
1599 gchar
*content_type
= NULL
;
1601 g_return_if_fail(partinfo
!= NULL
);
1603 filename
= procmime_get_tmp_file_name(partinfo
);
1605 if (procmime_get_part(filename
, partinfo
) < 0) {
1607 (_("Can't save the part of multipart message."));
1612 if (!prefs_common
.mime_open_cmd_history
)
1613 prefs_common
.mime_open_cmd_history
=
1614 add_history(NULL
, prefs_common
.mime_open_cmd
);
1616 if ((partinfo
->type
== MIMETYPE_APPLICATION
) &&
1617 (!g_ascii_strcasecmp(partinfo
->subtype
, "octet-stream"))) {
1618 /* guess content-type from filename */
1619 content_type
= procmime_get_mime_type(filename
);
1621 if (content_type
== NULL
) {
1622 content_type
= procmime_get_content_type_str(partinfo
->type
,
1625 mime_command
= mailcap_get_command_for_type(content_type
);
1627 if (mime_command
== NULL
) {
1628 /* try with extension this time */
1629 g_free(content_type
);
1630 content_type
= procmime_get_mime_type(filename
);
1631 mime_command
= mailcap_get_command_for_type(content_type
);
1634 g_free(content_type
);
1635 cmd
= input_dialog_combo
1637 _("Enter the command line to open file:\n"
1638 "('%s' will be replaced with file name)"),
1639 mime_command
? mime_command
: prefs_common
.mime_open_cmd
,
1640 prefs_common
.mime_open_cmd_history
,
1642 g_free(mime_command
);
1644 mimeview_view_file(filename
, partinfo
, cmd
, mimeview
);
1645 g_free(prefs_common
.mime_open_cmd
);
1646 prefs_common
.mime_open_cmd
= cmd
;
1647 prefs_common
.mime_open_cmd_history
=
1648 add_history(prefs_common
.mime_open_cmd_history
, cmd
);
1654 static void mimeview_view_file(const gchar
*filename
, MimeInfo
*partinfo
,
1655 const gchar
*cmdline
, MimeView
*mimeview
)
1657 static gchar
*default_image_cmdline
= DEFAULT_IMAGE_VIEWER_CMD
;
1658 static gchar
*default_audio_cmdline
= DEFAULT_AUDIO_PLAYER_CMD
;
1659 static gchar
*default_html_cmdline
= DEFAULT_BROWSER_CMD
;
1660 static gchar
*mime_cmdline
= DEFAULT_MIME_CMD
;
1664 const gchar
*def_cmd
;
1670 } else if (MIMETYPE_APPLICATION
== partinfo
->type
&&
1671 !g_ascii_strcasecmp(partinfo
->subtype
, "octet-stream")) {
1672 mimeview_open_part_with(mimeview
, partinfo
);
1674 } else if (MIMETYPE_IMAGE
== partinfo
->type
) {
1675 cmd
= prefs_common
.mime_image_viewer
;
1676 def_cmd
= default_image_cmdline
;
1677 } else if (MIMETYPE_AUDIO
== partinfo
->type
) {
1678 cmd
= prefs_common
.mime_audio_player
;
1679 def_cmd
= default_audio_cmdline
;
1680 } else if (MIMETYPE_TEXT
== partinfo
->type
&& !strcmp(partinfo
->subtype
, "html")) {
1681 cmd
= prefs_common
.uri_cmd
;
1682 def_cmd
= default_html_cmdline
;
1684 gchar
*content_type
;
1686 content_type
= procmime_get_content_type_str(partinfo
->type
, partinfo
->subtype
);
1687 g_snprintf(m_buf
, sizeof(m_buf
), mime_cmdline
,
1688 content_type
, "%s");
1689 g_free(content_type
);
1694 if (cmd
&& (p
= strchr(cmd
, '%')) && *(p
+ 1) == 's' &&
1695 !strchr(p
+ 2, '%'))
1696 g_snprintf(buf
, sizeof(buf
), cmd
, filename
);
1699 g_warning("MIME viewer command line is invalid: '%s'", cmd
);
1701 g_snprintf(buf
, sizeof(buf
), def_cmd
, filename
);
1703 mimeview_open_part_with(mimeview
, partinfo
);
1708 if (execute_command_line(buf
, TRUE
) != 0)
1709 mimeview_open_part_with(mimeview
, partinfo
);
1712 void mimeview_register_viewer_factory(MimeViewerFactory
*factory
)
1714 mimeviewer_factories
= g_slist_append(mimeviewer_factories
, factory
);
1717 static gint
cmp_viewer_by_factroy(gconstpointer a
, gconstpointer b
)
1719 return ((MimeViewer
*) a
)->factory
== (MimeViewerFactory
*) b
? 0 : -1;
1722 void mimeview_unregister_viewer_factory(MimeViewerFactory
*factory
)
1724 GSList
*mimeview_list
, *viewer_list
;
1726 for (mimeview_list
= mimeviews
; mimeview_list
!= NULL
; mimeview_list
= g_slist_next(mimeview_list
)) {
1727 MimeView
*mimeview
= (MimeView
*) mimeview_list
->data
;
1729 if (mimeview
->mimeviewer
&& mimeview
->mimeviewer
->factory
== factory
) {
1730 mimeview_change_view_type(mimeview
, MIMEVIEW_TEXT
);
1731 mimeview
->mimeviewer
= NULL
;
1734 while ((viewer_list
= g_slist_find_custom(mimeview
->viewers
, factory
, cmp_viewer_by_factroy
)) != NULL
) {
1735 MimeViewer
*mimeviewer
= (MimeViewer
*) viewer_list
->data
;
1737 mimeviewer
->destroy_viewer(mimeviewer
);
1738 mimeview
->viewers
= g_slist_remove(mimeview
->viewers
, mimeviewer
);
1742 mimeviewer_factories
= g_slist_remove(mimeviewer_factories
, factory
);
1745 static gboolean
icon_clicked_cb (GtkWidget
*button
, GdkEventButton
*event
, MimeView
*mimeview
)
1750 num
= GPOINTER_TO_INT(g_object_get_data(G_OBJECT(button
), "icon_number"));
1751 partinfo
= g_object_get_data(G_OBJECT(button
), "partinfo");
1753 icon_selected(mimeview
, num
, partinfo
);
1754 gtk_widget_grab_focus(button
);
1755 if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button
))) {
1756 toggle_icon(GTK_TOGGLE_BUTTON(button
), mimeview
);
1757 if (event
->button
== 2 || event
->button
== 3)
1758 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button
),
1762 part_button_pressed(mimeview
, event
, partinfo
);
1767 static void icon_selected (MimeView
*mimeview
, gint num
, MimeInfo
*partinfo
)
1770 node
= gtk_ctree_find_by_row_data(GTK_CTREE(mimeview
->ctree
), NULL
, partinfo
);
1772 gtk_ctree_select(GTK_CTREE(mimeview
->ctree
), node
);
1775 #undef KEY_PRESS_EVENT_STOP
1776 #define KEY_PRESS_EVENT_STOP() \
1777 g_signal_stop_emission_by_name(G_OBJECT(button), \
1780 static gint
icon_key_pressed(GtkWidget
*button
, GdkEventKey
*event
,
1785 SummaryView
*summaryview
;
1788 num
= GPOINTER_TO_INT(g_object_get_data(G_OBJECT(button
), "icon_number"));
1789 partinfo
= g_object_get_data(G_OBJECT(button
), "partinfo");
1791 if (!event
) return FALSE
;
1793 textview
= mimeview
->textview
;
1795 switch (event
->keyval
) {
1797 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button
))) {
1798 /* stop the button being untoggled */
1799 KEY_PRESS_EVENT_STOP();
1800 if (textview_scroll_page(textview
, FALSE
))
1803 if (icon_list_select_by_number(mimeview
, num
+ 1))
1806 icon_selected(mimeview
, num
, partinfo
);
1807 toggle_icon(GTK_TOGGLE_BUTTON(button
), mimeview
);
1813 textview_scroll_page(textview
, TRUE
);
1816 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button
))) {
1817 KEY_PRESS_EVENT_STOP();
1818 textview_scroll_one_line(textview
,
1819 (event
->state
& GDK_MOD1_MASK
) != 0);
1822 icon_selected(mimeview
, num
, partinfo
);
1823 toggle_icon(GTK_TOGGLE_BUTTON(button
), mimeview
);
1829 BREAK_ON_MODIFIER_KEY();
1830 if (icon_list_select_by_number(mimeview
, num
+ 1)) {
1831 KEY_PRESS_EVENT_STOP();
1838 BREAK_ON_MODIFIER_KEY();
1839 if (icon_list_select_by_number(mimeview
, num
- 1)) {
1840 KEY_PRESS_EVENT_STOP();
1846 BREAK_ON_MODIFIER_KEY();
1847 KEY_PRESS_EVENT_STOP();
1848 mimeview_save_as(mimeview
);
1851 BREAK_ON_MODIFIER_KEY();
1852 KEY_PRESS_EVENT_STOP();
1853 mimeview_display_as_text(mimeview
);
1856 BREAK_ON_MODIFIER_KEY();
1857 KEY_PRESS_EVENT_STOP();
1858 mimeview_launch(mimeview
);
1861 BREAK_ON_MODIFIER_KEY();
1862 KEY_PRESS_EVENT_STOP();
1863 mimeview_open_with(mimeview
);
1866 BREAK_ON_MODIFIER_KEY();
1867 KEY_PRESS_EVENT_STOP();
1868 mimeview_check_signature(mimeview
);
1874 if (!mimeview
->messageview
->mainwin
) return FALSE
;
1875 summaryview
= mimeview
->messageview
->mainwin
->summaryview
;
1876 return summary_pass_key_press_event(summaryview
, event
);
1879 static void toggle_icon(GtkToggleButton
*button
, MimeView
*mimeview
)
1883 child
= gtk_container_get_children(GTK_CONTAINER(mimeview
->icon_vbox
));
1884 for (; child
!= NULL
; child
= g_list_next(child
)) {
1885 if (GTK_IS_TOGGLE_BUTTON(child
->data
) &&
1886 GTK_TOGGLE_BUTTON(child
->data
) != button
&&
1887 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(child
->data
)))
1888 gtk_toggle_button_set_active
1889 (GTK_TOGGLE_BUTTON(child
->data
),
1894 static void icon_list_append_icon (MimeView
*mimeview
, MimeInfo
*mimeinfo
)
1896 GtkWidget
*pixmap
= NULL
;
1901 const gchar
*desc
= NULL
;
1902 gchar
*sigshort
= NULL
;
1903 gchar
*content_type
;
1906 MimeInfo
*siginfo
= NULL
;
1907 MimeInfo
*encrypted
= NULL
;
1909 vbox
= mimeview
->icon_vbox
;
1910 mimeview
->icon_count
++;
1911 button
= gtk_toggle_button_new();
1912 gtk_button_set_relief(GTK_BUTTON(button
), GTK_RELIEF_NONE
);
1913 g_object_set_data(G_OBJECT(button
), "icon_number",
1914 GINT_TO_POINTER(mimeview
->icon_count
));
1915 g_object_set_data(G_OBJECT(button
), "partinfo",
1918 switch (mimeinfo
->type
) {
1921 if (mimeinfo
->subtype
&& !g_ascii_strcasecmp(mimeinfo
->subtype
, "html"))
1922 stockp
= STOCK_PIXMAP_MIME_TEXT_HTML
;
1923 else if (mimeinfo
->subtype
&& !g_ascii_strcasecmp(mimeinfo
->subtype
, "enriched"))
1924 stockp
= STOCK_PIXMAP_MIME_TEXT_ENRICHED
;
1926 stockp
= STOCK_PIXMAP_MIME_TEXT_PLAIN
;
1928 case MIMETYPE_MESSAGE
:
1929 stockp
= STOCK_PIXMAP_MIME_MESSAGE
;
1931 case MIMETYPE_APPLICATION
:
1932 stockp
= STOCK_PIXMAP_MIME_APPLICATION
;
1934 case MIMETYPE_IMAGE
:
1935 stockp
= STOCK_PIXMAP_MIME_IMAGE
;
1937 case MIMETYPE_AUDIO
:
1938 stockp
= STOCK_PIXMAP_MIME_AUDIO
;
1941 stockp
= STOCK_PIXMAP_MIME_UNKNOWN
;
1945 partinfo
= mimeinfo
;
1946 while (partinfo
!= NULL
) {
1947 if (privacy_mimeinfo_is_signed(partinfo
)) {
1951 if (privacy_mimeinfo_is_encrypted(partinfo
)) {
1952 encrypted
= partinfo
;
1955 partinfo
= procmime_mimeinfo_parent(partinfo
);
1958 if (siginfo
!= NULL
) {
1959 switch (privacy_mimeinfo_get_sig_status(siginfo
)) {
1960 case SIGNATURE_UNCHECKED
:
1961 case SIGNATURE_CHECK_FAILED
:
1962 case SIGNATURE_CHECK_TIMEOUT
:
1963 pixmap
= stock_pixmap_widget_with_overlay(mimeview
->mainwin
->window
, stockp
,
1964 STOCK_PIXMAP_PRIVACY_EMBLEM_SIGNED
, OVERLAY_BOTTOM_RIGHT
, 6, 3);
1967 pixmap
= stock_pixmap_widget_with_overlay(mimeview
->mainwin
->window
, stockp
,
1968 STOCK_PIXMAP_PRIVACY_EMBLEM_PASSED
, OVERLAY_BOTTOM_RIGHT
, 6, 3);
1970 case SIGNATURE_WARN
:
1971 pixmap
= stock_pixmap_widget_with_overlay(mimeview
->mainwin
->window
, stockp
,
1972 STOCK_PIXMAP_PRIVACY_EMBLEM_WARN
, OVERLAY_BOTTOM_RIGHT
, 6, 3);
1974 case SIGNATURE_INVALID
:
1975 pixmap
= stock_pixmap_widget_with_overlay(mimeview
->mainwin
->window
, stockp
,
1976 STOCK_PIXMAP_PRIVACY_EMBLEM_FAILED
, OVERLAY_BOTTOM_RIGHT
, 6, 3);
1979 sigshort
= privacy_mimeinfo_sig_info_short(siginfo
);
1980 } else if (encrypted
!= NULL
) {
1981 pixmap
= stock_pixmap_widget_with_overlay(mimeview
->mainwin
->window
, stockp
,
1982 STOCK_PIXMAP_PRIVACY_EMBLEM_ENCRYPTED
, OVERLAY_BOTTOM_RIGHT
, 6, 3);
1984 pixmap
= stock_pixmap_widget_with_overlay(mimeview
->mainwin
->window
, stockp
, 0,
1985 OVERLAY_NONE
, 6, 3);
1987 gtk_container_add(GTK_CONTAINER(button
), pixmap
);
1990 if (prefs_common
.attach_desc
)
1991 desc
= get_part_description(mimeinfo
);
1993 desc
= get_part_name(mimeinfo
);
1996 content_type
= procmime_get_content_type_str(mimeinfo
->type
,
1999 tip
= g_strjoin("\n", content_type
,
2000 to_human_readable(mimeinfo
->length
), NULL
);
2001 g_free(content_type
);
2002 if (desc
&& *desc
) {
2004 if (!g_utf8_validate(desc
, -1, NULL
)) {
2005 tmp
= conv_filename_to_utf8(desc
);
2007 tmp
= g_strdup(desc
);
2009 tiptmp
= g_strjoin("\n", tmp
, tip
, NULL
);
2014 if (sigshort
&& *sigshort
) {
2015 tiptmp
= g_strjoin("\n", tip
, sigshort
, NULL
);
2021 gtk_tooltips_set_tip(mimeview
->tooltips
, button
, tip
, NULL
);
2023 gtk_widget_show_all(button
);
2024 gtk_drag_source_set(button
, GDK_BUTTON1_MASK
|GDK_BUTTON3_MASK
,
2025 mimeview_mime_types
, 1, GDK_ACTION_COPY
);
2026 g_signal_connect(G_OBJECT(button
), "button_release_event",
2027 G_CALLBACK(icon_clicked_cb
), mimeview
);
2028 g_signal_connect(G_OBJECT(button
), "key_press_event",
2029 G_CALLBACK(icon_key_pressed
), mimeview
);
2030 g_signal_connect(G_OBJECT(button
), "drag_data_get",
2031 G_CALLBACK(mimeview_drag_data_get
), mimeview
);
2032 gtk_box_pack_start(GTK_BOX(vbox
), button
, FALSE
, FALSE
, 0);
2036 static void icon_list_clear (MimeView
*mimeview
)
2041 child
= gtk_container_children(GTK_CONTAINER(mimeview
->icon_vbox
));
2042 for (; child
!= NULL
; child
= g_list_next(child
)) {
2043 gtkut_container_remove(GTK_CONTAINER(mimeview
->icon_vbox
),
2044 GTK_WIDGET(child
->data
));
2045 gtk_widget_destroy(GTK_WIDGET(child
->data
));
2048 mimeview
->icon_count
= 0;
2049 adj
= gtk_layout_get_vadjustment(GTK_LAYOUT(mimeview
->icon_scroll
));
2050 gtk_adjustment_set_value(adj
, adj
->lower
);
2053 static void icon_list_toggle_by_mime_info(MimeView
*mimeview
,
2058 child
= gtk_container_children(GTK_CONTAINER(mimeview
->icon_vbox
));
2059 for (; child
!= NULL
; child
= g_list_next(child
)) {
2060 if (GTK_IS_TOGGLE_BUTTON(child
->data
) &&
2061 g_object_get_data(G_OBJECT(child
->data
),
2062 "partinfo") == (gpointer
)mimeinfo
) {
2063 toggle_icon(GTK_TOGGLE_BUTTON(child
->data
), mimeview
);
2064 gtk_toggle_button_set_active
2065 (GTK_TOGGLE_BUTTON(child
->data
), TRUE
);
2071 *\brief Used to 'click' the next or previous icon.
2073 *\return true if the icon 'number' exists and was selected.
2075 static gboolean
icon_list_select_by_number(MimeView
*mimeview
,
2080 if (number
== 0) return FALSE
;
2081 child
= gtk_container_children(GTK_CONTAINER(mimeview
->icon_vbox
));
2082 for (; child
!= NULL
; child
= g_list_next(child
)) {
2083 if (GTK_IS_TOGGLE_BUTTON(child
->data
) &&
2084 GPOINTER_TO_INT(g_object_get_data(G_OBJECT(child
->data
),
2085 "icon_number")) == number
) {
2086 icon_selected(mimeview
, number
,
2087 (MimeInfo
*)g_object_get_data(G_OBJECT(child
->data
),
2089 toggle_icon(GTK_TOGGLE_BUTTON(child
->data
), mimeview
);
2090 gtk_toggle_button_set_active
2091 (GTK_TOGGLE_BUTTON(child
->data
), TRUE
);
2092 gtk_widget_grab_focus(GTK_WIDGET(child
->data
));
2100 static void icon_scroll_size_allocate_cb(GtkWidget
*widget
,
2101 GtkAllocation
*size
, MimeView
*mimeview
)
2103 GtkAllocation
*mainbox_size
;
2104 GtkAllocation
*vbox_size
;
2105 GtkAllocation
*layout_size
;
2108 adj
= gtk_layout_get_vadjustment(GTK_LAYOUT(mimeview
->icon_scroll
));
2110 mainbox_size
= &mimeview
->icon_mainbox
->allocation
;
2111 vbox_size
= &mimeview
->icon_vbox
->allocation
;
2112 layout_size
= &mimeview
->icon_scroll
->allocation
;
2114 gtk_layout_set_size(GTK_LAYOUT(mimeview
->icon_scroll
),
2115 GTK_LAYOUT(mimeview
->icon_scroll
)->width
,
2116 MAX(vbox_size
->height
, layout_size
->height
));
2117 adj
->step_increment
= 5;
2120 static void icon_list_create(MimeView
*mimeview
, MimeInfo
*mimeinfo
)
2122 GtkRequisition size
;
2124 g_return_if_fail(mimeinfo
!= NULL
);
2126 while (mimeinfo
!= NULL
) {
2127 if (mimeinfo
->type
!= MIMETYPE_MULTIPART
)
2128 icon_list_append_icon(mimeview
, mimeinfo
);
2129 if (mimeinfo
->node
->children
!= NULL
)
2130 icon_list_create(mimeview
,
2131 (MimeInfo
*) mimeinfo
->node
->children
->data
);
2132 mimeinfo
= mimeinfo
->node
->next
!= NULL
2133 ? (MimeInfo
*) mimeinfo
->node
->next
->data
2136 gtk_widget_size_request(mimeview
->icon_vbox
, &size
);
2137 if (size
.width
> mimeview
->icon_mainbox
->requisition
.width
) {
2138 gtk_widget_set_size_request(mimeview
->icon_mainbox
,
2144 static void mime_toggle_button_cb (GtkWidget
*button
, MimeView
*mimeview
)
2146 gtk_widget_ref(button
);
2148 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button
))) {
2149 gtk_arrow_set(GTK_ARROW(GTK_BIN(button
)->child
), GTK_ARROW_RIGHT
,
2151 gtk_widget_hide(mimeview
->icon_mainbox
);
2152 gtk_widget_show(mimeview
->ctree_mainbox
);
2153 gtk_paned_set_position(GTK_PANED(mimeview
->paned
), mimeview
->oldsize
);
2155 gtkut_container_remove(GTK_CONTAINER(mimeview
->icon_mainbox
),
2157 gtk_box_pack_end(GTK_BOX(mimeview
->ctree_mainbox
),
2158 button
, FALSE
, FALSE
, 0);
2159 gtk_paned_set_gutter_size(GTK_PANED(mimeview
->paned
), 6);
2161 gtk_arrow_set(GTK_ARROW(GTK_BIN(button
)->child
), GTK_ARROW_LEFT
,
2163 mimeview
->oldsize
= mimeview
->ctree_mainbox
->allocation
.height
;
2164 gtk_widget_hide(mimeview
->ctree_mainbox
);
2165 gtk_widget_show(mimeview
->icon_mainbox
);
2166 gtk_paned_set_position(GTK_PANED(mimeview
->paned
), 0);
2168 gtkut_container_remove(GTK_CONTAINER(mimeview
->ctree_mainbox
),
2170 gtk_box_pack_start(GTK_BOX(mimeview
->icon_mainbox
),
2171 button
, FALSE
, FALSE
, 0);
2172 gtk_box_reorder_child(GTK_BOX(button
->parent
), button
, 0);
2173 if (mimeview
->opened
)
2174 icon_list_toggle_by_mime_info
2175 (mimeview
, gtk_ctree_node_get_row_data(GTK_CTREE(mimeview
->ctree
),
2178 gtk_paned_set_gutter_size(GTK_PANED(mimeview
->paned
), 0);
2180 gtk_widget_grab_focus(button
);
2181 gtk_widget_unref(button
);
2185 void mimeview_update (MimeView
*mimeview
) {
2186 if (mimeview
&& mimeview
->mimeinfo
) {
2187 icon_list_clear(mimeview
);
2188 icon_list_create(mimeview
, mimeview
->mimeinfo
);
2192 void mimeview_handle_cmd(MimeView
*mimeview
, const gchar
*cmd
, GdkEventButton
*event
, gpointer data
)
2194 MessageView
*msgview
= NULL
;
2195 MainWindow
*mainwin
= NULL
;
2200 msgview
= mimeview
->messageview
;
2204 mainwin
= msgview
->mainwin
;
2208 else if (!strcmp(cmd
, "sc://view_log"))
2209 log_window_show(mainwin
->logwin
);
2210 else if (!strcmp(cmd
, "sc://save_as"))
2211 mimeview_save_as(mimeview
);
2212 else if (!strcmp(cmd
, "sc://display_as_text"))
2213 mimeview_display_as_text(mimeview
);
2214 else if (!strcmp(cmd
, "sc://open_with"))
2215 mimeview_open_with(mimeview
);
2216 else if (!strcmp(cmd
, "sc://open"))
2217 mimeview_launch(mimeview
);
2218 else if (!strcmp(cmd
, "sc://select_attachment") && data
!= NULL
) {
2219 icon_list_toggle_by_mime_info(mimeview
, (MimeInfo
*)data
);
2220 icon_selected(mimeview
, -1, (MimeInfo
*)data
);
2221 } else if (!strcmp(cmd
, "sc://open_attachment") && data
!= NULL
) {
2222 icon_list_toggle_by_mime_info(mimeview
, (MimeInfo
*)data
);
2223 icon_selected(mimeview
, -1, (MimeInfo
*)data
);
2224 mimeview_launch(mimeview
);
2225 } else if (!strcmp(cmd
, "sc://menu_attachment") && data
!= NULL
) {
2226 mimeview
->spec_part
= (MimeInfo
*)data
;
2227 part_button_pressed(mimeview
, event
, (MimeInfo
*)data
);