Statistics
| Revision:

root / src / mimeview.c @ 642

History | View | Annotate | Download (33 kB)

1 1 hiro
/*
2 1 hiro
 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 135 hiro
 * Copyright (C) 1999-2005 Hiroyuki Yamamoto
4 1 hiro
 *
5 1 hiro
 * This program is free software; you can redistribute it and/or modify
6 1 hiro
 * it under the terms of the GNU General Public License as published by
7 1 hiro
 * the Free Software Foundation; either version 2 of the License, or
8 1 hiro
 * (at your option) any later version.
9 1 hiro
 *
10 1 hiro
 * This program is distributed in the hope that it will be useful,
11 1 hiro
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 1 hiro
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 1 hiro
 * GNU General Public License for more details.
14 1 hiro
 *
15 1 hiro
 * You should have received a copy of the GNU General Public License
16 1 hiro
 * along with this program; if not, write to the Free Software
17 1 hiro
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 1 hiro
 */
19 1 hiro
20 1 hiro
#ifdef HAVE_CONFIG_H
21 1 hiro
#  include "config.h"
22 1 hiro
#endif
23 1 hiro
24 1 hiro
#include "defs.h"
25 1 hiro
26 1 hiro
#include <glib.h>
27 92 hiro
#include <glib/gi18n.h>
28 1 hiro
#include <gdk/gdkkeysyms.h>
29 1 hiro
#include <gtk/gtkscrolledwindow.h>
30 275 hiro
#include <gtk/gtktreestore.h>
31 275 hiro
#include <gtk/gtktreeview.h>
32 275 hiro
#include <gtk/gtktreeselection.h>
33 275 hiro
#include <gtk/gtkcellrenderertext.h>
34 1 hiro
#include <gtk/gtkvbox.h>
35 1 hiro
#include <gtk/gtkvpaned.h>
36 1 hiro
#include <gtk/gtksignal.h>
37 1 hiro
#include <gtk/gtkmenu.h>
38 1 hiro
#include <gtk/gtkdnd.h>
39 1 hiro
#include <gtk/gtkselection.h>
40 237 hiro
#include <gtk/gtknotebook.h>
41 275 hiro
#include <gtk/gtkvbbox.h>
42 1 hiro
#include <stdio.h>
43 1 hiro
#include <unistd.h>
44 1 hiro
45 642 hiro
#ifdef G_OS_WIN32
46 642 hiro
#  include <windows.h>
47 642 hiro
#endif
48 642 hiro
49 1 hiro
#include "main.h"
50 1 hiro
#include "mimeview.h"
51 1 hiro
#include "textview.h"
52 1 hiro
#include "imageview.h"
53 1 hiro
#include "procmime.h"
54 1 hiro
#include "summaryview.h"
55 1 hiro
#include "menu.h"
56 1 hiro
#include "filesel.h"
57 1 hiro
#include "alertpanel.h"
58 1 hiro
#include "inputdialog.h"
59 1 hiro
#include "utils.h"
60 1 hiro
#include "gtkutils.h"
61 1 hiro
#include "prefs_common.h"
62 1 hiro
#include "rfc2015.h"
63 1 hiro
64 275 hiro
enum
65 1 hiro
{
66 275 hiro
        COL_MIMETYPE,
67 275 hiro
        COL_SIZE,
68 275 hiro
        COL_NAME,
69 275 hiro
        COL_MIME_INFO,
70 275 hiro
        N_COLS
71 275 hiro
};
72 1 hiro
73 1 hiro
static void mimeview_set_multipart_tree                (MimeView        *mimeview,
74 1 hiro
                                                 MimeInfo        *mimeinfo,
75 275 hiro
                                                 GtkTreeIter        *parent);
76 275 hiro
static gboolean mimeview_append_part                (MimeView        *mimeview,
77 1 hiro
                                                 MimeInfo        *partinfo,
78 275 hiro
                                                 GtkTreeIter        *iter,
79 275 hiro
                                                 GtkTreeIter        *parent);
80 1 hiro
static void mimeview_show_message_part                (MimeView        *mimeview,
81 1 hiro
                                                 MimeInfo        *partinfo);
82 1 hiro
static void mimeview_show_image_part                (MimeView        *mimeview,
83 1 hiro
                                                 MimeInfo        *partinfo);
84 135 hiro
static void mimeview_show_mime_part                (MimeView        *mimeview,
85 135 hiro
                                                 MimeInfo        *partinfo);
86 135 hiro
#if USE_GPGME
87 135 hiro
static void mimeview_show_signature_part        (MimeView        *mimeview,
88 135 hiro
                                                 MimeInfo        *partinfo);
89 135 hiro
#endif
90 1 hiro
static void mimeview_change_view_type                (MimeView        *mimeview,
91 1 hiro
                                                 MimeViewType         type);
92 1 hiro
93 275 hiro
static void mimeview_selection_changed        (GtkTreeSelection        *selection,
94 275 hiro
                                         MimeView                *mimeview);
95 275 hiro
96 1 hiro
static gint mimeview_button_pressed        (GtkWidget        *widget,
97 1 hiro
                                         GdkEventButton        *event,
98 1 hiro
                                         MimeView        *mimeview);
99 1 hiro
static gint mimeview_key_pressed        (GtkWidget        *widget,
100 1 hiro
                                         GdkEventKey        *event,
101 1 hiro
                                         MimeView        *mimeview);
102 1 hiro
103 275 hiro
static void mimeview_drag_begin         (GtkWidget          *widget,
104 275 hiro
                                         GdkDragContext          *drag_context,
105 275 hiro
                                         MimeView          *mimeview);
106 275 hiro
static void mimeview_drag_end                 (GtkWidget          *widget,
107 275 hiro
                                         GdkDragContext          *drag_context,
108 275 hiro
                                         MimeView          *mimeview);
109 1 hiro
static void mimeview_drag_data_get      (GtkWidget          *widget,
110 1 hiro
                                         GdkDragContext   *drag_context,
111 1 hiro
                                         GtkSelectionData *selection_data,
112 1 hiro
                                         guint                   info,
113 1 hiro
                                         guint                   time,
114 1 hiro
                                         MimeView          *mimeview);
115 1 hiro
116 1 hiro
static void mimeview_display_as_text        (MimeView        *mimeview);
117 1 hiro
static void mimeview_launch                (MimeView        *mimeview);
118 1 hiro
static void mimeview_open_with                (MimeView        *mimeview);
119 1 hiro
static void mimeview_view_file                (const gchar        *filename,
120 1 hiro
                                         MimeInfo        *partinfo,
121 1 hiro
                                         const gchar        *cmdline);
122 1 hiro
#if USE_GPGME
123 1 hiro
static void mimeview_check_signature        (MimeView        *mimeview);
124 1 hiro
#endif
125 1 hiro
126 1 hiro
static GtkItemFactoryEntry mimeview_popup_entries[] =
127 1 hiro
{
128 1 hiro
        {N_("/_Open"),                  NULL, mimeview_launch,          0, NULL},
129 1 hiro
        {N_("/Open _with..."),          NULL, mimeview_open_with,          0, NULL},
130 1 hiro
        {N_("/_Display as text"), NULL, mimeview_display_as_text, 0, NULL},
131 601 hiro
        {N_("/_Save as..."),          NULL, mimeview_save_as,          0, NULL},
132 601 hiro
        {N_("/Save _all..."),          NULL, mimeview_save_all,          0, NULL}
133 1 hiro
#if USE_GPGME
134 1 hiro
        ,
135 1 hiro
        {N_("/_Check signature"), NULL, mimeview_check_signature, 0, NULL}
136 1 hiro
#endif
137 1 hiro
};
138 1 hiro
139 1 hiro
static GtkTargetEntry mimeview_mime_types[] =
140 1 hiro
{
141 1 hiro
        {"text/uri-list", 0, 0}
142 1 hiro
};
143 1 hiro
144 1 hiro
MimeView *mimeview_create(void)
145 1 hiro
{
146 1 hiro
        MimeView *mimeview;
147 1 hiro
148 1 hiro
        GtkWidget *paned;
149 1 hiro
        GtkWidget *scrolledwin;
150 275 hiro
        GtkWidget *treeview;
151 275 hiro
        GtkTreeStore *store;
152 275 hiro
        GtkTreeSelection *selection;
153 275 hiro
        GtkTreeViewColumn *column;
154 275 hiro
        GtkCellRenderer *renderer;
155 1 hiro
        GtkWidget *mime_vbox;
156 1 hiro
        GtkWidget *popupmenu;
157 1 hiro
        GtkItemFactory *popupfactory;
158 1 hiro
        gint n_entries;
159 1 hiro
160 1 hiro
        debug_print(_("Creating MIME view...\n"));
161 1 hiro
        mimeview = g_new0(MimeView, 1);
162 1 hiro
163 1 hiro
        scrolledwin = gtk_scrolled_window_new(NULL, NULL);
164 1 hiro
        gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwin),
165 1 hiro
                                       GTK_POLICY_AUTOMATIC,
166 1 hiro
                                       GTK_POLICY_ALWAYS);
167 275 hiro
        gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolledwin),
168 275 hiro
                                            GTK_SHADOW_IN);
169 1 hiro
        gtk_widget_set_size_request(scrolledwin, -1, 80);
170 1 hiro
171 275 hiro
        store = gtk_tree_store_new(N_COLS, G_TYPE_STRING, G_TYPE_STRING,
172 275 hiro
                                   G_TYPE_STRING, G_TYPE_POINTER);
173 1 hiro
174 275 hiro
        treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
175 275 hiro
        g_object_unref(G_OBJECT(store));
176 275 hiro
        gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview), TRUE);
177 275 hiro
        gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(treeview), TRUE);
178 275 hiro
        gtk_tree_view_set_search_column(GTK_TREE_VIEW(treeview), COL_NAME);
179 275 hiro
        gtk_tree_view_set_reorderable(GTK_TREE_VIEW(treeview), FALSE);
180 275 hiro
181 275 hiro
        selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview));
182 275 hiro
        gtk_tree_selection_set_mode(selection, GTK_SELECTION_BROWSE);
183 275 hiro
184 275 hiro
        gtk_container_add(GTK_CONTAINER(scrolledwin), treeview);
185 275 hiro
186 275 hiro
        renderer = gtk_cell_renderer_text_new();
187 275 hiro
        g_object_set(renderer, "ypad", 0, NULL);
188 275 hiro
        column = gtk_tree_view_column_new_with_attributes
189 275 hiro
                (_("MIME Type"), renderer, "text", COL_MIMETYPE, NULL);
190 275 hiro
        gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
191 275 hiro
        gtk_tree_view_column_set_resizable(column, TRUE);
192 275 hiro
        gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
193 275 hiro
194 275 hiro
        renderer = gtk_cell_renderer_text_new();
195 275 hiro
        g_object_set(renderer, "xalign", 1.0, "ypad", 0, NULL);
196 275 hiro
        column = gtk_tree_view_column_new_with_attributes
197 275 hiro
                (_("Size"), renderer, "text", COL_SIZE, NULL);
198 275 hiro
        gtk_tree_view_column_set_alignment(column, 1.0);
199 275 hiro
        gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
200 275 hiro
        gtk_tree_view_column_set_resizable(column, TRUE);
201 275 hiro
        gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
202 275 hiro
203 275 hiro
        renderer = gtk_cell_renderer_text_new();
204 275 hiro
        g_object_set(renderer, "ypad", 0, NULL);
205 275 hiro
        column = gtk_tree_view_column_new_with_attributes
206 275 hiro
                (_("Name"), renderer, "text", COL_NAME, NULL);
207 275 hiro
        gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
208 275 hiro
        gtk_tree_view_column_set_resizable(column, TRUE);
209 275 hiro
        gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
210 275 hiro
211 275 hiro
        gtk_tree_view_enable_model_drag_source
212 275 hiro
                (GTK_TREE_VIEW(treeview), 0, mimeview_mime_types, 1,
213 275 hiro
                 GDK_ACTION_COPY);
214 275 hiro
215 275 hiro
        g_signal_connect(G_OBJECT(selection), "changed",
216 275 hiro
                         G_CALLBACK(mimeview_selection_changed), mimeview);
217 275 hiro
        g_signal_connect(G_OBJECT(treeview), "button_press_event",
218 1 hiro
                         G_CALLBACK(mimeview_button_pressed), mimeview);
219 275 hiro
        g_signal_connect(G_OBJECT(treeview), "key_press_event",
220 1 hiro
                         G_CALLBACK(mimeview_key_pressed), mimeview);
221 275 hiro
222 275 hiro
        g_signal_connect_after(G_OBJECT (treeview),"drag-begin",
223 275 hiro
                               G_CALLBACK (mimeview_drag_begin), mimeview);
224 275 hiro
        g_signal_connect(G_OBJECT (treeview),"drag-end",
225 275 hiro
                         G_CALLBACK (mimeview_drag_end), mimeview);
226 275 hiro
        g_signal_connect(G_OBJECT(treeview), "drag-data-get",
227 1 hiro
                         G_CALLBACK(mimeview_drag_data_get), mimeview);
228 1 hiro
229 1 hiro
        mime_vbox = gtk_vbox_new(FALSE, 0);
230 135 hiro
        gtk_container_set_reallocate_redraws(GTK_CONTAINER(mime_vbox), TRUE);
231 1 hiro
232 1 hiro
        paned = gtk_vpaned_new();
233 1 hiro
        gtk_paned_add1(GTK_PANED(paned), scrolledwin);
234 1 hiro
        gtk_paned_add2(GTK_PANED(paned), mime_vbox);
235 1 hiro
236 1 hiro
        n_entries = sizeof(mimeview_popup_entries) /
237 1 hiro
                sizeof(mimeview_popup_entries[0]);
238 1 hiro
        popupmenu = menu_create_items(mimeview_popup_entries, n_entries,
239 1 hiro
                                      "<MimeView>", &popupfactory, mimeview);
240 1 hiro
241 1 hiro
        mimeview->paned        = paned;
242 1 hiro
        mimeview->scrolledwin  = scrolledwin;
243 275 hiro
        mimeview->treeview     = treeview;
244 275 hiro
        mimeview->store        = store;
245 275 hiro
        mimeview->selection    = selection;
246 1 hiro
        mimeview->mime_vbox    = mime_vbox;
247 1 hiro
        mimeview->popupmenu    = popupmenu;
248 1 hiro
        mimeview->popupfactory = popupfactory;
249 1 hiro
        mimeview->type         = -1;
250 1 hiro
251 1 hiro
        return mimeview;
252 1 hiro
}
253 1 hiro
254 1 hiro
void mimeview_init(MimeView *mimeview)
255 1 hiro
{
256 1 hiro
        textview_init(mimeview->textview);
257 1 hiro
        imageview_init(mimeview->imageview);
258 1 hiro
}
259 1 hiro
260 1 hiro
/*
261 1 hiro
 * Check whether the message is OpenPGP signed
262 1 hiro
 */
263 1 hiro
#if USE_GPGME
264 1 hiro
static gboolean mimeview_is_signed(MimeView *mimeview)
265 1 hiro
{
266 1 hiro
        MimeInfo *partinfo;
267 1 hiro
268 1 hiro
        debug_print("mimeview_is signed of %p\n", mimeview);
269 1 hiro
270 1 hiro
        if (!mimeview) return FALSE;
271 1 hiro
        if (!mimeview->opened) return FALSE;
272 1 hiro
273 1 hiro
        debug_print("mimeview_is_signed: open\n" );
274 1 hiro
275 1 hiro
        if (!mimeview->file) return FALSE;
276 1 hiro
277 1 hiro
        debug_print("mimeview_is_signed: file\n" );
278 1 hiro
279 1 hiro
        partinfo = mimeview_get_selected_part(mimeview);
280 1 hiro
        g_return_val_if_fail(partinfo != NULL, FALSE);
281 1 hiro
282 1 hiro
        /* walk the tree and see whether there is a signature somewhere */
283 1 hiro
        do {
284 1 hiro
                if (rfc2015_has_signature(partinfo))
285 1 hiro
                        return TRUE;
286 1 hiro
        } while ((partinfo = partinfo->parent) != NULL);
287 1 hiro
288 1 hiro
        debug_print("mimeview_is_signed: FALSE\n" );
289 1 hiro
290 1 hiro
        return FALSE;
291 1 hiro
}
292 1 hiro
293 1 hiro
static void set_unchecked_signature(MimeInfo *mimeinfo)
294 1 hiro
{
295 56 hiro
        MimeInfo **signedinfo;
296 1 hiro
297 56 hiro
        signedinfo = rfc2015_find_signature(mimeinfo);
298 56 hiro
        if (signedinfo == NULL) return;
299 1 hiro
300 56 hiro
        g_free(signedinfo[1]->sigstatus);
301 56 hiro
        signedinfo[1]->sigstatus =
302 1 hiro
                g_strdup(_("Select \"Check signature\" to check"));
303 1 hiro
304 56 hiro
        g_free(signedinfo[1]->sigstatus_full);
305 56 hiro
        signedinfo[1]->sigstatus_full = NULL;
306 56 hiro
307 275 hiro
        g_free(signedinfo);
308 1 hiro
}
309 1 hiro
#endif /* USE_GPGME */
310 1 hiro
311 1 hiro
void mimeview_show_message(MimeView *mimeview, MimeInfo *mimeinfo,
312 1 hiro
                           const gchar *file)
313 1 hiro
{
314 275 hiro
        GtkTreeModel *model = GTK_TREE_MODEL(mimeview->store);
315 275 hiro
        GtkTreeIter iter;
316 275 hiro
        gboolean valid;
317 1 hiro
318 1 hiro
        mimeview_clear(mimeview);
319 1 hiro
        textview_clear(mimeview->messageview->textview);
320 1 hiro
321 1 hiro
        g_return_if_fail(file != NULL);
322 1 hiro
        g_return_if_fail(mimeinfo != NULL);
323 1 hiro
324 1 hiro
        mimeview->mimeinfo = mimeinfo;
325 1 hiro
326 1 hiro
        mimeview->file = g_strdup(file);
327 1 hiro
328 1 hiro
#if USE_GPGME
329 1 hiro
        if (prefs_common.auto_check_signatures) {
330 1 hiro
                FILE *fp;
331 1 hiro
332 478 hiro
                if ((fp = g_fopen(file, "rb")) == NULL) {
333 1 hiro
                        FILE_OP_ERROR(file, "fopen");
334 1 hiro
                        return;
335 1 hiro
                }
336 1 hiro
                rfc2015_check_signature(mimeinfo, fp);
337 1 hiro
                fclose(fp);
338 1 hiro
        } else
339 1 hiro
                set_unchecked_signature(mimeinfo);
340 1 hiro
#endif
341 1 hiro
342 1 hiro
        g_signal_handlers_block_by_func
343 275 hiro
                (G_OBJECT(mimeview->selection),
344 275 hiro
                 G_CALLBACK(mimeview_selection_changed), mimeview);
345 1 hiro
346 1 hiro
        mimeview_set_multipart_tree(mimeview, mimeinfo, NULL);
347 275 hiro
        gtk_tree_view_expand_all(GTK_TREE_VIEW(mimeview->treeview));
348 1 hiro
349 1 hiro
        g_signal_handlers_unblock_by_func
350 275 hiro
                (G_OBJECT(mimeview->selection),
351 275 hiro
                 G_CALLBACK(mimeview_selection_changed), mimeview);
352 1 hiro
353 1 hiro
        /* search first text part */
354 275 hiro
        for (valid = gtk_tree_model_get_iter_first(model, &iter); valid;
355 275 hiro
             valid = gtkut_tree_model_next(model, &iter)) {
356 1 hiro
                MimeInfo *partinfo;
357 1 hiro
358 275 hiro
                gtk_tree_model_get(model, &iter, COL_MIME_INFO, &partinfo, -1);
359 1 hiro
                if (partinfo &&
360 1 hiro
                    (partinfo->mime_type == MIME_TEXT ||
361 1 hiro
                     partinfo->mime_type == MIME_TEXT_HTML))
362 1 hiro
                        break;
363 1 hiro
        }
364 1 hiro
        textview_show_message(mimeview->messageview->textview, mimeinfo, file);
365 1 hiro
366 275 hiro
        if (!valid)
367 275 hiro
                valid = gtk_tree_model_get_iter_first(model, &iter);
368 1 hiro
369 275 hiro
        if (valid) {
370 275 hiro
                GtkTreePath *path;
371 275 hiro
372 275 hiro
                path = gtk_tree_model_get_path(model, &iter);
373 275 hiro
                gtk_tree_view_set_cursor(GTK_TREE_VIEW(mimeview->treeview),
374 275 hiro
                                         path, NULL, FALSE);
375 275 hiro
                gtk_tree_path_free(path);
376 154 hiro
                if (mimeview_get_selected_part(mimeview))
377 275 hiro
                        gtk_widget_grab_focus(mimeview->treeview);
378 1 hiro
        }
379 1 hiro
}
380 1 hiro
381 1 hiro
void mimeview_clear(MimeView *mimeview)
382 1 hiro
{
383 1 hiro
        procmime_mimeinfo_free_all(mimeview->mimeinfo);
384 1 hiro
        mimeview->mimeinfo = NULL;
385 1 hiro
386 275 hiro
        gtk_tree_store_clear(mimeview->store);
387 1 hiro
        textview_clear(mimeview->textview);
388 1 hiro
        imageview_clear(mimeview->imageview);
389 1 hiro
390 275 hiro
        gtk_tree_path_free(mimeview->opened);
391 1 hiro
        mimeview->opened = NULL;
392 1 hiro
393 1 hiro
        g_free(mimeview->file);
394 1 hiro
        mimeview->file = NULL;
395 291 hiro
396 291 hiro
        g_free(mimeview->drag_file);
397 291 hiro
        mimeview->drag_file = NULL;
398 1 hiro
}
399 1 hiro
400 1 hiro
void mimeview_destroy(MimeView *mimeview)
401 1 hiro
{
402 1 hiro
        textview_destroy(mimeview->textview);
403 1 hiro
        imageview_destroy(mimeview->imageview);
404 1 hiro
        procmime_mimeinfo_free_all(mimeview->mimeinfo);
405 1 hiro
        g_free(mimeview->file);
406 275 hiro
        g_free(mimeview->drag_file);
407 1 hiro
        g_free(mimeview);
408 1 hiro
}
409 1 hiro
410 1 hiro
MimeInfo *mimeview_get_selected_part(MimeView *mimeview)
411 1 hiro
{
412 275 hiro
        GtkTreeModel *model = GTK_TREE_MODEL(mimeview->store);
413 275 hiro
        GtkTreeIter iter;
414 275 hiro
        MimeInfo *partinfo = NULL;
415 275 hiro
416 275 hiro
        if (!mimeview->opened)
417 275 hiro
                return NULL;
418 1 hiro
        if (gtk_notebook_get_current_page
419 154 hiro
                (GTK_NOTEBOOK(mimeview->messageview->notebook)) == 0)
420 1 hiro
                return NULL;
421 1 hiro
422 275 hiro
        if (gtk_tree_model_get_iter(model, &iter, mimeview->opened))
423 275 hiro
                gtk_tree_model_get(model, &iter, COL_MIME_INFO, &partinfo, -1);
424 275 hiro
425 275 hiro
        return partinfo;
426 1 hiro
}
427 1 hiro
428 135 hiro
gboolean mimeview_step(MimeView *mimeview, GtkScrollType type)
429 135 hiro
{
430 275 hiro
        GtkTreeView *treeview = GTK_TREE_VIEW(mimeview->treeview);
431 275 hiro
        GtkTreeModel *model = GTK_TREE_MODEL(mimeview->store);
432 275 hiro
        GtkTreeIter iter;
433 275 hiro
        gboolean moved;
434 135 hiro
435 275 hiro
        if (!mimeview->opened)
436 275 hiro
                return FALSE;
437 275 hiro
        if (!gtk_tree_model_get_iter(model, &iter, mimeview->opened))
438 275 hiro
                return FALSE;
439 275 hiro
440 135 hiro
        if (type == GTK_SCROLL_STEP_FORWARD) {
441 275 hiro
                if (gtkut_tree_model_next(model, &iter))
442 275 hiro
                        gtkut_tree_view_expand_parent_all(treeview, &iter);
443 135 hiro
                else
444 135 hiro
                        return FALSE;
445 135 hiro
        } else {
446 275 hiro
                if (!gtkut_tree_model_prev(model, &iter))
447 135 hiro
                        return FALSE;
448 135 hiro
        }
449 135 hiro
450 275 hiro
        g_signal_emit_by_name(G_OBJECT(treeview), "move-cursor",
451 275 hiro
                              GTK_MOVEMENT_DISPLAY_LINES,
452 275 hiro
                              type == GTK_SCROLL_STEP_FORWARD ? 1 : -1, &moved);
453 135 hiro
454 135 hiro
        return TRUE;
455 135 hiro
}
456 135 hiro
457 1 hiro
static void mimeview_set_multipart_tree(MimeView *mimeview,
458 1 hiro
                                        MimeInfo *mimeinfo,
459 275 hiro
                                        GtkTreeIter *parent)
460 1 hiro
{
461 275 hiro
        GtkTreeIter iter;
462 1 hiro
463 1 hiro
        g_return_if_fail(mimeinfo != NULL);
464 1 hiro
465 1 hiro
        if (mimeinfo->children)
466 1 hiro
                mimeinfo = mimeinfo->children;
467 1 hiro
468 1 hiro
        while (mimeinfo != NULL) {
469 275 hiro
                mimeview_append_part(mimeview, mimeinfo, &iter, parent);
470 1 hiro
471 1 hiro
                if (mimeinfo->children)
472 275 hiro
                        mimeview_set_multipart_tree(mimeview, mimeinfo, &iter);
473 1 hiro
                else if (mimeinfo->sub &&
474 1 hiro
                         mimeinfo->sub->mime_type != MIME_TEXT &&
475 1 hiro
                         mimeinfo->sub->mime_type != MIME_TEXT_HTML)
476 1 hiro
                        mimeview_set_multipart_tree(mimeview, mimeinfo->sub,
477 275 hiro
                                                    &iter);
478 1 hiro
                mimeinfo = mimeinfo->next;
479 1 hiro
        }
480 1 hiro
}
481 1 hiro
482 1 hiro
static gchar *get_part_name(MimeInfo *partinfo)
483 1 hiro
{
484 1 hiro
#if USE_GPGME
485 1 hiro
        if (partinfo->sigstatus)
486 1 hiro
                return partinfo->sigstatus;
487 1 hiro
        else
488 1 hiro
#endif
489 1 hiro
        if (partinfo->name)
490 1 hiro
                return partinfo->name;
491 1 hiro
        else if (partinfo->filename)
492 1 hiro
                return partinfo->filename;
493 1 hiro
        else
494 1 hiro
                return "";
495 1 hiro
}
496 1 hiro
497 275 hiro
static gboolean mimeview_append_part(MimeView *mimeview, MimeInfo *partinfo,
498 275 hiro
                                     GtkTreeIter *iter, GtkTreeIter *parent)
499 1 hiro
{
500 275 hiro
        gchar *mime_type;
501 275 hiro
        gchar *size;
502 275 hiro
        gchar *name;
503 1 hiro
504 275 hiro
        mime_type = partinfo->content_type ? partinfo->content_type : "";
505 427 hiro
        size = to_human_readable(partinfo->content_size);
506 275 hiro
        name = get_part_name(partinfo);
507 1 hiro
508 275 hiro
        gtk_tree_store_append(mimeview->store, iter, parent);
509 275 hiro
        gtk_tree_store_set(mimeview->store, iter,
510 275 hiro
                           COL_MIMETYPE, mime_type,
511 275 hiro
                           COL_SIZE, size,
512 275 hiro
                           COL_NAME, name,
513 275 hiro
                           COL_MIME_INFO, partinfo,
514 275 hiro
                           -1);
515 1 hiro
516 275 hiro
        return TRUE;
517 1 hiro
}
518 1 hiro
519 1 hiro
static void mimeview_show_message_part(MimeView *mimeview, MimeInfo *partinfo)
520 1 hiro
{
521 1 hiro
        FILE *fp;
522 1 hiro
        const gchar *fname;
523 1 hiro
#if USE_GPGME
524 1 hiro
        MimeInfo *pi;
525 1 hiro
#endif
526 1 hiro
527 1 hiro
        if (!partinfo) return;
528 1 hiro
529 1 hiro
#if USE_GPGME
530 1 hiro
        for (pi = partinfo; pi && !pi->plaintextfile ; pi = pi->parent)
531 1 hiro
                ;
532 1 hiro
        fname = pi ? pi->plaintextfile : mimeview->file;
533 1 hiro
#else
534 1 hiro
        fname = mimeview->file;
535 1 hiro
#endif /* USE_GPGME */
536 1 hiro
        if (!fname) return;
537 1 hiro
538 478 hiro
        if ((fp = g_fopen(fname, "rb")) == NULL) {
539 1 hiro
                FILE_OP_ERROR(fname, "fopen");
540 1 hiro
                return;
541 1 hiro
        }
542 1 hiro
543 1 hiro
        if (fseek(fp, partinfo->fpos, SEEK_SET) < 0) {
544 1 hiro
                FILE_OP_ERROR(mimeview->file, "fseek");
545 1 hiro
                fclose(fp);
546 1 hiro
                return;
547 1 hiro
        }
548 1 hiro
549 1 hiro
        mimeview_change_view_type(mimeview, MIMEVIEW_TEXT);
550 1 hiro
        textview_show_part(mimeview->textview, partinfo, fp);
551 1 hiro
552 1 hiro
        fclose(fp);
553 1 hiro
}
554 1 hiro
555 1 hiro
static void mimeview_show_image_part(MimeView *mimeview, MimeInfo *partinfo)
556 1 hiro
{
557 1 hiro
        gchar *filename;
558 1 hiro
559 1 hiro
        if (!partinfo) return;
560 1 hiro
561 1 hiro
        filename = procmime_get_tmp_file_name(partinfo);
562 1 hiro
563 1 hiro
        if (procmime_get_part(filename, mimeview->file, partinfo) < 0)
564 1 hiro
                alertpanel_error
565 1 hiro
                        (_("Can't get the part of multipart message."));
566 1 hiro
        else {
567 1 hiro
                mimeview_change_view_type(mimeview, MIMEVIEW_IMAGE);
568 1 hiro
                imageview_show_image(mimeview->imageview, partinfo, filename,
569 1 hiro
                                     prefs_common.resize_image);
570 478 hiro
                g_unlink(filename);
571 1 hiro
        }
572 1 hiro
573 1 hiro
        g_free(filename);
574 1 hiro
}
575 1 hiro
576 135 hiro
static void save_as_button_clicked(GtkWidget *widget, gpointer data)
577 135 hiro
{
578 135 hiro
        MimeView *mimeview = (MimeView *)data;
579 135 hiro
580 135 hiro
        mimeview_save_as(mimeview);
581 135 hiro
}
582 135 hiro
583 135 hiro
static void display_as_text_button_clicked(GtkWidget *widget, gpointer data)
584 135 hiro
{
585 135 hiro
        MimeView *mimeview = (MimeView *)data;
586 135 hiro
587 135 hiro
        mimeview_display_as_text(mimeview);
588 135 hiro
}
589 135 hiro
590 135 hiro
static void open_button_clicked(GtkWidget *widget, gpointer data)
591 135 hiro
{
592 135 hiro
        MimeView *mimeview = (MimeView *)data;
593 135 hiro
594 135 hiro
        mimeview_launch(mimeview);
595 135 hiro
}
596 135 hiro
597 135 hiro
static void open_with_button_clicked(GtkWidget *widget, gpointer data)
598 135 hiro
{
599 135 hiro
        MimeView *mimeview = (MimeView *)data;
600 135 hiro
601 135 hiro
        mimeview_open_with(mimeview);
602 135 hiro
}
603 135 hiro
604 135 hiro
static void mimeview_show_mime_part(MimeView *mimeview, MimeInfo *partinfo)
605 135 hiro
{
606 135 hiro
        TextView *textview = mimeview->textview;
607 135 hiro
        GtkTextBuffer *buffer;
608 135 hiro
        GtkTextIter iter;
609 135 hiro
        GtkTextChildAnchor *anchor;
610 135 hiro
        GtkWidget *vbbox;
611 135 hiro
        GtkWidget *button;
612 135 hiro
        gchar buf[BUFFSIZE];
613 135 hiro
614 135 hiro
        if (!partinfo) return;
615 135 hiro
616 135 hiro
        textview_set_font(textview, NULL);
617 135 hiro
        textview_clear(textview);
618 135 hiro
619 135 hiro
        buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview->text));
620 135 hiro
        gtk_text_buffer_get_start_iter(buffer, &iter);
621 135 hiro
622 135 hiro
        gtk_text_buffer_insert(buffer, &iter,
623 135 hiro
                               _("Select an action for the attached file:\n"),
624 135 hiro
                               -1);
625 135 hiro
        if (partinfo->filename || partinfo->name)
626 428 hiro
                g_snprintf(buf, sizeof(buf), "[%s  %s (%s)]\n\n",
627 135 hiro
                           partinfo->filename ? partinfo->filename :
628 135 hiro
                           partinfo->name,
629 428 hiro
                           partinfo->content_type,
630 428 hiro
                           to_human_readable(partinfo->content_size));
631 135 hiro
        else
632 428 hiro
                g_snprintf(buf, sizeof(buf), "[%s (%s)]\n\n",
633 428 hiro
                           partinfo->content_type,
634 428 hiro
                           to_human_readable(partinfo->content_size));
635 135 hiro
        gtk_text_buffer_insert(buffer, &iter, buf, -1);
636 135 hiro
637 135 hiro
        vbbox = gtk_vbutton_box_new();
638 135 hiro
        gtk_box_set_spacing(GTK_BOX(vbbox), 5);
639 135 hiro
640 135 hiro
        button = gtk_button_new_from_stock(GTK_STOCK_OPEN);
641 135 hiro
        gtk_container_add(GTK_CONTAINER(vbbox), button);
642 135 hiro
        g_signal_connect(button, "clicked", G_CALLBACK(open_button_clicked),
643 135 hiro
                         mimeview);
644 135 hiro
        button = gtk_button_new_with_mnemonic(_("Open _with..."));
645 135 hiro
        gtk_container_add(GTK_CONTAINER(vbbox), button);
646 135 hiro
        g_signal_connect(button, "clicked",
647 135 hiro
                         G_CALLBACK(open_with_button_clicked), mimeview);
648 135 hiro
        button = gtk_button_new_with_mnemonic(_("_Display as text"));
649 135 hiro
        gtk_container_add(GTK_CONTAINER(vbbox), button);
650 135 hiro
        g_signal_connect(button, "clicked",
651 135 hiro
                         G_CALLBACK(display_as_text_button_clicked), mimeview);
652 135 hiro
        button = gtk_button_new_with_mnemonic(_("_Save as..."));
653 135 hiro
        gtk_container_add(GTK_CONTAINER(vbbox), button);
654 135 hiro
        g_signal_connect(button, "clicked", G_CALLBACK(save_as_button_clicked),
655 135 hiro
                         mimeview);
656 135 hiro
657 135 hiro
        gtk_widget_show_all(vbbox);
658 135 hiro
659 135 hiro
        anchor = gtk_text_buffer_create_child_anchor(buffer, &iter);
660 135 hiro
        gtk_text_view_add_child_at_anchor(GTK_TEXT_VIEW(textview->text),
661 135 hiro
                                          vbbox, anchor);
662 135 hiro
}
663 135 hiro
664 135 hiro
#if USE_GPGME
665 135 hiro
static void check_signature_button_clicked(GtkWidget *widget, gpointer data)
666 135 hiro
{
667 135 hiro
        MimeView *mimeview = (MimeView *)data;
668 135 hiro
669 135 hiro
        mimeview_check_signature(mimeview);
670 135 hiro
}
671 135 hiro
672 135 hiro
static void mimeview_show_signature_part(MimeView *mimeview,
673 135 hiro
                                         MimeInfo *partinfo)
674 135 hiro
{
675 135 hiro
        TextView *textview = mimeview->textview;
676 135 hiro
        GtkTextBuffer *buffer;
677 135 hiro
        GtkTextIter iter;
678 135 hiro
        GtkTextChildAnchor *anchor;
679 135 hiro
        GtkWidget *vbbox;
680 135 hiro
        GtkWidget *button;
681 135 hiro
682 135 hiro
        if (!partinfo) return;
683 135 hiro
684 135 hiro
        textview_set_font(textview, NULL);
685 135 hiro
        textview_clear(textview);
686 135 hiro
687 135 hiro
        buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview->text));
688 135 hiro
        gtk_text_buffer_get_start_iter(buffer, &iter);
689 135 hiro
690 135 hiro
        if (partinfo->sigstatus_full) {
691 135 hiro
                gtk_text_buffer_insert
692 135 hiro
                        (buffer, &iter, partinfo->sigstatus_full, -1);
693 135 hiro
                return;
694 135 hiro
        }
695 135 hiro
696 135 hiro
        gtk_text_buffer_insert
697 135 hiro
                (buffer, &iter,
698 135 hiro
                 _("This signature has not been checked yet.\n\n"), -1);
699 135 hiro
700 135 hiro
        vbbox = gtk_vbutton_box_new();
701 135 hiro
        gtk_box_set_spacing(GTK_BOX(vbbox), 5);
702 135 hiro
703 135 hiro
        button = gtk_button_new_with_mnemonic(_("_Check signature"));
704 135 hiro
        gtk_container_add(GTK_CONTAINER(vbbox), button);
705 135 hiro
        g_signal_connect(button, "clicked",
706 135 hiro
                         G_CALLBACK(check_signature_button_clicked), mimeview);
707 135 hiro
708 135 hiro
        gtk_widget_show_all(vbbox);
709 135 hiro
710 135 hiro
        anchor = gtk_text_buffer_create_child_anchor(buffer, &iter);
711 135 hiro
        gtk_text_view_add_child_at_anchor(GTK_TEXT_VIEW(textview->text),
712 135 hiro
                                          vbbox, anchor);
713 135 hiro
}
714 135 hiro
#endif /* USE_GPGME */
715 135 hiro
716 1 hiro
static void mimeview_change_view_type(MimeView *mimeview, MimeViewType type)
717 1 hiro
{
718 1 hiro
        TextView  *textview  = mimeview->textview;
719 1 hiro
        ImageView *imageview = mimeview->imageview;
720 1 hiro
        GList *children;
721 1 hiro
722 1 hiro
        if (mimeview->type == type) return;
723 1 hiro
724 1 hiro
        children = gtk_container_get_children
725 1 hiro
                (GTK_CONTAINER(mimeview->mime_vbox));
726 1 hiro
        if (children) {
727 1 hiro
                gtkut_container_remove(GTK_CONTAINER(mimeview->mime_vbox),
728 1 hiro
                                       GTK_WIDGET(children->data));
729 1 hiro
                g_list_free(children);
730 1 hiro
        }
731 1 hiro
732 1 hiro
        switch (type) {
733 1 hiro
        case MIMEVIEW_IMAGE:
734 1 hiro
                gtk_container_add(GTK_CONTAINER(mimeview->mime_vbox),
735 1 hiro
                                  GTK_WIDGET_PTR(imageview));
736 1 hiro
                break;
737 1 hiro
        case MIMEVIEW_TEXT:
738 1 hiro
                gtk_container_add(GTK_CONTAINER(mimeview->mime_vbox),
739 1 hiro
                                  GTK_WIDGET_PTR(textview));
740 1 hiro
                break;
741 1 hiro
        default:
742 1 hiro
                return;
743 1 hiro
        }
744 1 hiro
745 1 hiro
        mimeview->type = type;
746 1 hiro
}
747 1 hiro
748 275 hiro
static void mimeview_selection_changed(GtkTreeSelection *selection,
749 275 hiro
                                       MimeView *mimeview)
750 1 hiro
{
751 275 hiro
        GtkTreeModel *model = GTK_TREE_MODEL(mimeview->store);
752 275 hiro
        GtkTreeIter iter;
753 275 hiro
        GtkTreePath *path;
754 1 hiro
        MimeInfo *partinfo;
755 1 hiro
756 275 hiro
        if (!gtk_tree_selection_get_selected(selection, NULL, &iter)) {
757 275 hiro
                if (mimeview->opened) {
758 275 hiro
                        gtk_tree_path_free(mimeview->opened);
759 275 hiro
                        mimeview->opened = NULL;
760 275 hiro
                }
761 275 hiro
                return;
762 275 hiro
        }
763 1 hiro
764 275 hiro
        path = gtk_tree_model_get_path(model, &iter);
765 1 hiro
766 275 hiro
        if (mimeview->opened &&
767 275 hiro
            gtk_tree_path_compare(mimeview->opened, path) == 0) {
768 275 hiro
                gtk_tree_path_free(path);
769 275 hiro
                return;
770 1 hiro
        }
771 1 hiro
772 275 hiro
        gtk_tree_path_free(mimeview->opened);
773 275 hiro
        mimeview->opened = path;
774 275 hiro
        path = NULL;
775 275 hiro
776 275 hiro
        gtk_tree_model_get(model, &iter, COL_MIME_INFO, &partinfo, -1);
777 275 hiro
        if (!partinfo)
778 275 hiro
                return;
779 275 hiro
780 1 hiro
        switch (partinfo->mime_type) {
781 1 hiro
        case MIME_TEXT:
782 1 hiro
        case MIME_TEXT_HTML:
783 1 hiro
        case MIME_MESSAGE_RFC822:
784 1 hiro
        case MIME_MULTIPART:
785 1 hiro
                mimeview_show_message_part(mimeview, partinfo);
786 1 hiro
                break;
787 1 hiro
        case MIME_IMAGE:
788 1 hiro
                mimeview_show_image_part(mimeview, partinfo);
789 1 hiro
                break;
790 1 hiro
        default:
791 1 hiro
                mimeview_change_view_type(mimeview, MIMEVIEW_TEXT);
792 1 hiro
#if USE_GPGME
793 605 hiro
                if (rfc2015_is_signature_part(partinfo))
794 135 hiro
                        mimeview_show_signature_part(mimeview, partinfo);
795 1 hiro
                else
796 1 hiro
#endif
797 135 hiro
                        mimeview_show_mime_part(mimeview, partinfo);
798 1 hiro
                break;
799 1 hiro
        }
800 1 hiro
}
801 1 hiro
802 1 hiro
static gint mimeview_button_pressed(GtkWidget *widget, GdkEventButton *event,
803 1 hiro
                                    MimeView *mimeview)
804 1 hiro
{
805 275 hiro
        GtkTreeView *treeview = GTK_TREE_VIEW(widget);
806 1 hiro
        MimeInfo *partinfo;
807 1 hiro
808 1 hiro
        if (!event) return FALSE;
809 1 hiro
810 1 hiro
        if (event->button == 2 || event->button == 3) {
811 275 hiro
                GtkTreePath *path;
812 275 hiro
813 275 hiro
                if (!gtk_tree_view_get_path_at_pos(treeview, event->x, event->y,
814 275 hiro
                                                   &path, NULL, NULL, NULL))
815 1 hiro
                        return FALSE;
816 275 hiro
                gtk_tree_view_set_cursor(treeview, path, NULL, FALSE);
817 275 hiro
                gtk_tree_path_free(path);
818 1 hiro
        }
819 1 hiro
820 1 hiro
        if (event->button == 2 ||
821 1 hiro
            (event->button == 1 && event->type == GDK_2BUTTON_PRESS)) {
822 1 hiro
                /* call external program for image, audio or html */
823 1 hiro
                mimeview_launch(mimeview);
824 1 hiro
        } else if (event->button == 3) {
825 1 hiro
                partinfo = mimeview_get_selected_part(mimeview);
826 1 hiro
                if (partinfo && (partinfo->mime_type == MIME_TEXT ||
827 1 hiro
                                 partinfo->mime_type == MIME_TEXT_HTML ||
828 1 hiro
                                 partinfo->mime_type == MIME_MESSAGE_RFC822 ||
829 1 hiro
                                 partinfo->mime_type == MIME_IMAGE ||
830 1 hiro
                                 partinfo->mime_type == MIME_MULTIPART))
831 1 hiro
                        menu_set_sensitive(mimeview->popupfactory,
832 1 hiro
                                           "/Display as text", FALSE);
833 1 hiro
                else
834 1 hiro
                        menu_set_sensitive(mimeview->popupfactory,
835 1 hiro
                                           "/Display as text", TRUE);
836 1 hiro
                if (partinfo &&
837 1 hiro
                    partinfo->mime_type == MIME_APPLICATION_OCTET_STREAM)
838 1 hiro
                        menu_set_sensitive(mimeview->popupfactory,
839 1 hiro
                                           "/Open", FALSE);
840 1 hiro
                else
841 1 hiro
                        menu_set_sensitive(mimeview->popupfactory,
842 1 hiro
                                           "/Open", TRUE);
843 1 hiro
#if USE_GPGME
844 1 hiro
                menu_set_sensitive(mimeview->popupfactory,
845 1 hiro
                                   "/Check signature",
846 1 hiro
                                   mimeview_is_signed(mimeview));
847 1 hiro
#endif
848 1 hiro
849 1 hiro
                gtk_menu_popup(GTK_MENU(mimeview->popupmenu),
850 1 hiro
                               NULL, NULL, NULL, NULL,
851 1 hiro
                               event->button, event->time);
852 135 hiro
                return TRUE;
853 1 hiro
        }
854 1 hiro
855 1 hiro
        return FALSE;
856 1 hiro
}
857 1 hiro
858 1 hiro
void mimeview_pass_key_press_event(MimeView *mimeview, GdkEventKey *event)
859 1 hiro
{
860 275 hiro
        mimeview_key_pressed(mimeview->treeview, event, mimeview);
861 1 hiro
}
862 1 hiro
863 1 hiro
#define BREAK_ON_MODIFIER_KEY() \
864 1 hiro
        if ((event->state & (GDK_MOD1_MASK|GDK_CONTROL_MASK)) != 0) break
865 1 hiro
866 1 hiro
#define KEY_PRESS_EVENT_STOP() \
867 275 hiro
        g_signal_stop_emission_by_name(G_OBJECT(treeview), "key_press_event");
868 1 hiro
869 1 hiro
static gint mimeview_key_pressed(GtkWidget *widget, GdkEventKey *event,
870 1 hiro
                                 MimeView *mimeview)
871 1 hiro
{
872 135 hiro
        SummaryView *summaryview = NULL;
873 275 hiro
        GtkTreeView *treeview = GTK_TREE_VIEW(widget);
874 275 hiro
        GtkTreeModel *model = GTK_TREE_MODEL(mimeview->store);
875 275 hiro
        GtkTreeIter iter;
876 135 hiro
        gboolean mod_pressed;
877 1 hiro
878 1 hiro
        if (!event) return FALSE;
879 1 hiro
        if (!mimeview->opened) return FALSE;
880 275 hiro
        if (!gtk_tree_model_get_iter(model, &iter, mimeview->opened))
881 275 hiro
                return FALSE;
882 1 hiro
883 135 hiro
        if (mimeview->messageview->mainwin)
884 135 hiro
                summaryview = mimeview->messageview->mainwin->summaryview;
885 135 hiro
        mod_pressed =
886 135 hiro
                ((event->state & (GDK_SHIFT_MASK|GDK_MOD1_MASK)) != 0);
887 135 hiro
888 1 hiro
        switch (event->keyval) {
889 1 hiro
        case GDK_space:
890 135 hiro
                if (textview_scroll_page(mimeview->textview, mod_pressed))
891 1 hiro
                        return TRUE;
892 1 hiro
893 275 hiro
                if (gtkut_tree_model_next(model, &iter)) {
894 275 hiro
                        GtkTreePath *path;
895 275 hiro
896 275 hiro
                        path = gtk_tree_model_get_path(model, &iter);
897 275 hiro
                        gtk_tree_view_set_cursor(treeview, path, NULL, FALSE);
898 275 hiro
                        gtk_tree_path_free(path);
899 1 hiro
                        return TRUE;
900 1 hiro
                }
901 135 hiro
                if (summaryview)
902 135 hiro
                        summary_pass_key_press_event(summaryview, event);
903 1 hiro
                break;
904 1 hiro
        case GDK_BackSpace:
905 1 hiro
                textview_scroll_page(mimeview->textview, TRUE);
906 1 hiro
                return TRUE;
907 1 hiro
        case GDK_Return:
908 135 hiro
                textview_scroll_one_line(mimeview->textview, mod_pressed);
909 1 hiro
                return TRUE;
910 1 hiro
        case GDK_t:
911 1 hiro
                BREAK_ON_MODIFIER_KEY();
912 1 hiro
                KEY_PRESS_EVENT_STOP();
913 1 hiro
                mimeview_display_as_text(mimeview);
914 1 hiro
                return TRUE;
915 165 hiro
        case GDK_Escape:
916 165 hiro
                if (summaryview)
917 237 hiro
                        gtk_widget_grab_focus(summaryview->treeview);
918 165 hiro
                break;
919 135 hiro
        case GDK_Left:
920 135 hiro
        case GDK_Delete:
921 135 hiro
                if (summaryview)
922 135 hiro
                        summary_pass_key_press_event(summaryview, event);
923 135 hiro
                break;
924 1 hiro
        default:
925 1 hiro
                break;
926 1 hiro
        }
927 1 hiro
928 135 hiro
        return FALSE;
929 1 hiro
}
930 1 hiro
931 275 hiro
static void mimeview_drag_begin(GtkWidget *widget, GdkDragContext *drag_context,
932 275 hiro
                                MimeView *mimeview)
933 1 hiro
{
934 275 hiro
        gchar *filename;
935 275 hiro
        gchar *bname = NULL;
936 1 hiro
        MimeInfo *partinfo;
937 1 hiro
938 1 hiro
        if (!mimeview->opened) return;
939 1 hiro
        if (!mimeview->file) return;
940 1 hiro
941 1 hiro
        partinfo = mimeview_get_selected_part(mimeview);
942 1 hiro
        if (!partinfo) return;
943 1 hiro
944 1 hiro
        filename = partinfo->filename ? partinfo->filename : partinfo->name;
945 275 hiro
        if (filename) {
946 275 hiro
                const gchar *bname_;
947 1 hiro
948 275 hiro
                bname_ = g_basename(filename);
949 275 hiro
                bname = conv_filename_from_utf8(bname_);
950 275 hiro
                subst_for_filename(bname);
951 275 hiro
        }
952 275 hiro
        if (!bname || *bname == '\0')
953 275 hiro
                filename = procmime_get_tmp_file_name(partinfo);
954 275 hiro
        else
955 275 hiro
                filename = g_strconcat(get_mime_tmp_dir(), G_DIR_SEPARATOR_S,
956 275 hiro
                                       bname, NULL);
957 1 hiro
958 275 hiro
        if (procmime_get_part(filename, mimeview->file, partinfo) < 0) {
959 275 hiro
                g_warning(_("Can't save the part of multipart message."));
960 275 hiro
        } else
961 291 hiro
                mimeview->drag_file = encode_uri(filename);
962 1 hiro
963 291 hiro
        g_free(filename);
964 291 hiro
965 275 hiro
        gtk_drag_set_icon_default(drag_context);
966 275 hiro
}
967 275 hiro
968 275 hiro
static void mimeview_drag_end(GtkWidget *widget, GdkDragContext *drag_context,
969 275 hiro
                              MimeView *mimeview)
970 275 hiro
{
971 275 hiro
        if (mimeview->drag_file) {
972 275 hiro
                g_free(mimeview->drag_file);
973 275 hiro
                mimeview->drag_file = NULL;
974 275 hiro
        }
975 275 hiro
}
976 275 hiro
977 275 hiro
static void mimeview_drag_data_get(GtkWidget            *widget,
978 275 hiro
                                   GdkDragContext   *drag_context,
979 275 hiro
                                   GtkSelectionData *selection_data,
980 275 hiro
                                   guint             info,
981 275 hiro
                                   guint             time,
982 275 hiro
                                   MimeView            *mimeview)
983 275 hiro
{
984 275 hiro
        if (!mimeview->drag_file) return;
985 275 hiro
986 1 hiro
        gtk_selection_data_set(selection_data, selection_data->target, 8,
987 583 hiro
                               (guchar *)mimeview->drag_file,
988 291 hiro
                               strlen(mimeview->drag_file));
989 1 hiro
}
990 1 hiro
991 1 hiro
static void mimeview_display_as_text(MimeView *mimeview)
992 1 hiro
{
993 1 hiro
        MimeInfo *partinfo;
994 1 hiro
995 1 hiro
        if (!mimeview->opened) return;
996 1 hiro
997 1 hiro
        partinfo = mimeview_get_selected_part(mimeview);
998 1 hiro
        g_return_if_fail(partinfo != NULL);
999 1 hiro
        mimeview_show_message_part(mimeview, partinfo);
1000 1 hiro
}
1001 1 hiro
1002 152 hiro
void mimeview_save_as(MimeView *mimeview)
1003 1 hiro
{
1004 1 hiro
        gchar *filename;
1005 1 hiro
        gchar *defname = NULL;
1006 1 hiro
        MimeInfo *partinfo;
1007 1 hiro
1008 1 hiro
        if (!mimeview->opened) return;
1009 1 hiro
        if (!mimeview->file) return;
1010 1 hiro
1011 1 hiro
        partinfo = mimeview_get_selected_part(mimeview);
1012 1 hiro
        g_return_if_fail(partinfo != NULL);
1013 1 hiro
1014 1 hiro
        if (partinfo->filename)
1015 1 hiro
                defname = partinfo->filename;
1016 1 hiro
        else if (partinfo->name) {
1017 1 hiro
                Xstrdup_a(defname, partinfo->name, return);
1018 1 hiro
                subst_for_filename(defname);
1019 1 hiro
        }
1020 1 hiro
1021 128 hiro
        filename = filesel_save_as(defname);
1022 1 hiro
        if (!filename) return;
1023 1 hiro
1024 1 hiro
        if (procmime_get_part(filename, mimeview->file, partinfo) < 0)
1025 1 hiro
                alertpanel_error
1026 1 hiro
                        (_("Can't save the part of multipart message."));
1027 128 hiro
1028 128 hiro
        g_free(filename);
1029 1 hiro
}
1030 1 hiro
1031 601 hiro
void mimeview_save_all(MimeView *mimeview)
1032 601 hiro
{
1033 601 hiro
        gchar *dir;
1034 601 hiro
1035 601 hiro
        dir = filesel_select_dir(NULL);
1036 601 hiro
        if (!dir) return;
1037 601 hiro
1038 601 hiro
        if (procmime_get_all_parts(dir, mimeview->file, mimeview->mimeinfo) < 0)
1039 601 hiro
                alertpanel_error(_("Can't save the attachments."));
1040 601 hiro
1041 601 hiro
        g_free(dir);
1042 601 hiro
}
1043 601 hiro
1044 1 hiro
static void mimeview_launch(MimeView *mimeview)
1045 1 hiro
{
1046 1 hiro
        MimeInfo *partinfo;
1047 1 hiro
        gchar *filename;
1048 1 hiro
1049 1 hiro
        if (!mimeview->opened) return;
1050 1 hiro
        if (!mimeview->file) return;
1051 1 hiro
1052 1 hiro
        partinfo = mimeview_get_selected_part(mimeview);
1053 1 hiro
        g_return_if_fail(partinfo != NULL);
1054 1 hiro
1055 1 hiro
        filename = procmime_get_tmp_file_name(partinfo);
1056 1 hiro
1057 1 hiro
        if (procmime_get_part(filename, mimeview->file, partinfo) < 0)
1058 1 hiro
                alertpanel_error
1059 1 hiro
                        (_("Can't save the part of multipart message."));
1060 1 hiro
        else
1061 1 hiro
                mimeview_view_file(filename, partinfo, NULL);
1062 1 hiro
1063 1 hiro
        g_free(filename);
1064 1 hiro
}
1065 1 hiro
1066 1 hiro
static void mimeview_open_with(MimeView *mimeview)
1067 1 hiro
{
1068 1 hiro
        MimeInfo *partinfo;
1069 1 hiro
        gchar *filename;
1070 1 hiro
        gchar *cmd;
1071 1 hiro
1072 1 hiro
        if (!mimeview->opened) return;
1073 1 hiro
        if (!mimeview->file) return;
1074 1 hiro
1075 1 hiro
        partinfo = mimeview_get_selected_part(mimeview);
1076 1 hiro
        g_return_if_fail(partinfo != NULL);
1077 1 hiro
1078 1 hiro
        filename = procmime_get_tmp_file_name(partinfo);
1079 1 hiro
1080 1 hiro
        if (procmime_get_part(filename, mimeview->file, partinfo) < 0) {
1081 1 hiro
                alertpanel_error
1082 1 hiro
                        (_("Can't save the part of multipart message."));
1083 1 hiro
                g_free(filename);
1084 1 hiro
                return;
1085 1 hiro
        }
1086 1 hiro
1087 1 hiro
        if (!prefs_common.mime_open_cmd_history)
1088 1 hiro
                prefs_common.mime_open_cmd_history =
1089 1 hiro
                        add_history(NULL, prefs_common.mime_open_cmd);
1090 1 hiro
1091 1 hiro
        cmd = input_dialog_combo
1092 1 hiro
                (_("Open with"),
1093 1 hiro
                 _("Enter the command line to open file:\n"
1094 1 hiro
                   "(`%s' will be replaced with file name)"),
1095 1 hiro
                 prefs_common.mime_open_cmd,
1096 1 hiro
                 prefs_common.mime_open_cmd_history,
1097 1 hiro
                 TRUE);
1098 1 hiro
        if (cmd) {
1099 1 hiro
                mimeview_view_file(filename, partinfo, cmd);
1100 1 hiro
                g_free(prefs_common.mime_open_cmd);
1101 1 hiro
                prefs_common.mime_open_cmd = cmd;
1102 1 hiro
                prefs_common.mime_open_cmd_history =
1103 1 hiro
                        add_history(prefs_common.mime_open_cmd_history, cmd);
1104 1 hiro
        }
1105 1 hiro
1106 1 hiro
        g_free(filename);
1107 1 hiro
}
1108 1 hiro
1109 1 hiro
static void mimeview_view_file(const gchar *filename, MimeInfo *partinfo,
1110 1 hiro
                               const gchar *cmdline)
1111 1 hiro
{
1112 1 hiro
        static gchar *default_image_cmdline = "display '%s'";
1113 1 hiro
        static gchar *default_audio_cmdline = "play '%s'";
1114 1 hiro
        static gchar *default_html_cmdline = DEFAULT_BROWSER_CMD;
1115 1 hiro
        static gchar *mime_cmdline = "metamail -d -b -x -c %s '%s'";
1116 1 hiro
        gchar buf[1024];
1117 1 hiro
        gchar m_buf[1024];
1118 1 hiro
        const gchar *cmd;
1119 1 hiro
        const gchar *def_cmd;
1120 1 hiro
        const gchar *p;
1121 1 hiro
1122 642 hiro
#ifdef G_OS_WIN32
1123 642 hiro
        if (!cmdline) {
1124 642 hiro
                DWORD dwtype;
1125 642 hiro
                AlertValue avalue;
1126 642 hiro
1127 642 hiro
                if (str_has_suffix_case(filename, ".exe") ||
1128 642 hiro
                    str_has_suffix_case(filename, ".com") ||
1129 642 hiro
                    str_has_suffix_case(filename, ".scr") ||
1130 642 hiro
                    str_has_suffix_case(filename, ".pif") ||
1131 642 hiro
                    str_has_suffix_case(filename, ".bat") ||
1132 642 hiro
                    str_has_suffix_case(filename, ".vbs") ||
1133 642 hiro
                    str_has_suffix_case(filename, ".js")  ||
1134 642 hiro
                    GetBinaryType(filename, &dwtype)) {
1135 642 hiro
                        avalue = alertpanel_full
1136 642 hiro
                                (_("Opening executable file"),
1137 642 hiro
                                 _("This is an executable file. Do you really want to launch it?"),
1138 642 hiro
                                 ALERT_WARNING, G_ALERTALTERNATE, FALSE,
1139 642 hiro
                                 GTK_STOCK_YES, GTK_STOCK_NO, NULL);
1140 642 hiro
                        if (avalue != G_ALERTDEFAULT)
1141 642 hiro
                                return;
1142 642 hiro
                }
1143 642 hiro
                execute_open_file(filename, partinfo->content_type);
1144 642 hiro
                return;
1145 642 hiro
        }
1146 642 hiro
#endif
1147 1 hiro
        if (cmdline) {
1148 1 hiro
                cmd = cmdline;
1149 1 hiro
                def_cmd = NULL;
1150 1 hiro
        } else if (MIME_APPLICATION_OCTET_STREAM == partinfo->mime_type) {
1151 1 hiro
                return;
1152 1 hiro
        } else if (MIME_IMAGE == partinfo->mime_type) {
1153 1 hiro
                cmd = prefs_common.mime_image_viewer;
1154 1 hiro
                def_cmd = default_image_cmdline;
1155 1 hiro
        } else if (MIME_AUDIO == partinfo->mime_type) {
1156 1 hiro
                cmd = prefs_common.mime_audio_player;
1157 1 hiro
                def_cmd = default_audio_cmdline;
1158 1 hiro
        } else if (MIME_TEXT_HTML == partinfo->mime_type) {
1159 1 hiro
                cmd = prefs_common.uri_cmd;
1160 1 hiro
                def_cmd = default_html_cmdline;
1161 1 hiro
        } else {
1162 1 hiro
                g_snprintf(m_buf, sizeof(m_buf), mime_cmdline,
1163 1 hiro
                           partinfo->content_type, "%s");
1164 1 hiro
                cmd = m_buf;
1165 1 hiro
                def_cmd = NULL;
1166 1 hiro
        }
1167 1 hiro
1168 1 hiro
        if (cmd && (p = strchr(cmd, '%')) && *(p + 1) == 's' &&
1169 1 hiro
            !strchr(p + 2, '%'))
1170 1 hiro
                g_snprintf(buf, sizeof(buf), cmd, filename);
1171 1 hiro
        else {
1172 1 hiro
                if (cmd)
1173 1 hiro
                        g_warning(_("MIME viewer command line is invalid: `%s'"), cmd);
1174 1 hiro
                if (def_cmd)
1175 1 hiro
                        g_snprintf(buf, sizeof(buf), def_cmd, filename);
1176 1 hiro
                else
1177 1 hiro
                        return;
1178 1 hiro
        }
1179 1 hiro
1180 1 hiro
        execute_command_line(buf, TRUE);
1181 1 hiro
}
1182 1 hiro
1183 1 hiro
#if USE_GPGME
1184 275 hiro
static gboolean update_node_name_func(GtkTreeModel *model, GtkTreePath *path,
1185 275 hiro
                                      GtkTreeIter *iter, gpointer data)
1186 1 hiro
{
1187 1 hiro
        MimeInfo *partinfo;
1188 1 hiro
        gchar *part_name;
1189 1 hiro
1190 275 hiro
        gtk_tree_model_get(model, iter, COL_MIME_INFO, &partinfo, -1);
1191 275 hiro
        g_return_val_if_fail(partinfo != NULL, FALSE);
1192 1 hiro
1193 1 hiro
        part_name = get_part_name(partinfo);
1194 275 hiro
        gtk_tree_store_set(GTK_TREE_STORE(model), iter, COL_NAME, part_name,
1195 275 hiro
                           -1);
1196 275 hiro
1197 275 hiro
        return FALSE;
1198 1 hiro
}
1199 1 hiro
1200 1 hiro
static void mimeview_update_names(MimeView *mimeview)
1201 1 hiro
{
1202 275 hiro
        gtk_tree_model_foreach(GTK_TREE_MODEL(mimeview->store),
1203 275 hiro
                               update_node_name_func, NULL);
1204 1 hiro
}
1205 1 hiro
1206 1 hiro
static void mimeview_update_signature_info(MimeView *mimeview)
1207 1 hiro
{
1208 1 hiro
        MimeInfo *partinfo;
1209 1 hiro
1210 1 hiro
        if (!mimeview) return;
1211 1 hiro
        if (!mimeview->opened) return;
1212 1 hiro
1213 1 hiro
        partinfo = mimeview_get_selected_part(mimeview);
1214 1 hiro
        if (!partinfo) return;
1215 1 hiro
1216 605 hiro
        if (rfc2015_is_signature_part(partinfo)) {
1217 1 hiro
                mimeview_change_view_type(mimeview, MIMEVIEW_TEXT);
1218 135 hiro
                mimeview_show_signature_part(mimeview, partinfo);
1219 1 hiro
        }
1220 1 hiro
}
1221 1 hiro
1222 1 hiro
static void mimeview_check_signature(MimeView *mimeview)
1223 1 hiro
{
1224 1 hiro
        MimeInfo *mimeinfo;
1225 1 hiro
        FILE *fp;
1226 1 hiro
1227 1 hiro
        g_return_if_fail (mimeview_is_signed(mimeview));
1228 1 hiro
1229 1 hiro
        mimeinfo = mimeview_get_selected_part(mimeview);
1230 1 hiro
        g_return_if_fail(mimeinfo != NULL);
1231 1 hiro
        g_return_if_fail(mimeview->file != NULL);
1232 1 hiro
1233 1 hiro
        while (mimeinfo->parent)
1234 1 hiro
                mimeinfo = mimeinfo->parent;
1235 1 hiro
1236 478 hiro
        if ((fp = g_fopen(mimeview->file, "rb")) == NULL) {
1237 1 hiro
                FILE_OP_ERROR(mimeview->file, "fopen");
1238 1 hiro
                return;
1239 1 hiro
        }
1240 1 hiro
1241 1 hiro
        rfc2015_check_signature(mimeinfo, fp);
1242 1 hiro
        fclose(fp);
1243 1 hiro
1244 1 hiro
        mimeview_update_names(mimeview);
1245 1 hiro
        mimeview_update_signature_info(mimeview);
1246 1 hiro
1247 1 hiro
        textview_show_message(mimeview->messageview->textview, mimeinfo,
1248 1 hiro
                              mimeview->file);
1249 1 hiro
}
1250 1 hiro
#endif /* USE_GPGME */