Evince
Evince is a document viewer capable of displaying multiple and single page document formats like PDF and Postscript.
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
ev-attachment.c
Go to the documentation of this file.
1 /* this file is part of evince, a gnome document viewer
2  *
3  * Copyright (C) 2006 Carlos Garcia Campos <carlosgc@gnome.org>
4  *
5  * Evince is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * Evince is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18  */
19 
20 #include <config.h>
21 #include <glib/gi18n-lib.h>
22 #include <glib/gstdio.h>
23 #include <gtk/gtk.h>
24 #include "ev-file-helpers.h"
25 #include "ev-attachment.h"
26 
27 enum
28 {
36 };
37 
39  gchar *name;
40  gchar *description;
41  GTime mtime;
42  GTime ctime;
43  gsize size;
44  gchar *data;
45  gchar *mime_type;
46 
47  GAppInfo *app;
48  GFile *tmp_file;
49 };
50 
51 #define EV_ATTACHMENT_GET_PRIVATE(object) \
52  (G_TYPE_INSTANCE_GET_PRIVATE ((object), EV_TYPE_ATTACHMENT, EvAttachmentPrivate))
53 
54 G_DEFINE_TYPE (EvAttachment, ev_attachment, G_TYPE_OBJECT)
55 
56 GQuark
58 {
59  static GQuark error_quark = 0;
60 
61  if (error_quark == 0)
62  error_quark =
63  g_quark_from_static_string ("ev-attachment-error-quark");
64 
65  return error_quark;
66 }
67 
68 static void
69 ev_attachment_finalize (GObject *object)
70 {
71  EvAttachment *attachment = EV_ATTACHMENT (object);
72 
73  if (attachment->priv->name) {
74  g_free (attachment->priv->name);
75  attachment->priv->name = NULL;
76  }
77 
78  if (attachment->priv->description) {
79  g_free (attachment->priv->description);
80  attachment->priv->description = NULL;
81  }
82 
83  if (attachment->priv->data) {
84  g_free (attachment->priv->data);
85  attachment->priv->data = NULL;
86  }
87 
88  if (attachment->priv->mime_type) {
89  g_free (attachment->priv->mime_type);
90  attachment->priv->mime_type = NULL;
91  }
92 
93  if (attachment->priv->app) {
94  g_object_unref (attachment->priv->app);
95  attachment->priv->app = NULL;
96  }
97 
98  if (attachment->priv->tmp_file) {
99  ev_tmp_file_unlink (attachment->priv->tmp_file);
100  g_object_unref (attachment->priv->tmp_file);
101  attachment->priv->tmp_file = NULL;
102  }
103 
104  G_OBJECT_CLASS (ev_attachment_parent_class)->finalize (object);
105 }
106 
107 static void
108 ev_attachment_set_property (GObject *object,
109  guint prop_id,
110  const GValue *value,
111  GParamSpec *param_spec)
112 {
113  EvAttachment *attachment = EV_ATTACHMENT (object);
114 
115  switch (prop_id) {
116  case PROP_NAME:
117  attachment->priv->name = g_value_dup_string (value);
118  break;
119  case PROP_DESCRIPTION:
120  attachment->priv->description = g_value_dup_string (value);
121  break;
122  case PROP_MTIME:
123  attachment->priv->mtime = g_value_get_ulong (value);
124  break;
125  case PROP_CTIME:
126  attachment->priv->ctime = g_value_get_ulong (value);
127  break;
128  case PROP_SIZE:
129  attachment->priv->size = g_value_get_uint (value);
130  break;
131  case PROP_DATA:
132  attachment->priv->data = g_value_get_pointer (value);
133  attachment->priv->mime_type = g_content_type_guess (attachment->priv->name,
134  (guchar *) attachment->priv->data,
135  attachment->priv->size,
136  NULL);
137  break;
138  default:
139  G_OBJECT_WARN_INVALID_PROPERTY_ID (object,
140  prop_id,
141  param_spec);
142  break;
143  }
144 }
145 
146 static void
148 {
149  GObjectClass *g_object_class;
150 
151  g_object_class = G_OBJECT_CLASS (klass);
152 
153  g_object_class->set_property = ev_attachment_set_property;
154 
155  g_type_class_add_private (g_object_class, sizeof (EvAttachmentPrivate));
156 
157  /* Properties */
158  g_object_class_install_property (g_object_class,
159  PROP_NAME,
160  g_param_spec_string ("name",
161  "Name",
162  "The attachment name",
163  NULL,
164  G_PARAM_WRITABLE |
165  G_PARAM_CONSTRUCT_ONLY |
166  G_PARAM_STATIC_STRINGS));
167  g_object_class_install_property (g_object_class,
169  g_param_spec_string ("description",
170  "Description",
171  "The attachment description",
172  NULL,
173  G_PARAM_WRITABLE |
174  G_PARAM_CONSTRUCT_ONLY |
175  G_PARAM_STATIC_STRINGS));
176  g_object_class_install_property (g_object_class,
177  PROP_MTIME,
178  g_param_spec_ulong ("mtime",
179  "ModifiedTime",
180  "The attachment modification date",
181  0, G_MAXULONG, 0,
182  G_PARAM_WRITABLE |
183  G_PARAM_CONSTRUCT_ONLY |
184  G_PARAM_STATIC_STRINGS));
185  g_object_class_install_property (g_object_class,
186  PROP_CTIME,
187  g_param_spec_ulong ("ctime",
188  "CreationTime",
189  "The attachment creation date",
190  0, G_MAXULONG, 0,
191  G_PARAM_WRITABLE |
192  G_PARAM_CONSTRUCT_ONLY |
193  G_PARAM_STATIC_STRINGS));
194  g_object_class_install_property (g_object_class,
195  PROP_SIZE,
196  g_param_spec_uint ("size",
197  "Size",
198  "The attachment size",
199  0, G_MAXUINT, 0,
200  G_PARAM_WRITABLE |
201  G_PARAM_CONSTRUCT_ONLY |
202  G_PARAM_STATIC_STRINGS));
203  g_object_class_install_property (g_object_class,
204  PROP_DATA,
205  g_param_spec_pointer ("data",
206  "Data",
207  "The attachment data",
208  G_PARAM_WRITABLE |
209  G_PARAM_CONSTRUCT_ONLY |
210  G_PARAM_STATIC_STRINGS));
211 
212  g_object_class->finalize = ev_attachment_finalize;
213 }
214 
215 static void
217 {
218  attachment->priv = EV_ATTACHMENT_GET_PRIVATE (attachment);
219 
220  attachment->priv->name = NULL;
221  attachment->priv->description = NULL;
222  attachment->priv->data = NULL;
223  attachment->priv->mime_type = NULL;
224 
225  attachment->priv->tmp_file = NULL;
226 }
227 
228 EvAttachment *
229 ev_attachment_new (const gchar *name,
230  const gchar *description,
231  GTime mtime,
232  GTime ctime,
233  gsize size,
234  gpointer data)
235 {
236  EvAttachment *attachment;
237 
238  attachment = g_object_new (EV_TYPE_ATTACHMENT,
239  "name", name,
240  "description", description,
241  "mtime", mtime,
242  "ctime", ctime,
243  "size", size,
244  "data", data,
245  NULL);
246 
247  return attachment;
248 }
249 
250 const gchar *
252 {
253  g_return_val_if_fail (EV_IS_ATTACHMENT (attachment), NULL);
254 
255  return attachment->priv->name;
256 }
257 
258 const gchar *
260 {
261  g_return_val_if_fail (EV_IS_ATTACHMENT (attachment), NULL);
262 
263  return attachment->priv->description;
264 }
265 
266 GTime
268 {
269  g_return_val_if_fail (EV_IS_ATTACHMENT (attachment), 0);
270 
271  return attachment->priv->mtime;
272 }
273 
274 GTime
276 {
277  g_return_val_if_fail (EV_IS_ATTACHMENT (attachment), 0);
278 
279  return attachment->priv->ctime;
280 }
281 
282 const gchar *
284 {
285  g_return_val_if_fail (EV_IS_ATTACHMENT (attachment), NULL);
286 
287  return attachment->priv->mime_type;
288 }
289 
290 gboolean
292  GFile *file,
293  GError **error)
294 {
295  GFileOutputStream *output_stream;
296  GError *ioerror = NULL;
297  gssize written_bytes;
298 
299  g_return_val_if_fail (EV_IS_ATTACHMENT (attachment), FALSE);
300  g_return_val_if_fail (G_IS_FILE (file), FALSE);
301 
302  output_stream = g_file_replace (file, NULL, FALSE, 0, NULL, &ioerror);
303  if (output_stream == NULL) {
304  char *uri;
305 
306  uri = g_file_get_uri (file);
307  g_set_error (error,
309  ioerror->code,
310  _("Couldn’t save attachment “%s”: %s"),
311  uri,
312  ioerror->message);
313 
314  g_error_free (ioerror);
315  g_free (uri);
316 
317  return FALSE;
318  }
319 
320  written_bytes = g_output_stream_write (G_OUTPUT_STREAM (output_stream),
321  attachment->priv->data,
322  attachment->priv->size,
323  NULL, &ioerror);
324  if (written_bytes == -1) {
325  char *uri;
326 
327  uri = g_file_get_uri (file);
328  g_set_error (error,
330  ioerror->code,
331  _("Couldn’t save attachment “%s”: %s"),
332  uri,
333  ioerror->message);
334 
335  g_output_stream_close (G_OUTPUT_STREAM (output_stream), NULL, NULL);
336  g_error_free (ioerror);
337  g_free (uri);
338 
339  return FALSE;
340  }
341 
342  g_output_stream_close (G_OUTPUT_STREAM (output_stream), NULL, NULL);
343 
344  return TRUE;
345 
346 }
347 
348 static gboolean
350  GdkScreen *screen,
351  guint32 timestamp,
352  GError **error)
353 {
354  gboolean result;
355  GList *files = NULL;
356  GdkAppLaunchContext *context;
357  GdkDisplay *display;
358  GError *ioerror = NULL;
359 
360  g_assert (G_IS_FILE (attachment->priv->tmp_file));
361  g_assert (G_IS_APP_INFO (attachment->priv->app));
362 
363  files = g_list_prepend (files, attachment->priv->tmp_file);
364 
365  display = screen ? gdk_screen_get_display (screen) : gdk_display_get_default ();
366  context = gdk_display_get_app_launch_context (display);
367  gdk_app_launch_context_set_screen (context, screen);
368  gdk_app_launch_context_set_timestamp (context, timestamp);
369 
370  result = g_app_info_launch (attachment->priv->app, files,
371  G_APP_LAUNCH_CONTEXT (context),
372  &ioerror);
373  g_object_unref (context);
374 
375  if (!result) {
376  g_set_error (error,
378  (gint) result,
379  _("Couldn’t open attachment “%s”: %s"),
380  attachment->priv->name,
381  ioerror->message);
382 
383  g_list_free (files);
384  g_error_free (ioerror);
385 
386  return FALSE;
387  }
388 
389  g_list_free (files);
390 
391  return TRUE;
392 }
393 
394 gboolean
396  GdkScreen *screen,
397  guint32 timestamp,
398  GError **error)
399 {
400  GAppInfo *app_info;
401  gboolean retval = FALSE;
402 
403  g_return_val_if_fail (EV_IS_ATTACHMENT (attachment), FALSE);
404 
405  if (!attachment->priv->app) {
406  app_info = g_app_info_get_default_for_type (attachment->priv->mime_type, FALSE);
407  attachment->priv->app = app_info;
408  }
409 
410  if (!attachment->priv->app) {
411  g_set_error (error,
413  0,
414  _("Couldn’t open attachment “%s”"),
415  attachment->priv->name);
416 
417  return FALSE;
418  }
419 
420  if (attachment->priv->tmp_file) {
421  retval = ev_attachment_launch_app (attachment, screen,
422  timestamp, error);
423  } else {
424  char *basename;
425  char *template;
426  GFile *file;
427 
428  /* FIXMEchpe: convert to filename encoding first! */
429  basename = g_path_get_basename (ev_attachment_get_name (attachment));
430  template = g_strdup_printf ("%s.XXXXXX", basename);
431  file = ev_mkstemp_file (template, error);
432  g_free (template);
433  g_free (basename);
434 
435  if (file != NULL && ev_attachment_save (attachment, file, error)) {
436  if (attachment->priv->tmp_file)
437  g_object_unref (attachment->priv->tmp_file);
438  attachment->priv->tmp_file = g_object_ref (file);
439 
440  retval = ev_attachment_launch_app (attachment, screen,
441  timestamp, error);
442  }
443 
444  g_object_unref (file);
445  }
446 
447  return retval;
448 }
449