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 gboolean
mimeview_scrolled (GtkWidget
*widget
,
117 GdkEventScroll
*event
,
119 static void mimeview_display_as_text (MimeView
*mimeview
);
120 static void mimeview_save_as (MimeView
*mimeview
);
121 static void mimeview_save_all (MimeView
*mimeview
);
122 static void mimeview_launch (MimeView
*mimeview
);
123 static void mimeview_open_with (MimeView
*mimeview
);
124 static void mimeview_open_part_with (MimeView
*mimeview
,
127 static void mimeview_view_file (const gchar
*filename
,
131 static gboolean
icon_clicked_cb (GtkWidget
*button
,
132 GdkEventButton
*event
,
134 static void icon_selected (MimeView
*mimeview
,
137 static gint
icon_key_pressed (GtkWidget
*button
,
140 static void toggle_icon (GtkToggleButton
*button
,
142 static void icon_list_append_icon (MimeView
*mimeview
,
144 static void icon_list_create (MimeView
*mimeview
,
146 static void icon_list_clear (MimeView
*mimeview
);
147 static void icon_list_toggle_by_mime_info (MimeView
*mimeview
,
149 static gboolean
icon_list_select_by_number(MimeView
*mimeview
,
151 static void mime_toggle_button_cb (GtkWidget
*button
,
153 static gboolean
part_button_pressed (MimeView
*mimeview
,
154 GdkEventButton
*event
,
156 static void icon_scroll_size_allocate_cb(GtkWidget
*widget
,
157 GtkAllocation
*layout_size
,
160 static GtkItemFactoryEntry mimeview_popup_entries
[] =
162 {N_("/_Open"), NULL
, mimeview_launch
, 0, NULL
},
163 {N_("/Open _with..."), NULL
, mimeview_open_with
, 0, NULL
},
164 {N_("/_Display as text"), NULL
, mimeview_display_as_text
, 0, NULL
},
165 {N_("/_Save as..."), NULL
, mimeview_save_as
, 0, NULL
},
166 {N_("/Save _all..."), NULL
, mimeview_save_all
, 0, NULL
},
169 static GtkTargetEntry mimeview_mime_types
[] =
171 {"text/uri-list", 0, 0}
174 GSList
*mimeviewer_factories
;
177 MimeView
*mimeview_create(MainWindow
*mainwin
)
182 GtkWidget
*scrolledwin
;
184 GtkWidget
*mime_notebook
;
185 GtkWidget
*popupmenu
;
186 GtkWidget
*ctree_mainbox
;
188 GtkWidget
*mime_toggle
;
189 GtkWidget
*icon_mainbox
;
190 GtkWidget
*icon_scroll
;
191 GtkWidget
*icon_vbox
;
193 GtkWidget
*scrollbutton
;
195 GtkTooltips
*tooltips
;
196 GtkItemFactory
*popupfactory
;
197 NoticeView
*siginfoview
;
198 gchar
*titles
[N_MIMEVIEW_COLS
];
202 debug_print("Creating MIME view...\n");
203 mimeview
= g_new0(MimeView
, 1);
205 titles
[COL_MIMETYPE
] = _("MIME Type");
206 titles
[COL_SIZE
] = _("Size");
207 titles
[COL_NAME
] = _("Name");
209 scrolledwin
= gtk_scrolled_window_new(NULL
, NULL
);
210 gtk_widget_show(scrolledwin
);
211 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwin
),
212 GTK_POLICY_AUTOMATIC
,
213 GTK_POLICY_AUTOMATIC
);
215 ctree
= gtk_sctree_new_with_titles(N_MIMEVIEW_COLS
, 0, titles
);
216 gtk_widget_show(ctree
);
217 gtk_clist_set_selection_mode(GTK_CLIST(ctree
), GTK_SELECTION_BROWSE
);
218 gtk_ctree_set_line_style(GTK_CTREE(ctree
), GTK_CTREE_LINES_NONE
);
219 gtk_clist_set_column_justification(GTK_CLIST(ctree
), COL_SIZE
,
221 gtk_clist_set_column_width(GTK_CLIST(ctree
), COL_MIMETYPE
, 240);
222 gtk_clist_set_column_width(GTK_CLIST(ctree
), COL_SIZE
, 90);
223 for (i
= 0; i
< N_MIMEVIEW_COLS
; i
++)
224 GTK_WIDGET_UNSET_FLAGS(GTK_CLIST(ctree
)->column
[i
].button
,
226 gtk_container_add(GTK_CONTAINER(scrolledwin
), ctree
);
228 g_signal_connect(G_OBJECT(ctree
), "tree_select_row",
229 G_CALLBACK(mimeview_selected
), mimeview
);
230 g_signal_connect(G_OBJECT(ctree
), "button_release_event",
231 G_CALLBACK(mimeview_button_pressed
), mimeview
);
232 g_signal_connect(G_OBJECT(ctree
), "key_press_event",
233 G_CALLBACK(mimeview_key_pressed
), mimeview
);
234 g_signal_connect(G_OBJECT (ctree
),"start_drag",
235 G_CALLBACK (mimeview_start_drag
), mimeview
);
236 g_signal_connect(G_OBJECT(ctree
), "drag_data_get",
237 G_CALLBACK(mimeview_drag_data_get
), mimeview
);
239 mime_notebook
= gtk_notebook_new();
240 gtk_widget_show(mime_notebook
);
241 GTK_WIDGET_UNSET_FLAGS(mime_notebook
, GTK_CAN_FOCUS
);
242 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(mime_notebook
), FALSE
);
243 gtk_notebook_set_show_border(GTK_NOTEBOOK(mime_notebook
), FALSE
);
245 icon_vbox
= gtk_vbox_new(FALSE
, 2);
246 gtk_widget_show(icon_vbox
);
247 icon_scroll
= gtk_layout_new(NULL
, NULL
);
248 gtk_widget_show(icon_scroll
);
249 gtk_layout_put(GTK_LAYOUT(icon_scroll
), icon_vbox
, 0, 0);
250 scrollbutton
= gtk_vscrollbutton_new(gtk_layout_get_vadjustment(GTK_LAYOUT(icon_scroll
)));
251 gtk_widget_show(scrollbutton
);
253 g_signal_connect(G_OBJECT(icon_scroll
), "scroll_event",
254 G_CALLBACK(mimeview_scrolled
), mimeview
);
256 mime_toggle
= gtk_toggle_button_new();
257 gtk_widget_show(mime_toggle
);
258 arrow
= gtk_arrow_new(GTK_ARROW_LEFT
, GTK_SHADOW_NONE
);
259 gtk_widget_show(arrow
);
260 gtk_container_add(GTK_CONTAINER(mime_toggle
), arrow
);
261 g_signal_connect(G_OBJECT(mime_toggle
), "toggled",
262 G_CALLBACK(mime_toggle_button_cb
), mimeview
);
264 icon_mainbox
= gtk_vbox_new(FALSE
, 0);
265 gtk_widget_show(icon_mainbox
);
266 gtk_box_pack_start(GTK_BOX(icon_mainbox
), mime_toggle
, FALSE
, FALSE
, 0);
267 gtk_box_pack_start(GTK_BOX(icon_mainbox
), icon_scroll
, TRUE
, TRUE
, 3);
268 gtk_box_pack_end(GTK_BOX(icon_mainbox
), scrollbutton
, FALSE
, FALSE
, 0);
269 g_signal_connect(G_OBJECT(icon_mainbox
), "size_allocate",
270 G_CALLBACK(icon_scroll_size_allocate_cb
), mimeview
);
272 ctree_mainbox
= gtk_hbox_new(FALSE
, 0);
273 gtk_box_pack_start(GTK_BOX(ctree_mainbox
), scrolledwin
, TRUE
, TRUE
, 0);
275 n_entries
= sizeof(mimeview_popup_entries
) /
276 sizeof(mimeview_popup_entries
[0]);
277 popupmenu
= menu_create_items(mimeview_popup_entries
, n_entries
,
278 "<MimeView>", &popupfactory
, mimeview
);
279 tooltips
= gtk_tooltips_new();
280 gtk_tooltips_set_delay(tooltips
, 0);
282 vbox
= gtk_vbox_new(FALSE
, 0);
283 gtk_widget_show(vbox
);
284 siginfoview
= noticeview_create(mainwin
);
285 noticeview_hide(siginfoview
);
286 noticeview_set_icon_clickable(siginfoview
, TRUE
);
287 gtk_box_pack_start(GTK_BOX(vbox
), mime_notebook
, TRUE
, TRUE
, 0);
288 gtk_box_pack_end(GTK_BOX(vbox
), GTK_WIDGET_PTR(siginfoview
), FALSE
, FALSE
, 0);
290 paned
= gtk_vpaned_new();
291 gtk_widget_show(paned
);
292 gtk_paned_set_gutter_size(GTK_PANED(paned
), 0);
293 gtk_paned_pack1(GTK_PANED(paned
), ctree_mainbox
, FALSE
, TRUE
);
294 gtk_paned_pack2(GTK_PANED(paned
), vbox
, TRUE
, TRUE
);
296 hbox
= gtk_hbox_new(FALSE
, 0);
297 gtk_box_pack_start(GTK_BOX(hbox
), paned
, TRUE
, TRUE
, 0);
298 gtk_box_pack_start(GTK_BOX(hbox
), icon_mainbox
, FALSE
, FALSE
, 0);
300 gtk_widget_show(hbox
);
301 gtk_widget_hide(ctree_mainbox
);
303 mimeview
->hbox
= hbox
;
304 mimeview
->paned
= paned
;
305 mimeview
->scrolledwin
= scrolledwin
;
306 mimeview
->ctree
= ctree
;
307 mimeview
->mime_notebook
= mime_notebook
;
308 mimeview
->popupmenu
= popupmenu
;
309 mimeview
->popupfactory
= popupfactory
;
311 mimeview
->ctree_mainbox
= ctree_mainbox
;
312 mimeview
->icon_scroll
= icon_scroll
;
313 mimeview
->icon_vbox
= icon_vbox
;
314 mimeview
->icon_mainbox
= icon_mainbox
;
315 mimeview
->icon_count
= 0;
316 mimeview
->mainwin
= mainwin
;
317 mimeview
->tooltips
= tooltips
;
318 mimeview
->oldsize
= 60;
319 mimeview
->mime_toggle
= mime_toggle
;
320 mimeview
->siginfoview
= siginfoview
;
321 mimeview
->scrollbutton
= scrollbutton
;
322 mimeview
->target_list
= gtk_target_list_new(mimeview_mime_types
, 1);
324 mimeviews
= g_slist_prepend(mimeviews
, mimeview
);
329 void mimeview_init(MimeView
*mimeview
)
331 textview_init(mimeview
->textview
);
333 gtk_container_add(GTK_CONTAINER(mimeview
->mime_notebook
),
334 GTK_WIDGET_PTR(mimeview
->textview
));
337 void mimeview_show_message(MimeView
*mimeview
, MimeInfo
*mimeinfo
,
340 GtkCTree
*ctree
= GTK_CTREE(mimeview
->ctree
);
343 mimeview_clear(mimeview
);
345 g_return_if_fail(file
!= NULL
);
346 g_return_if_fail(mimeinfo
!= NULL
);
348 mimeview
->mimeinfo
= mimeinfo
;
350 mimeview
->file
= g_strdup(file
);
352 g_signal_handlers_block_by_func(G_OBJECT(ctree
), mimeview_selected
,
355 mimeview_set_multipart_tree(mimeview
, mimeinfo
, NULL
);
356 icon_list_create(mimeview
, mimeinfo
);
358 g_signal_handlers_unblock_by_func(G_OBJECT(ctree
),
359 mimeview_selected
, mimeview
);
361 node
= GTK_CTREE_NODE(GTK_CLIST(ctree
)->row_list
);
363 gtk_ctree_select(ctree
, node
);
364 icon_list_toggle_by_mime_info
365 (mimeview
, gtk_ctree_node_get_row_data(ctree
, node
));
366 gtkut_ctree_set_focus_row(ctree
, node
);
371 static void mimeview_check_sig_cancel_now(MimeView
*mimeview
);
374 static void mimeview_free_mimeinfo(MimeView
*mimeview
)
376 gboolean defer
= FALSE
;
378 defer
= (mimeview
->check_data
!= NULL
);
380 mimeview
->check_data
->free_after_use
= TRUE
;
382 if (mimeview
->mimeinfo
!= NULL
&& !defer
) {
383 procmime_mimeinfo_free_all(mimeview
->mimeinfo
);
384 mimeview
->mimeinfo
= NULL
;
387 debug_print("deferring free(mimeinfo) and cancelling check\n");
388 mimeview_check_sig_cancel_now(mimeview
);
393 void mimeview_destroy(MimeView
*mimeview
)
397 for (cur
= mimeview
->viewers
; cur
!= NULL
; cur
= g_slist_next(cur
)) {
398 MimeViewer
*viewer
= (MimeViewer
*) cur
->data
;
399 viewer
->destroy_viewer(viewer
);
401 g_slist_free(mimeview
->viewers
);
402 gtk_target_list_unref(mimeview
->target_list
);
404 mimeview_free_mimeinfo(mimeview
);
406 if (mimeview
->check_data
) {
407 mimeview
->check_data
->destroy_mimeview
= TRUE
;
408 debug_print("deferring destroy\n");
412 g_free(mimeview
->file
);
414 mimeviews
= g_slist_remove(mimeviews
, mimeview
);
419 MimeInfo
*mimeview_get_selected_part(MimeView
*mimeview
)
421 return gtk_ctree_node_get_row_data
422 (GTK_CTREE(mimeview
->ctree
), mimeview
->opened
);
425 static void mimeview_set_multipart_tree(MimeView
*mimeview
,
427 GtkCTreeNode
*parent
)
431 g_return_if_fail(mimeinfo
!= NULL
);
433 while (mimeinfo
!= NULL
) {
434 node
= mimeview_append_part(mimeview
, mimeinfo
, parent
);
436 if (mimeinfo
->node
->children
)
437 mimeview_set_multipart_tree(mimeview
, (MimeInfo
*) mimeinfo
->node
->children
->data
, node
);
438 mimeinfo
= mimeinfo
->node
->next
!= NULL
? (MimeInfo
*) mimeinfo
->node
->next
->data
: NULL
;
442 static const gchar
*get_real_part_name(MimeInfo
*partinfo
)
444 const gchar
*name
= NULL
;
446 name
= procmime_mimeinfo_get_parameter(partinfo
, "filename");
448 name
= procmime_mimeinfo_get_parameter(partinfo
, "name");
453 static const gchar
*get_part_name(MimeInfo
*partinfo
)
457 name
= get_real_part_name(partinfo
);
464 static const gchar
*get_part_description(MimeInfo
*partinfo
)
466 if (partinfo
->description
)
467 return partinfo
->description
;
469 return get_part_name(partinfo
);
472 static GtkCTreeNode
*mimeview_append_part(MimeView
*mimeview
,
474 GtkCTreeNode
*parent
)
476 GtkCTree
*ctree
= GTK_CTREE(mimeview
->ctree
);
478 static gchar content_type
[64];
479 gchar
*str
[N_MIMEVIEW_COLS
];
481 if (partinfo
->type
!= MIMETYPE_UNKNOWN
&& partinfo
->subtype
) {
482 g_snprintf(content_type
, 64, "%s/%s", procmime_get_media_type_str(partinfo
->type
), partinfo
->subtype
);
484 g_snprintf(content_type
, 64, "UNKNOWN");
487 str
[COL_MIMETYPE
] = content_type
;
488 str
[COL_SIZE
] = to_human_readable(partinfo
->length
);
489 if (prefs_common
.attach_desc
)
490 str
[COL_NAME
] = (gchar
*) get_part_description(partinfo
);
492 str
[COL_NAME
] = (gchar
*) get_part_name(partinfo
);
494 node
= gtk_sctree_insert_node(ctree
, parent
, NULL
, str
, 0,
495 NULL
, NULL
, NULL
, NULL
,
497 gtk_ctree_node_set_row_data(ctree
, node
, partinfo
);
502 static void mimeview_show_message_part(MimeView
*mimeview
, MimeInfo
*partinfo
)
507 if (!partinfo
) return;
509 fname
= mimeview
->file
;
512 if ((fp
= g_fopen(fname
, "rb")) == NULL
) {
513 FILE_OP_ERROR(fname
, "fopen");
517 if (fseek(fp
, partinfo
->offset
, SEEK_SET
) < 0) {
518 FILE_OP_ERROR(mimeview
->file
, "fseek");
523 mimeview_change_view_type(mimeview
, MIMEVIEW_TEXT
);
524 textview_show_part(mimeview
->textview
, partinfo
, fp
);
529 static MimeViewer
*get_viewer_for_content_type(MimeView
*mimeview
, const gchar
*content_type
)
532 MimeViewerFactory
*factory
= NULL
;
533 MimeViewer
*viewer
= NULL
;
536 * FNM_CASEFOLD is a GNU extension
537 * if its not defined copy the string to the stack and
538 * convert the copy to lower case
541 #define FNM_CASEFOLD 0
542 Xstrdup_a(content_type
, content_type
, return NULL
);
543 g_strdown((gchar
*)content_type
);
546 for (cur
= mimeviewer_factories
; cur
!= NULL
; cur
= g_slist_next(cur
)) {
547 MimeViewerFactory
*curfactory
= cur
->data
;
550 while (curfactory
->content_types
[i
] != NULL
) {
551 if(!fnmatch(curfactory
->content_types
[i
], content_type
, FNM_CASEFOLD
)) {
552 debug_print("%s\n", curfactory
->content_types
[i
]);
553 factory
= curfactory
;
564 for (cur
= mimeview
->viewers
; cur
!= NULL
; cur
= g_slist_next(cur
)) {
565 MimeViewer
*curviewer
= cur
->data
;
567 if (curviewer
->factory
== factory
)
570 viewer
= factory
->create_viewer();
571 gtk_container_add(GTK_CONTAINER(mimeview
->mime_notebook
),
572 GTK_WIDGET(viewer
->get_widget(viewer
)));
574 mimeview
->viewers
= g_slist_append(mimeview
->viewers
, viewer
);
579 static MimeViewer
*get_viewer_for_mimeinfo(MimeView
*mimeview
, MimeInfo
*partinfo
)
581 gchar
*content_type
= NULL
;
582 MimeViewer
*viewer
= NULL
;
584 if ((partinfo
->type
== MIMETYPE_APPLICATION
) &&
585 (!g_ascii_strcasecmp(partinfo
->subtype
, "octet-stream"))) {
586 const gchar
*filename
;
588 filename
= procmime_mimeinfo_get_parameter(partinfo
, "filename");
589 if (filename
== NULL
)
590 filename
= procmime_mimeinfo_get_parameter(partinfo
, "name");
591 if (filename
!= NULL
)
592 content_type
= procmime_get_mime_type(filename
);
594 content_type
= procmime_get_content_type_str(partinfo
->type
, partinfo
->subtype
);
597 if (content_type
!= NULL
) {
598 viewer
= get_viewer_for_content_type(mimeview
, content_type
);
599 g_free(content_type
);
605 gboolean
mimeview_show_part(MimeView
*mimeview
, MimeInfo
*partinfo
)
609 viewer
= get_viewer_for_mimeinfo(mimeview
, partinfo
);
610 if (viewer
== NULL
) {
611 if (mimeview
->mimeviewer
!= NULL
)
612 mimeview
->mimeviewer
->clear_viewer(mimeview
->mimeviewer
);
613 mimeview
->mimeviewer
= NULL
;
617 if (mimeview
->mimeviewer
!= NULL
)
618 mimeview
->mimeviewer
->clear_viewer(mimeview
->mimeviewer
);
620 if (mimeview
->mimeviewer
!= viewer
) {
621 mimeview
->mimeviewer
= viewer
;
622 mimeview_change_view_type(mimeview
, MIMEVIEW_VIEWER
);
624 viewer
->mimeview
= mimeview
;
625 viewer
->show_mimepart(viewer
, mimeview
->file
, partinfo
);
630 static void mimeview_change_view_type(MimeView
*mimeview
, MimeViewType type
)
632 TextView
*textview
= mimeview
->textview
;
634 if ((mimeview
->type
!= MIMEVIEW_VIEWER
) &&
635 (mimeview
->type
== type
)) return;
639 gtk_notebook_set_current_page(GTK_NOTEBOOK(mimeview
->mime_notebook
),
640 gtk_notebook_page_num(GTK_NOTEBOOK(mimeview
->mime_notebook
),
641 GTK_WIDGET_PTR(textview
)));
643 case MIMEVIEW_VIEWER
:
644 gtk_notebook_set_current_page(GTK_NOTEBOOK(mimeview
->mime_notebook
),
645 gtk_notebook_page_num(GTK_NOTEBOOK(mimeview
->mime_notebook
),
646 GTK_WIDGET(mimeview
->mimeviewer
->get_widget(mimeview
->mimeviewer
))));
652 mimeview
->type
= type
;
655 void mimeview_clear(MimeView
*mimeview
)
657 GtkCList
*clist
= NULL
;
662 if (g_slist_find(mimeviews
, mimeview
) == NULL
)
665 clist
= GTK_CLIST(mimeview
->ctree
);
667 noticeview_hide(mimeview
->siginfoview
);
669 gtk_clist_clear(clist
);
670 textview_clear(mimeview
->textview
);
671 if (mimeview
->mimeviewer
!= NULL
)
672 mimeview
->mimeviewer
->clear_viewer(mimeview
->mimeviewer
);
674 mimeview_free_mimeinfo(mimeview
);
676 mimeview
->mimeinfo
= NULL
;
678 mimeview
->opened
= NULL
;
680 g_free(mimeview
->file
);
681 mimeview
->file
= NULL
;
683 icon_list_clear(mimeview
);
684 mimeview_change_view_type(mimeview
, MIMEVIEW_TEXT
);
687 static void check_signature_cb(GtkWidget
*widget
, gpointer user_data
);
688 void mimeview_check_signature(MimeView
*mimeview
);
689 static void display_full_info_cb(GtkWidget
*widget
, gpointer user_data
);
691 static void update_signature_noticeview(MimeView
*mimeview
, MimeInfo
*mimeinfo
,
692 gboolean special
, SignatureStatus code
)
694 gchar
*text
= NULL
, *button_text
= NULL
;
696 StockPixmap icon
= STOCK_PIXMAP_PRIVACY_SIGNED
;
697 SignatureStatus mycode
= SIGNATURE_UNCHECKED
;
699 g_return_if_fail(mimeview
!= NULL
);
700 g_return_if_fail(mimeinfo
!= NULL
);
705 mycode
= privacy_mimeinfo_get_sig_status(mimeinfo
);
708 case SIGNATURE_UNCHECKED
:
709 button_text
= _("Check signature");
710 func
= check_signature_cb
;
711 icon
= STOCK_PIXMAP_PRIVACY_SIGNED
;
714 button_text
= _("View full information");
715 func
= display_full_info_cb
;
716 icon
= STOCK_PIXMAP_PRIVACY_PASSED
;
719 button_text
= _("View full information");
720 func
= display_full_info_cb
;
721 icon
= STOCK_PIXMAP_PRIVACY_WARN
;
723 case SIGNATURE_INVALID
:
724 button_text
= _("View full information");
725 func
= display_full_info_cb
;
726 icon
= STOCK_PIXMAP_PRIVACY_FAILED
;
728 case SIGNATURE_CHECK_FAILED
:
729 button_text
= _("Check again");
730 func
= check_signature_cb
;
731 icon
= STOCK_PIXMAP_PRIVACY_UNKNOWN
;
732 case SIGNATURE_CHECK_TIMEOUT
:
733 button_text
= _("Check again");
734 func
= check_signature_cb
;
735 icon
= STOCK_PIXMAP_PRIVACY_UNKNOWN
;
739 if (mycode
== SIGNATURE_UNCHECKED
) {
740 gchar
*tmp
= privacy_mimeinfo_sig_info_short(mimeinfo
);
741 text
= g_strdup_printf("%s %s",
742 tmp
, _("Click the icon or hit 'C' to check it."));
744 } else if (mycode
!= SIGNATURE_CHECK_TIMEOUT
) {
745 text
= privacy_mimeinfo_sig_info_short(mimeinfo
);
746 } else if (mycode
== SIGNATURE_CHECK_TIMEOUT
) {
747 text
= g_strdup(_("Timeout checking the signature. Click the icon or hit 'C' to try again."));
750 noticeview_set_text(mimeview
->siginfoview
, text
);
751 gtk_label_set_selectable(GTK_LABEL(mimeview
->siginfoview
->text
), TRUE
);
754 noticeview_set_button_text(mimeview
->siginfoview
, NULL
);
755 noticeview_set_button_press_callback(
756 mimeview
->siginfoview
,
758 (gpointer
) mimeview
);
759 noticeview_set_icon(mimeview
->siginfoview
, icon
);
760 noticeview_set_tooltip(mimeview
->siginfoview
, button_text
);
765 /* reset all thread stuff, and do the cleanups we've been left to do */
766 static void mimeview_check_data_reset(MimeView
*mimeview
)
768 if (!mimeview
->check_data
)
771 if (mimeview
->check_data
->free_after_use
) {
772 debug_print("freeing deferred mimeinfo\n");
773 procmime_mimeinfo_free_all(mimeview
->check_data
->siginfo
);
775 if (mimeview
->check_data
->destroy_mimeview
) {
776 debug_print("freeing deferred mimeview\n");
777 g_free(mimeview
->file
);
779 mimeviews
= g_slist_remove(mimeviews
, mimeview
);
782 g_free(mimeview
->check_data
);
783 mimeview
->check_data
= NULL
;
786 /* GUI update once the checker thread is done or killed */
787 static gboolean
mimeview_check_sig_thread_cb(void *data
)
789 MimeView
*mimeview
= (MimeView
*) data
;
790 MimeInfo
*mimeinfo
= mimeview
->siginfo
;
792 debug_print("mimeview_check_sig_thread_cb\n");
794 if (mimeinfo
== NULL
) {
795 /* message changed !? */
796 g_warning("no more siginfo!\n");
800 if (!mimeview
->check_data
) {
801 g_warning("nothing to check\n");
805 if (mimeview
->check_data
->siginfo
!= mimeinfo
) {
806 /* message changed !? */
807 g_warning("different siginfo!\n");
811 if (mimeview
->check_data
->destroy_mimeview
||
812 mimeview
->check_data
->free_after_use
) {
813 debug_print("not bothering, we're changing message\n");
818 if (mimeview
->check_data
->timeout
)
819 update_signature_noticeview(mimeview
, mimeview
->siginfo
,
820 TRUE
, SIGNATURE_CHECK_TIMEOUT
);
822 update_signature_noticeview(mimeview
, mimeview
->siginfo
,
824 icon_list_clear(mimeview
);
825 icon_list_create(mimeview
, mimeview
->mimeinfo
);
828 mimeview_check_data_reset(mimeview
);
832 /* sig checker thread */
833 static void *mimeview_check_sig_worker_thread(void *data
)
835 MimeView
*mimeview
= (MimeView
*)data
;
836 MimeInfo
*mimeinfo
= mimeview
->siginfo
;
838 debug_print("checking...\n");
840 if (!mimeview
->check_data
)
843 if (mimeinfo
&& mimeinfo
== mimeview
->check_data
->siginfo
)
844 privacy_mimeinfo_check_signature(mimeinfo
);
846 /* that's strange! we changed message without
848 g_warning("different siginfo!\n");
849 mimeview_check_data_reset(mimeview
);
853 /* use g_timeout so that GUI updates is done from the
855 g_timeout_add(0,mimeview_check_sig_thread_cb
,mimeview
);
860 /* killer thread - acts when the checker didn't work fast
862 static void *mimeview_check_sig_cancel_thread(void *data
)
864 MimeView
*mimeview
= (MimeView
*)data
;
866 if (!mimeview
->check_data
)
867 return NULL
; /* nothing to kill ! */
869 /* wait for a few seconds... */
870 debug_print("waiting a while\n");
874 if (!mimeview
->check_data
)
875 return NULL
; /* nothing to kill, it's done in time :) */
877 /* too late, go away checker thread */
878 debug_print("killing checker thread\n");
879 pthread_cancel(mimeview
->check_data
->th
);
881 /* tell upstream it was a timeout */
882 mimeview
->check_data
->timeout
= TRUE
;
883 /* use g_timeout so that GUI updates is done from the
885 g_timeout_add(0,mimeview_check_sig_thread_cb
,mimeview
);
890 /* get rid of the checker thread right now - used when changing the
891 * displayed message for example. */
892 static void mimeview_check_sig_cancel_now(MimeView
*mimeview
)
894 if (!mimeview
->check_data
)
896 debug_print("killing checker thread NOW\n");
897 pthread_cancel(mimeview
->check_data
->th
);
899 /* tell upstream it was a timeout */
900 mimeview
->check_data
->timeout
= TRUE
;
901 mimeview_check_sig_thread_cb(mimeview
);
905 /* creates a thread to check the signature, and a second one
906 * to kill the first one after a timeout */
907 static void mimeview_check_sig_in_thread(MimeView
*mimeview
)
910 pthread_attr_t detach
, detach2
;
912 if (mimeview
->check_data
) {
913 g_warning("already checking it");
917 mimeview
->check_data
= g_new0(SigCheckData
, 1);
918 mimeview
->check_data
->siginfo
= mimeview
->siginfo
;
919 debug_print("creating thread\n");
921 pthread_attr_init(&detach
);
922 pthread_attr_setdetachstate(&detach
, TRUE
);
924 pthread_attr_init(&detach2
);
925 pthread_attr_setdetachstate(&detach2
, TRUE
);
927 /* create the checker thread */
928 if (pthread_create(&th
, &detach
,
929 mimeview_check_sig_worker_thread
,
931 /* arh. We'll do it synchronously. */
932 g_warning("can't create thread");
933 g_free(mimeview
->check_data
);
934 mimeview
->check_data
= NULL
;
937 mimeview
->check_data
->th
= th
;
939 /* create the killer thread */
940 pthread_create(&th2
, &detach2
,
941 mimeview_check_sig_cancel_thread
,
946 static void check_signature_cb(GtkWidget
*widget
, gpointer user_data
)
948 MimeView
*mimeview
= (MimeView
*) user_data
;
949 MimeInfo
*mimeinfo
= mimeview
->siginfo
;
951 if (mimeinfo
== NULL
)
954 if (mimeview
->check_data
)
957 noticeview_set_text(mimeview
->siginfoview
, _("Checking signature..."));
959 #if (defined USE_PTHREAD && defined __GLIBC__ && (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 3)))
960 /* let's do it non-blocking */
961 mimeview_check_sig_in_thread(mimeview
);
962 if (!mimeview
->check_data
) /* let's check syncronously */
965 debug_print("checking without thread\n");
966 privacy_mimeinfo_check_signature(mimeinfo
);
967 update_signature_noticeview(mimeview
, mimeview
->siginfo
, FALSE
, 0);
968 icon_list_clear(mimeview
);
969 icon_list_create(mimeview
, mimeview
->mimeinfo
);
973 void mimeview_check_signature(MimeView
*mimeview
)
975 check_signature_cb(NULL
, mimeview
);
978 static void redisplay_email(GtkWidget
*widget
, gpointer user_data
)
980 MimeView
*mimeview
= (MimeView
*) user_data
;
981 GtkCTreeNode
*node
= mimeview
->opened
;
982 mimeview
->opened
= NULL
;
983 mimeview_selected(GTK_CTREE(mimeview
->ctree
), node
, 0, mimeview
);
986 static void display_full_info_cb(GtkWidget
*widget
, gpointer user_data
)
988 MimeView
*mimeview
= (MimeView
*) user_data
;
991 siginfo
= privacy_mimeinfo_sig_info_full(mimeview
->siginfo
);
992 textview_set_text(mimeview
->textview
, siginfo
);
994 noticeview_set_button_text(mimeview
->siginfoview
, NULL
);
995 noticeview_set_button_press_callback(
996 mimeview
->siginfoview
,
997 G_CALLBACK(redisplay_email
),
998 (gpointer
) mimeview
);
999 noticeview_set_tooltip(mimeview
->siginfoview
, _("Go back to email"));
1002 static void update_signature_info(MimeView
*mimeview
, MimeInfo
*selected
)
1005 MimeInfo
*first_text
;
1007 g_return_if_fail(mimeview
!= NULL
);
1008 g_return_if_fail(selected
!= NULL
);
1010 if (selected
->type
== MIMETYPE_MESSAGE
1011 && !g_ascii_strcasecmp(selected
->subtype
, "rfc822")) {
1012 /* if the first text part is signed, check that */
1013 first_text
= selected
;
1014 while (first_text
&& first_text
->type
!= MIMETYPE_TEXT
) {
1015 first_text
= procmime_mimeinfo_next(first_text
);
1018 update_signature_info(mimeview
, first_text
);
1024 while (siginfo
!= NULL
) {
1025 if (privacy_mimeinfo_is_signed(siginfo
))
1027 siginfo
= procmime_mimeinfo_parent(siginfo
);
1029 mimeview
->siginfo
= siginfo
;
1031 if (siginfo
== NULL
) {
1032 noticeview_hide(mimeview
->siginfoview
);
1036 update_signature_noticeview(mimeview
, siginfo
, FALSE
, 0);
1037 noticeview_show(mimeview
->siginfoview
);
1040 static void mimeview_selected(GtkCTree
*ctree
, GtkCTreeNode
*node
, gint column
,
1044 if (mimeview
->opened
== node
) return;
1045 mimeview
->opened
= node
;
1046 mimeview
->spec_part
= NULL
;
1047 gtk_ctree_node_moveto(ctree
, node
, -1, 0.5, 0);
1049 partinfo
= gtk_ctree_node_get_row_data(ctree
, node
);
1050 if (!partinfo
) return;
1052 /* ungrab the mouse event */
1053 if (GTK_WIDGET_HAS_GRAB(ctree
)) {
1054 gtk_grab_remove(GTK_WIDGET(ctree
));
1055 if (gdk_pointer_is_grabbed())
1056 gdk_pointer_ungrab(GDK_CURRENT_TIME
);
1059 mimeview
->textview
->default_text
= FALSE
;
1061 update_signature_info(mimeview
, partinfo
);
1063 if (!mimeview_show_part(mimeview
, partinfo
)) {
1064 switch (partinfo
->type
) {
1066 case MIMETYPE_MESSAGE
:
1067 case MIMETYPE_MULTIPART
:
1068 mimeview_show_message_part(mimeview
, partinfo
);
1072 mimeview
->textview
->default_text
= TRUE
;
1073 mimeview_change_view_type(mimeview
, MIMEVIEW_TEXT
);
1074 textview_clear(mimeview
->textview
);
1075 textview_show_mime_part(mimeview
->textview
, partinfo
);
1081 static void mimeview_start_drag(GtkWidget
*widget
, gint button
,
1082 GdkEvent
*event
, MimeView
*mimeview
)
1084 GdkDragContext
*context
;
1087 g_return_if_fail(mimeview
!= NULL
);
1089 partinfo
= mimeview_get_selected_part(mimeview
);
1090 if (partinfo
->disposition
== DISPOSITIONTYPE_INLINE
) return;
1092 context
= gtk_drag_begin(widget
, mimeview
->target_list
,
1093 GDK_ACTION_COPY
, button
, event
);
1094 gtk_drag_set_icon_default(context
);
1097 static gint
mimeview_button_pressed(GtkWidget
*widget
, GdkEventButton
*event
,
1100 GtkCList
*clist
= GTK_CLIST(widget
);
1103 if (!event
) return FALSE
;
1105 if (event
->button
== 2 || event
->button
== 3) {
1106 if (!gtk_clist_get_selection_info(clist
, event
->x
, event
->y
,
1109 gtk_clist_unselect_all(clist
);
1110 gtk_clist_select_row(clist
, row
, column
);
1111 gtkut_clist_set_focus_row(clist
, row
);
1113 part_button_pressed(mimeview
, event
, mimeview_get_selected_part(mimeview
));
1118 static gboolean
mimeview_scrolled(GtkWidget
*widget
, GdkEventScroll
*event
,
1121 GtkVScrollbutton
*scrollbutton
= (GtkVScrollbutton
*)mimeview
->scrollbutton
;
1122 if (event
->direction
== GDK_SCROLL_UP
) {
1123 scrollbutton
->scroll_type
= GTK_SCROLL_STEP_BACKWARD
;
1125 scrollbutton
->scroll_type
= GTK_SCROLL_STEP_FORWARD
;
1127 gtk_vscrollbutton_scroll(scrollbutton
);
1131 /* from gdkevents.c */
1132 #define DOUBLE_CLICK_TIME 250
1134 static gboolean
part_button_pressed(MimeView
*mimeview
, GdkEventButton
*event
,
1137 static MimeInfo
*lastinfo
;
1138 static guint32 lasttime
;
1140 if (event
->button
== 2 ||
1141 (event
->button
== 1 && (event
->time
- lasttime
) < DOUBLE_CLICK_TIME
&& lastinfo
== partinfo
)) {
1142 /* call external program for image, audio or html */
1143 mimeview_launch(mimeview
);
1145 } else if (event
->button
== 3) {
1146 if (partinfo
&& (partinfo
->type
== MIMETYPE_MESSAGE
||
1147 partinfo
->type
== MIMETYPE_IMAGE
||
1148 partinfo
->type
== MIMETYPE_MULTIPART
))
1149 menu_set_sensitive(mimeview
->popupfactory
,
1150 "/Display as text", FALSE
);
1152 menu_set_sensitive(mimeview
->popupfactory
,
1153 "/Display as text", TRUE
);
1155 partinfo
->type
== MIMETYPE_APPLICATION
&&
1156 !g_ascii_strcasecmp(partinfo
->subtype
, "octet-stream"))
1157 menu_set_sensitive(mimeview
->popupfactory
,
1160 menu_set_sensitive(mimeview
->popupfactory
,
1163 g_object_set_data(G_OBJECT(mimeview
->popupmenu
),
1164 "pop_partinfo", partinfo
);
1166 gtk_menu_popup(GTK_MENU(mimeview
->popupmenu
),
1167 NULL
, NULL
, NULL
, NULL
,
1168 event
->button
, event
->time
);
1172 lastinfo
= partinfo
;
1173 lasttime
= event
->time
;
1178 void mimeview_pass_key_press_event(MimeView
*mimeview
, GdkEventKey
*event
)
1180 mimeview_key_pressed(mimeview
->ctree
, event
, mimeview
);
1183 #define BREAK_ON_MODIFIER_KEY() \
1184 if ((event->state & (GDK_MOD1_MASK|GDK_CONTROL_MASK)) != 0) break
1186 #define KEY_PRESS_EVENT_STOP() \
1187 g_signal_stop_emission_by_name(G_OBJECT(ctree), \
1190 static gint
mimeview_key_pressed(GtkWidget
*widget
, GdkEventKey
*event
,
1193 SummaryView
*summaryview
;
1194 GtkCTree
*ctree
= GTK_CTREE(widget
);
1197 if (!event
) return FALSE
;
1198 if (!mimeview
->opened
) return FALSE
;
1200 summaryview
= mimeview
->messageview
->mainwin
->summaryview
;
1202 if (summaryview
&& quicksearch_has_focus(summaryview
->quicksearch
))
1205 switch (event
->keyval
) {
1207 if (textview_scroll_page(mimeview
->textview
, FALSE
))
1210 node
= GTK_CTREE_NODE_NEXT(mimeview
->opened
);
1212 gtk_sctree_unselect_all(GTK_SCTREE(ctree
));
1213 gtk_sctree_select(GTK_SCTREE(ctree
), node
);
1218 textview_scroll_page(mimeview
->textview
, TRUE
);
1221 textview_scroll_one_line(mimeview
->textview
,
1222 (event
->state
& GDK_MOD1_MASK
) != 0);
1226 BREAK_ON_MODIFIER_KEY();
1227 if (!GTK_CTREE_NODE_NEXT(mimeview
->opened
)) break;
1228 KEY_PRESS_EVENT_STOP();
1229 g_signal_emit_by_name(G_OBJECT(ctree
), "scroll_vertical",
1230 GTK_SCROLL_STEP_FORWARD
, 0.0);
1234 BREAK_ON_MODIFIER_KEY();
1235 if (!GTK_CTREE_NODE_PREV(mimeview
->opened
)) break;
1236 KEY_PRESS_EVENT_STOP();
1237 g_signal_emit_by_name(G_OBJECT(ctree
), "scroll_vertical",
1238 GTK_SCROLL_STEP_BACKWARD
, 0.0);
1241 BREAK_ON_MODIFIER_KEY();
1242 KEY_PRESS_EVENT_STOP();
1243 mimeview_save_as(mimeview
);
1246 BREAK_ON_MODIFIER_KEY();
1247 KEY_PRESS_EVENT_STOP();
1248 mimeview_display_as_text(mimeview
);
1251 BREAK_ON_MODIFIER_KEY();
1252 KEY_PRESS_EVENT_STOP();
1253 mimeview_launch(mimeview
);
1256 BREAK_ON_MODIFIER_KEY();
1257 KEY_PRESS_EVENT_STOP();
1258 mimeview_open_with(mimeview
);
1261 BREAK_ON_MODIFIER_KEY();
1262 KEY_PRESS_EVENT_STOP();
1263 mimeview_check_signature(mimeview
);
1269 if (!mimeview
->messageview
->mainwin
) return FALSE
;
1271 summary_pass_key_press_event(summaryview
, event
);
1275 static void mimeview_drag_data_get(GtkWidget
*widget
,
1276 GdkDragContext
*drag_context
,
1277 GtkSelectionData
*selection_data
,
1282 gchar
*filename
= NULL
, *uriname
, *tmp
;
1285 if (!mimeview
->opened
) return;
1286 if (!mimeview
->file
) return;
1288 partinfo
= mimeview_get_selected_part(mimeview
);
1289 if (!partinfo
) return;
1291 if (strlen(get_part_name(partinfo
)) > 0) {
1292 filename
= g_path_get_basename(get_part_name(partinfo
));
1293 if (*filename
== '\0') return;
1294 } else if (partinfo
->type
== MIMETYPE_MESSAGE
1295 && !g_ascii_strcasecmp(partinfo
->subtype
, "rfc822")) {
1297 GPtrArray
*headers
= NULL
;
1300 fp
= g_fopen(partinfo
->data
.filename
, "rb");
1301 fseek(fp
, partinfo
->offset
, SEEK_SET
);
1302 headers
= procheader_get_header_array_asis(fp
);
1305 for (i
= 0; i
< headers
->len
; i
++) {
1306 Header
*header
= g_ptr_array_index(headers
, i
);
1307 if (procheader_headername_equal(header
->name
, "Subject")) {
1308 unfold_line(header
->body
);
1309 name
= g_strconcat(header
->body
, ".txt", NULL
);
1310 subst_for_filename(name
);
1313 procheader_header_array_destroy(headers
);
1317 filename
= g_path_get_basename(name
);
1320 if (filename
== NULL
)
1321 filename
= g_path_get_basename("Unnamed part");
1324 tmp
= g_filename_from_utf8(filename
, -1, NULL
, NULL
, NULL
);
1327 g_warning("filename not in UTF-8");
1328 tmp
= g_strdup("Unnamed part");
1330 filename
= g_strconcat(get_mime_tmp_dir(), G_DIR_SEPARATOR_S
,
1335 if (procmime_get_part(filename
, partinfo
) < 0)
1337 (_("Can't save the part of multipart message."));
1338 uriname
= g_strconcat("file://", filename
, "\r\n", NULL
);
1340 gtk_selection_data_set(selection_data
, selection_data
->target
, 8,
1341 (guchar
*)uriname
, strlen(uriname
));
1348 * Returns a filename (with path) for an attachment
1349 * \param partinfo The attachment to save
1350 * \param basedir The target directory
1351 * \param number Used for dummy filename if attachment is unnamed
1353 gchar
*mimeview_get_filename_for_part(MimeInfo
*partinfo
,
1354 const gchar
*basedir
,
1360 filename
= g_strdup(get_part_name(partinfo
));
1361 if (!filename
|| !*filename
)
1362 filename
= g_strdup_printf("noname.%d", number
);
1364 if (!g_utf8_validate(filename
, -1, NULL
)) {
1365 gchar
*tmp
= conv_filename_to_utf8(filename
);
1370 subst_for_filename(filename
);
1372 fullname
= g_strconcat
1373 (basedir
, G_DIR_SEPARATOR_S
, (filename
[0] == G_DIR_SEPARATOR
)
1374 ? &filename
[1] : filename
, NULL
);
1377 filename
= conv_filename_from_utf8(fullname
);
1383 * Write a single attachment to file
1384 * \param filename Filename with path
1385 * \param partinfo Attachment to save
1387 static gboolean
mimeview_write_part(const gchar
*filename
,
1392 dir
= g_path_get_dirname(filename
);
1393 if (!is_dir_exist(dir
))
1397 if (is_file_exist(filename
)) {
1402 if (!g_utf8_validate(filename
, -1, NULL
))
1403 tmp
= conv_filename_to_utf8(filename
);
1405 tmp
= g_strdup(filename
);
1407 res
= g_strdup_printf(_("Overwrite existing file '%s'?"),
1410 aval
= alertpanel(_("Overwrite"), res
, GTK_STOCK_CANCEL
,
1411 GTK_STOCK_OK
, NULL
);
1413 if (G_ALERTALTERNATE
!= aval
) return FALSE
;
1416 if (procmime_get_part(filename
, partinfo
) < 0) {
1418 (_("Can't save the part of multipart message."));
1426 * Menu callback: Save all attached files
1427 * \param mimeview Current display
1429 static void mimeview_save_all(MimeView
*mimeview
)
1433 gchar
*startdir
= NULL
;
1436 if (!mimeview
->opened
) return;
1437 if (!mimeview
->file
) return;
1438 if (!mimeview
->mimeinfo
) return;
1440 partinfo
= mimeview
->mimeinfo
;
1441 if (prefs_common
.attach_save_dir
)
1442 startdir
= g_strconcat(prefs_common
.attach_save_dir
,
1443 G_DIR_SEPARATOR_S
, NULL
);
1445 dirname
= filesel_select_file_save_folder(_("Select destination folder"), startdir
);
1451 if (!is_dir_exist (dirname
)) {
1452 alertpanel_error(_("'%s' is not a directory."),
1458 if (dirname
[strlen(dirname
)-1] == G_DIR_SEPARATOR
)
1459 dirname
[strlen(dirname
)-1] = '\0';
1461 /* Skip the first part, that is sometimes DISPOSITIONTYPE_UNKNOWN */
1462 if (partinfo
&& partinfo
->type
== MIMETYPE_MESSAGE
)
1463 partinfo
= procmime_mimeinfo_next(partinfo
);
1464 if (partinfo
&& partinfo
->type
== MIMETYPE_MULTIPART
) {
1465 partinfo
= procmime_mimeinfo_next(partinfo
);
1466 if (partinfo
&& partinfo
->type
== MIMETYPE_TEXT
)
1467 partinfo
= procmime_mimeinfo_next(partinfo
);
1470 while (partinfo
!= NULL
) {
1471 if (partinfo
->type
!= MIMETYPE_MESSAGE
&&
1472 partinfo
->type
!= MIMETYPE_MULTIPART
&&
1473 (partinfo
->disposition
!= DISPOSITIONTYPE_INLINE
1474 || get_real_part_name(partinfo
) != NULL
)) {
1475 gchar
*filename
= mimeview_get_filename_for_part
1476 (partinfo
, dirname
, number
++);
1478 mimeview_write_part(filename
, partinfo
);
1481 partinfo
= procmime_mimeinfo_next(partinfo
);
1484 g_free(prefs_common
.attach_save_dir
);
1486 prefs_common
.attach_save_dir
= g_strdup(dirname
);
1489 static MimeInfo
*mimeview_get_part_to_use(MimeView
*mimeview
)
1491 MimeInfo
*partinfo
= NULL
;
1492 if (mimeview
->spec_part
) {
1493 partinfo
= mimeview
->spec_part
;
1494 mimeview
->spec_part
= NULL
;
1496 partinfo
= mimeview_get_selected_part(mimeview
);
1498 partinfo
= (MimeInfo
*) g_object_get_data
1499 (G_OBJECT(mimeview
->popupmenu
),
1501 g_object_set_data(G_OBJECT(mimeview
->popupmenu
),
1502 "pop_partinfo", NULL
);
1509 * Menu callback: Save the selected attachment
1510 * \param mimeview Current display
1512 static void mimeview_save_as(MimeView
*mimeview
)
1515 gchar
*filepath
= NULL
;
1516 gchar
*filedir
= NULL
;
1518 gchar
*partname
= NULL
;
1520 if (!mimeview
->opened
) return;
1521 if (!mimeview
->file
) return;
1523 partinfo
= mimeview_get_part_to_use(mimeview
);
1525 g_return_if_fail(partinfo
!= NULL
);
1527 if (get_part_name(partinfo
) == NULL
) {
1530 partname
= g_strdup(get_part_name(partinfo
));
1532 if (!g_utf8_validate(partname
, -1, NULL
)) {
1533 gchar
*tmp
= conv_filename_to_utf8(partname
);
1538 subst_for_filename(partname
);
1540 if (prefs_common
.attach_save_dir
)
1541 filepath
= g_strconcat(prefs_common
.attach_save_dir
,
1542 G_DIR_SEPARATOR_S
, partname
, NULL
);
1544 filepath
= g_strdup(partname
);
1548 filename
= filesel_select_file_save(_("Save as"), filepath
);
1554 mimeview_write_part(filename
, partinfo
);
1556 filedir
= g_path_get_dirname(filename
);
1557 if (filedir
&& strcmp(filedir
, ".")) {
1558 g_free(prefs_common
.attach_save_dir
);
1559 prefs_common
.attach_save_dir
= g_strdup(filedir
);
1566 static void mimeview_display_as_text(MimeView
*mimeview
)
1570 if (!mimeview
->opened
) return;
1572 partinfo
= mimeview_get_part_to_use(mimeview
);
1574 g_return_if_fail(partinfo
!= NULL
);
1575 mimeview_show_message_part(mimeview
, partinfo
);
1578 static void mimeview_launch(MimeView
*mimeview
)
1583 if (!mimeview
->opened
) return;
1584 if (!mimeview
->file
) return;
1586 partinfo
= mimeview_get_part_to_use(mimeview
);
1588 g_return_if_fail(partinfo
!= NULL
);
1590 filename
= procmime_get_tmp_file_name(partinfo
);
1592 if (procmime_get_part(filename
, partinfo
) < 0)
1594 (_("Can't save the part of multipart message."));
1596 mimeview_view_file(filename
, partinfo
, NULL
, mimeview
);
1601 static void mimeview_open_with(MimeView
*mimeview
)
1605 if (!mimeview
) return;
1606 if (!mimeview
->opened
) return;
1607 if (!mimeview
->file
) return;
1609 partinfo
= mimeview_get_part_to_use(mimeview
);
1611 mimeview_open_part_with(mimeview
, partinfo
, FALSE
);
1614 static void mimeview_open_part_with(MimeView
*mimeview
, MimeInfo
*partinfo
, gboolean automatic
)
1618 gchar
*mime_command
= NULL
;
1619 gchar
*content_type
= NULL
;
1621 g_return_if_fail(partinfo
!= NULL
);
1623 filename
= procmime_get_tmp_file_name(partinfo
);
1625 if (procmime_get_part(filename
, partinfo
) < 0) {
1627 (_("Can't save the part of multipart message."));
1632 if (!prefs_common
.mime_open_cmd_history
)
1633 prefs_common
.mime_open_cmd_history
=
1634 add_history(NULL
, prefs_common
.mime_open_cmd
);
1636 if ((partinfo
->type
== MIMETYPE_APPLICATION
) &&
1637 (!g_ascii_strcasecmp(partinfo
->subtype
, "octet-stream"))) {
1638 /* guess content-type from filename */
1639 content_type
= procmime_get_mime_type(filename
);
1641 if (content_type
== NULL
) {
1642 content_type
= procmime_get_content_type_str(partinfo
->type
,
1646 if (partinfo
->type
!= MIMETYPE_TEXT
|| !prefs_common
.ext_editor_cmd
1647 || !prefs_common
.ext_editor_cmd
[0])
1648 mime_command
= mailcap_get_command_for_type(content_type
, filename
);
1650 mime_command
= g_strdup(prefs_common
.ext_editor_cmd
);
1651 if (mime_command
== NULL
) {
1652 /* try with extension this time */
1653 g_free(content_type
);
1654 content_type
= procmime_get_mime_type(filename
);
1655 mime_command
= mailcap_get_command_for_type(content_type
, filename
);
1658 if (mime_command
== NULL
)
1662 gboolean remember
= FALSE
;
1663 if (content_type
!= NULL
)
1664 cmd
= input_dialog_combo_remember
1666 _("Enter the command line to open file:\n"
1667 "('%s' will be replaced with file name)"),
1668 mime_command
? mime_command
: prefs_common
.mime_open_cmd
,
1669 prefs_common
.mime_open_cmd_history
,
1672 cmd
= input_dialog_combo
1674 _("Enter the command line to open file:\n"
1675 "('%s' will be replaced with file name)"),
1676 mime_command
? mime_command
: prefs_common
.mime_open_cmd
,
1677 prefs_common
.mime_open_cmd_history
,
1679 if (cmd
&& remember
) {
1680 mailcap_update_default(content_type
, cmd
);
1682 g_free(mime_command
);
1687 mimeview_view_file(filename
, partinfo
, cmd
, mimeview
);
1688 g_free(prefs_common
.mime_open_cmd
);
1689 prefs_common
.mime_open_cmd
= cmd
;
1690 prefs_common
.mime_open_cmd_history
=
1691 add_history(prefs_common
.mime_open_cmd_history
, cmd
);
1693 g_free(content_type
);
1697 static void mimeview_view_file(const gchar
*filename
, MimeInfo
*partinfo
,
1698 const gchar
*cmd
, MimeView
*mimeview
)
1701 gchar buf
[BUFFSIZE
];
1703 mimeview_open_part_with(mimeview
, partinfo
, TRUE
);
1705 if ((p
= strchr(cmd
, '%')) && *(p
+ 1) == 's' &&
1706 !strchr(p
+ 2, '%'))
1707 g_snprintf(buf
, sizeof(buf
), cmd
, filename
);
1709 g_warning("MIME viewer command line is invalid: '%s'", cmd
);
1710 mimeview_open_part_with(mimeview
, partinfo
, FALSE
);
1712 if (execute_command_line(buf
, TRUE
) != 0)
1713 mimeview_open_part_with(mimeview
, partinfo
, FALSE
);
1717 void mimeview_register_viewer_factory(MimeViewerFactory
*factory
)
1719 mimeviewer_factories
= g_slist_append(mimeviewer_factories
, factory
);
1722 static gint
cmp_viewer_by_factroy(gconstpointer a
, gconstpointer b
)
1724 return ((MimeViewer
*) a
)->factory
== (MimeViewerFactory
*) b
? 0 : -1;
1727 void mimeview_unregister_viewer_factory(MimeViewerFactory
*factory
)
1729 GSList
*mimeview_list
, *viewer_list
;
1731 for (mimeview_list
= mimeviews
; mimeview_list
!= NULL
; mimeview_list
= g_slist_next(mimeview_list
)) {
1732 MimeView
*mimeview
= (MimeView
*) mimeview_list
->data
;
1734 if (mimeview
->mimeviewer
&& mimeview
->mimeviewer
->factory
== factory
) {
1735 mimeview_change_view_type(mimeview
, MIMEVIEW_TEXT
);
1736 mimeview
->mimeviewer
= NULL
;
1739 while ((viewer_list
= g_slist_find_custom(mimeview
->viewers
, factory
, cmp_viewer_by_factroy
)) != NULL
) {
1740 MimeViewer
*mimeviewer
= (MimeViewer
*) viewer_list
->data
;
1742 mimeviewer
->destroy_viewer(mimeviewer
);
1743 mimeview
->viewers
= g_slist_remove(mimeview
->viewers
, mimeviewer
);
1747 mimeviewer_factories
= g_slist_remove(mimeviewer_factories
, factory
);
1750 static gboolean
icon_clicked_cb (GtkWidget
*button
, GdkEventButton
*event
, MimeView
*mimeview
)
1755 num
= GPOINTER_TO_INT(g_object_get_data(G_OBJECT(button
), "icon_number"));
1756 partinfo
= g_object_get_data(G_OBJECT(button
), "partinfo");
1758 icon_selected(mimeview
, num
, partinfo
);
1759 gtk_widget_grab_focus(button
);
1760 if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button
))) {
1761 toggle_icon(GTK_TOGGLE_BUTTON(button
), mimeview
);
1762 if (event
->button
== 2 || event
->button
== 3)
1763 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button
),
1767 part_button_pressed(mimeview
, event
, partinfo
);
1772 static void icon_selected (MimeView
*mimeview
, gint num
, MimeInfo
*partinfo
)
1775 node
= gtk_ctree_find_by_row_data(GTK_CTREE(mimeview
->ctree
), NULL
, partinfo
);
1777 gtk_ctree_select(GTK_CTREE(mimeview
->ctree
), node
);
1780 void mimeview_select_mimepart_icon(MimeView
*mimeview
, MimeInfo
*partinfo
)
1782 icon_list_toggle_by_mime_info(mimeview
, partinfo
);
1783 icon_selected(mimeview
, -1, partinfo
);
1786 #undef KEY_PRESS_EVENT_STOP
1787 #define KEY_PRESS_EVENT_STOP() \
1788 g_signal_stop_emission_by_name(G_OBJECT(button), \
1791 static gint
icon_key_pressed(GtkWidget
*button
, GdkEventKey
*event
,
1796 SummaryView
*summaryview
;
1799 num
= GPOINTER_TO_INT(g_object_get_data(G_OBJECT(button
), "icon_number"));
1800 partinfo
= g_object_get_data(G_OBJECT(button
), "partinfo");
1802 if (!event
) return FALSE
;
1804 textview
= mimeview
->textview
;
1806 switch (event
->keyval
) {
1808 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button
))) {
1809 /* stop the button being untoggled */
1810 KEY_PRESS_EVENT_STOP();
1811 if (textview_scroll_page(textview
, FALSE
))
1814 if (icon_list_select_by_number(mimeview
, num
+ 1))
1817 icon_selected(mimeview
, num
, partinfo
);
1818 toggle_icon(GTK_TOGGLE_BUTTON(button
), mimeview
);
1824 textview_scroll_page(textview
, TRUE
);
1827 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button
))) {
1828 KEY_PRESS_EVENT_STOP();
1829 textview_scroll_one_line(textview
,
1830 (event
->state
& GDK_MOD1_MASK
) != 0);
1833 icon_selected(mimeview
, num
, partinfo
);
1834 toggle_icon(GTK_TOGGLE_BUTTON(button
), mimeview
);
1840 BREAK_ON_MODIFIER_KEY();
1841 if (icon_list_select_by_number(mimeview
, num
+ 1)) {
1842 KEY_PRESS_EVENT_STOP();
1849 BREAK_ON_MODIFIER_KEY();
1850 if (icon_list_select_by_number(mimeview
, num
- 1)) {
1851 KEY_PRESS_EVENT_STOP();
1857 BREAK_ON_MODIFIER_KEY();
1858 KEY_PRESS_EVENT_STOP();
1859 mimeview_save_as(mimeview
);
1862 BREAK_ON_MODIFIER_KEY();
1863 KEY_PRESS_EVENT_STOP();
1864 mimeview_display_as_text(mimeview
);
1867 BREAK_ON_MODIFIER_KEY();
1868 KEY_PRESS_EVENT_STOP();
1869 mimeview_launch(mimeview
);
1872 BREAK_ON_MODIFIER_KEY();
1873 KEY_PRESS_EVENT_STOP();
1874 mimeview_open_with(mimeview
);
1877 BREAK_ON_MODIFIER_KEY();
1878 KEY_PRESS_EVENT_STOP();
1879 mimeview_check_signature(mimeview
);
1885 if (!mimeview
->messageview
->mainwin
) return FALSE
;
1886 summaryview
= mimeview
->messageview
->mainwin
->summaryview
;
1887 return summary_pass_key_press_event(summaryview
, event
);
1890 static void toggle_icon(GtkToggleButton
*button
, MimeView
*mimeview
)
1894 child
= gtk_container_get_children(GTK_CONTAINER(mimeview
->icon_vbox
));
1895 for (; child
!= NULL
; child
= g_list_next(child
)) {
1896 if (GTK_IS_TOGGLE_BUTTON(child
->data
) &&
1897 GTK_TOGGLE_BUTTON(child
->data
) != button
&&
1898 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(child
->data
)))
1899 gtk_toggle_button_set_active
1900 (GTK_TOGGLE_BUTTON(child
->data
),
1905 static void icon_list_append_icon (MimeView
*mimeview
, MimeInfo
*mimeinfo
)
1907 GtkWidget
*pixmap
= NULL
;
1912 const gchar
*desc
= NULL
;
1913 gchar
*sigshort
= NULL
;
1914 gchar
*content_type
;
1917 MimeInfo
*siginfo
= NULL
;
1918 MimeInfo
*encrypted
= NULL
;
1920 vbox
= mimeview
->icon_vbox
;
1921 mimeview
->icon_count
++;
1922 button
= gtk_toggle_button_new();
1923 gtk_button_set_relief(GTK_BUTTON(button
), GTK_RELIEF_NONE
);
1924 g_object_set_data(G_OBJECT(button
), "icon_number",
1925 GINT_TO_POINTER(mimeview
->icon_count
));
1926 g_object_set_data(G_OBJECT(button
), "partinfo",
1929 switch (mimeinfo
->type
) {
1932 if (mimeinfo
->subtype
&& !g_ascii_strcasecmp(mimeinfo
->subtype
, "html"))
1933 stockp
= STOCK_PIXMAP_MIME_TEXT_HTML
;
1934 else if (mimeinfo
->subtype
&& !g_ascii_strcasecmp(mimeinfo
->subtype
, "enriched"))
1935 stockp
= STOCK_PIXMAP_MIME_TEXT_ENRICHED
;
1937 stockp
= STOCK_PIXMAP_MIME_TEXT_PLAIN
;
1939 case MIMETYPE_MESSAGE
:
1940 stockp
= STOCK_PIXMAP_MIME_MESSAGE
;
1942 case MIMETYPE_APPLICATION
:
1943 stockp
= STOCK_PIXMAP_MIME_APPLICATION
;
1945 case MIMETYPE_IMAGE
:
1946 stockp
= STOCK_PIXMAP_MIME_IMAGE
;
1948 case MIMETYPE_AUDIO
:
1949 stockp
= STOCK_PIXMAP_MIME_AUDIO
;
1952 stockp
= STOCK_PIXMAP_MIME_UNKNOWN
;
1956 partinfo
= mimeinfo
;
1957 while (partinfo
!= NULL
) {
1958 if (privacy_mimeinfo_is_signed(partinfo
)) {
1962 if (privacy_mimeinfo_is_encrypted(partinfo
)) {
1963 encrypted
= partinfo
;
1966 partinfo
= procmime_mimeinfo_parent(partinfo
);
1969 if (siginfo
!= NULL
) {
1970 switch (privacy_mimeinfo_get_sig_status(siginfo
)) {
1971 case SIGNATURE_UNCHECKED
:
1972 case SIGNATURE_CHECK_FAILED
:
1973 case SIGNATURE_CHECK_TIMEOUT
:
1974 pixmap
= stock_pixmap_widget_with_overlay(mimeview
->mainwin
->window
, stockp
,
1975 STOCK_PIXMAP_PRIVACY_EMBLEM_SIGNED
, OVERLAY_BOTTOM_RIGHT
, 6, 3);
1978 pixmap
= stock_pixmap_widget_with_overlay(mimeview
->mainwin
->window
, stockp
,
1979 STOCK_PIXMAP_PRIVACY_EMBLEM_PASSED
, OVERLAY_BOTTOM_RIGHT
, 6, 3);
1981 case SIGNATURE_WARN
:
1982 pixmap
= stock_pixmap_widget_with_overlay(mimeview
->mainwin
->window
, stockp
,
1983 STOCK_PIXMAP_PRIVACY_EMBLEM_WARN
, OVERLAY_BOTTOM_RIGHT
, 6, 3);
1985 case SIGNATURE_INVALID
:
1986 pixmap
= stock_pixmap_widget_with_overlay(mimeview
->mainwin
->window
, stockp
,
1987 STOCK_PIXMAP_PRIVACY_EMBLEM_FAILED
, OVERLAY_BOTTOM_RIGHT
, 6, 3);
1990 sigshort
= privacy_mimeinfo_sig_info_short(siginfo
);
1991 } else if (encrypted
!= NULL
) {
1992 pixmap
= stock_pixmap_widget_with_overlay(mimeview
->mainwin
->window
, stockp
,
1993 STOCK_PIXMAP_PRIVACY_EMBLEM_ENCRYPTED
, OVERLAY_BOTTOM_RIGHT
, 6, 3);
1995 pixmap
= stock_pixmap_widget_with_overlay(mimeview
->mainwin
->window
, stockp
, 0,
1996 OVERLAY_NONE
, 6, 3);
1998 gtk_container_add(GTK_CONTAINER(button
), pixmap
);
2001 if (prefs_common
.attach_desc
)
2002 desc
= get_part_description(mimeinfo
);
2004 desc
= get_part_name(mimeinfo
);
2007 content_type
= procmime_get_content_type_str(mimeinfo
->type
,
2010 tip
= g_strjoin("\n", content_type
,
2011 to_human_readable(mimeinfo
->length
), NULL
);
2012 g_free(content_type
);
2013 if (desc
&& *desc
) {
2015 if (!g_utf8_validate(desc
, -1, NULL
)) {
2016 tmp
= conv_filename_to_utf8(desc
);
2018 tmp
= g_strdup(desc
);
2020 tiptmp
= g_strjoin("\n", tmp
, tip
, NULL
);
2025 if (sigshort
&& *sigshort
) {
2026 tiptmp
= g_strjoin("\n", tip
, sigshort
, NULL
);
2032 gtk_tooltips_set_tip(mimeview
->tooltips
, button
, tip
, NULL
);
2034 gtk_widget_show_all(button
);
2035 gtk_drag_source_set(button
, GDK_BUTTON1_MASK
|GDK_BUTTON3_MASK
,
2036 mimeview_mime_types
, 1, GDK_ACTION_COPY
);
2037 g_signal_connect(G_OBJECT(button
), "button_release_event",
2038 G_CALLBACK(icon_clicked_cb
), mimeview
);
2039 g_signal_connect(G_OBJECT(button
), "key_press_event",
2040 G_CALLBACK(icon_key_pressed
), mimeview
);
2041 g_signal_connect(G_OBJECT(button
), "drag_data_get",
2042 G_CALLBACK(mimeview_drag_data_get
), mimeview
);
2043 gtk_box_pack_start(GTK_BOX(vbox
), button
, FALSE
, FALSE
, 0);
2047 static void icon_list_clear (MimeView
*mimeview
)
2052 child
= gtk_container_children(GTK_CONTAINER(mimeview
->icon_vbox
));
2053 for (; child
!= NULL
; child
= g_list_next(child
)) {
2054 gtkut_container_remove(GTK_CONTAINER(mimeview
->icon_vbox
),
2055 GTK_WIDGET(child
->data
));
2056 gtk_widget_destroy(GTK_WIDGET(child
->data
));
2059 mimeview
->icon_count
= 0;
2060 adj
= gtk_layout_get_vadjustment(GTK_LAYOUT(mimeview
->icon_scroll
));
2061 gtk_adjustment_set_value(adj
, adj
->lower
);
2064 static void icon_list_toggle_by_mime_info(MimeView
*mimeview
,
2069 child
= gtk_container_children(GTK_CONTAINER(mimeview
->icon_vbox
));
2070 for (; child
!= NULL
; child
= g_list_next(child
)) {
2071 if (GTK_IS_TOGGLE_BUTTON(child
->data
) &&
2072 g_object_get_data(G_OBJECT(child
->data
),
2073 "partinfo") == (gpointer
)mimeinfo
) {
2074 toggle_icon(GTK_TOGGLE_BUTTON(child
->data
), mimeview
);
2075 gtk_toggle_button_set_active
2076 (GTK_TOGGLE_BUTTON(child
->data
), TRUE
);
2082 *\brief Used to 'click' the next or previous icon.
2084 *\return true if the icon 'number' exists and was selected.
2086 static gboolean
icon_list_select_by_number(MimeView
*mimeview
,
2091 if (number
== 0) return FALSE
;
2092 child
= gtk_container_children(GTK_CONTAINER(mimeview
->icon_vbox
));
2093 for (; child
!= NULL
; child
= g_list_next(child
)) {
2094 if (GTK_IS_TOGGLE_BUTTON(child
->data
) &&
2095 GPOINTER_TO_INT(g_object_get_data(G_OBJECT(child
->data
),
2096 "icon_number")) == number
) {
2097 icon_selected(mimeview
, number
,
2098 (MimeInfo
*)g_object_get_data(G_OBJECT(child
->data
),
2100 toggle_icon(GTK_TOGGLE_BUTTON(child
->data
), mimeview
);
2101 gtk_toggle_button_set_active
2102 (GTK_TOGGLE_BUTTON(child
->data
), TRUE
);
2103 gtk_widget_grab_focus(GTK_WIDGET(child
->data
));
2111 static void icon_scroll_size_allocate_cb(GtkWidget
*widget
,
2112 GtkAllocation
*size
, MimeView
*mimeview
)
2114 GtkAllocation
*mainbox_size
;
2115 GtkAllocation
*vbox_size
;
2116 GtkAllocation
*layout_size
;
2119 adj
= gtk_layout_get_vadjustment(GTK_LAYOUT(mimeview
->icon_scroll
));
2121 mainbox_size
= &mimeview
->icon_mainbox
->allocation
;
2122 vbox_size
= &mimeview
->icon_vbox
->allocation
;
2123 layout_size
= &mimeview
->icon_scroll
->allocation
;
2125 gtk_layout_set_size(GTK_LAYOUT(mimeview
->icon_scroll
),
2126 GTK_LAYOUT(mimeview
->icon_scroll
)->width
,
2127 MAX(vbox_size
->height
, layout_size
->height
));
2128 adj
->step_increment
= 10;
2131 static void icon_list_create(MimeView
*mimeview
, MimeInfo
*mimeinfo
)
2133 GtkRequisition size
;
2135 g_return_if_fail(mimeinfo
!= NULL
);
2137 while (mimeinfo
!= NULL
) {
2138 if (mimeinfo
->type
!= MIMETYPE_MULTIPART
)
2139 icon_list_append_icon(mimeview
, mimeinfo
);
2140 if (mimeinfo
->node
->children
!= NULL
)
2141 icon_list_create(mimeview
,
2142 (MimeInfo
*) mimeinfo
->node
->children
->data
);
2143 mimeinfo
= mimeinfo
->node
->next
!= NULL
2144 ? (MimeInfo
*) mimeinfo
->node
->next
->data
2147 gtk_widget_size_request(mimeview
->icon_vbox
, &size
);
2148 if (size
.width
> mimeview
->icon_mainbox
->requisition
.width
) {
2149 gtk_widget_set_size_request(mimeview
->icon_mainbox
,
2155 static void mime_toggle_button_cb (GtkWidget
*button
, MimeView
*mimeview
)
2157 gtk_widget_ref(button
);
2159 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button
))) {
2160 gtk_arrow_set(GTK_ARROW(GTK_BIN(button
)->child
), GTK_ARROW_RIGHT
,
2162 gtk_widget_hide(mimeview
->icon_mainbox
);
2163 gtk_widget_show(mimeview
->ctree_mainbox
);
2164 gtk_paned_set_position(GTK_PANED(mimeview
->paned
), mimeview
->oldsize
);
2166 gtkut_container_remove(GTK_CONTAINER(mimeview
->icon_mainbox
),
2168 gtk_box_pack_end(GTK_BOX(mimeview
->ctree_mainbox
),
2169 button
, FALSE
, FALSE
, 0);
2170 gtk_paned_set_gutter_size(GTK_PANED(mimeview
->paned
), 6);
2172 gtk_arrow_set(GTK_ARROW(GTK_BIN(button
)->child
), GTK_ARROW_LEFT
,
2174 mimeview
->oldsize
= mimeview
->ctree_mainbox
->allocation
.height
;
2175 gtk_widget_hide(mimeview
->ctree_mainbox
);
2176 gtk_widget_show(mimeview
->icon_mainbox
);
2177 gtk_paned_set_position(GTK_PANED(mimeview
->paned
), 0);
2179 gtkut_container_remove(GTK_CONTAINER(mimeview
->ctree_mainbox
),
2181 gtk_box_pack_start(GTK_BOX(mimeview
->icon_mainbox
),
2182 button
, FALSE
, FALSE
, 0);
2183 gtk_box_reorder_child(GTK_BOX(button
->parent
), button
, 0);
2184 if (mimeview
->opened
)
2185 icon_list_toggle_by_mime_info
2186 (mimeview
, gtk_ctree_node_get_row_data(GTK_CTREE(mimeview
->ctree
),
2189 gtk_paned_set_gutter_size(GTK_PANED(mimeview
->paned
), 0);
2191 gtk_widget_grab_focus(button
);
2192 gtk_widget_unref(button
);
2196 void mimeview_update (MimeView
*mimeview
) {
2197 if (mimeview
&& mimeview
->mimeinfo
) {
2198 icon_list_clear(mimeview
);
2199 icon_list_create(mimeview
, mimeview
->mimeinfo
);
2203 void mimeview_handle_cmd(MimeView
*mimeview
, const gchar
*cmd
, GdkEventButton
*event
, gpointer data
)
2205 MessageView
*msgview
= NULL
;
2206 MainWindow
*mainwin
= NULL
;
2211 msgview
= mimeview
->messageview
;
2215 mainwin
= msgview
->mainwin
;
2219 else if (!strcmp(cmd
, "sc://view_log"))
2220 log_window_show(mainwin
->logwin
);
2221 else if (!strcmp(cmd
, "sc://save_as"))
2222 mimeview_save_as(mimeview
);
2223 else if (!strcmp(cmd
, "sc://display_as_text"))
2224 mimeview_display_as_text(mimeview
);
2225 else if (!strcmp(cmd
, "sc://open_with"))
2226 mimeview_open_with(mimeview
);
2227 else if (!strcmp(cmd
, "sc://open"))
2228 mimeview_launch(mimeview
);
2229 else if (!strcmp(cmd
, "sc://select_attachment") && data
!= NULL
) {
2230 icon_list_toggle_by_mime_info(mimeview
, (MimeInfo
*)data
);
2231 icon_selected(mimeview
, -1, (MimeInfo
*)data
);
2232 } else if (!strcmp(cmd
, "sc://open_attachment") && data
!= NULL
) {
2233 icon_list_toggle_by_mime_info(mimeview
, (MimeInfo
*)data
);
2234 icon_selected(mimeview
, -1, (MimeInfo
*)data
);
2235 mimeview_launch(mimeview
);
2236 } else if (!strcmp(cmd
, "sc://menu_attachment") && data
!= NULL
) {
2237 mimeview
->spec_part
= (MimeInfo
*)data
;
2238 part_button_pressed(mimeview
, event
, (MimeInfo
*)data
);