/* this file is part of atril, a mate document viewer * * Copyright (C) 2006 Carlos Garcia Campos <carlosgc@gnome.org> * * Atril is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * Atril is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include <config.h> #include <glib/gi18n-lib.h> #include <glib/gstdio.h> #include <gtk/gtk.h> #include "ev-file-helpers.h" #include "ev-attachment.h" enum { PROP_0, PROP_NAME, PROP_DESCRIPTION, PROP_MTIME, PROP_CTIME, PROP_SIZE, PROP_DATA }; struct _EvAttachmentPrivate { gchar *name; gchar *description; GTime mtime; GTime ctime; gsize size; gchar *data; gchar *mime_type; GAppInfo *app; GFile *tmp_file; }; #define EV_ATTACHMENT_GET_PRIVATE(object) \ (G_TYPE_INSTANCE_GET_PRIVATE ((object), EV_TYPE_ATTACHMENT, EvAttachmentPrivate)) G_DEFINE_TYPE (EvAttachment, ev_attachment, G_TYPE_OBJECT) GQuark ev_attachment_error_quark (void) { static GQuark error_quark = 0; if (error_quark == 0) error_quark = g_quark_from_static_string ("ev-attachment-error-quark"); return error_quark; } static void ev_attachment_finalize (GObject *object) { EvAttachment *attachment = EV_ATTACHMENT (object); if (attachment->priv->name) { g_free (attachment->priv->name); attachment->priv->name = NULL; } if (attachment->priv->description) { g_free (attachment->priv->description); attachment->priv->description = NULL; } if (attachment->priv->data) { g_free (attachment->priv->data); attachment->priv->data = NULL; } if (attachment->priv->mime_type) { g_free (attachment->priv->mime_type); attachment->priv->mime_type = NULL; } if (attachment->priv->app) { g_object_unref (attachment->priv->app); attachment->priv->app = NULL; } if (attachment->priv->tmp_file) { ev_tmp_file_unlink (attachment->priv->tmp_file); g_object_unref (attachment->priv->tmp_file); attachment->priv->tmp_file = NULL; } G_OBJECT_CLASS (ev_attachment_parent_class)->finalize (object); } static void ev_attachment_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *param_spec) { EvAttachment *attachment = EV_ATTACHMENT (object); switch (prop_id) { case PROP_NAME: attachment->priv->name = g_value_dup_string (value); break; case PROP_DESCRIPTION: attachment->priv->description = g_value_dup_string (value); break; case PROP_MTIME: attachment->priv->mtime = g_value_get_ulong (value); break; case PROP_CTIME: attachment->priv->ctime = g_value_get_ulong (value); break; case PROP_SIZE: attachment->priv->size = g_value_get_uint (value); break; case PROP_DATA: attachment->priv->data = g_value_get_pointer (value); attachment->priv->mime_type = g_content_type_guess (attachment->priv->name, (guchar *) attachment->priv->data, attachment->priv->size, NULL); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, param_spec); break; } } static void ev_attachment_class_init (EvAttachmentClass *klass) { GObjectClass *g_object_class; g_object_class = G_OBJECT_CLASS (klass); g_object_class->set_property = ev_attachment_set_property; g_type_class_add_private (g_object_class, sizeof (EvAttachmentPrivate)); /* Properties */ g_object_class_install_property (g_object_class, PROP_NAME, g_param_spec_string ("name", "Name", "The attachment name", NULL, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); g_object_class_install_property (g_object_class, PROP_DESCRIPTION, g_param_spec_string ("description", "Description", "The attachment description", NULL, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); g_object_class_install_property (g_object_class, PROP_MTIME, g_param_spec_ulong ("mtime", "ModifiedTime", "The attachment modification date", 0, G_MAXULONG, 0, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); g_object_class_install_property (g_object_class, PROP_CTIME, g_param_spec_ulong ("ctime", "CreationTime", "The attachment creation date", 0, G_MAXULONG, 0, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); g_object_class_install_property (g_object_class, PROP_SIZE, g_param_spec_uint ("size", "Size", "The attachment size", 0, G_MAXUINT, 0, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); g_object_class_install_property (g_object_class, PROP_DATA, g_param_spec_pointer ("data", "Data", "The attachment data", G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); g_object_class->finalize = ev_attachment_finalize; } static void ev_attachment_init (EvAttachment *attachment) { attachment->priv = EV_ATTACHMENT_GET_PRIVATE (attachment); attachment->priv->name = NULL; attachment->priv->description = NULL; attachment->priv->data = NULL; attachment->priv->mime_type = NULL; attachment->priv->tmp_file = NULL; } EvAttachment * ev_attachment_new (const gchar *name, const gchar *description, GTime mtime, GTime ctime, gsize size, gpointer data) { EvAttachment *attachment; attachment = g_object_new (EV_TYPE_ATTACHMENT, "name", name, "description", description, "mtime", mtime, "ctime", ctime, "size", size, "data", data, NULL); return attachment; } const gchar * ev_attachment_get_name (EvAttachment *attachment) { g_return_val_if_fail (EV_IS_ATTACHMENT (attachment), NULL); return attachment->priv->name; } const gchar * ev_attachment_get_description (EvAttachment *attachment) { g_return_val_if_fail (EV_IS_ATTACHMENT (attachment), NULL); return attachment->priv->description; } GTime ev_attachment_get_modification_date (EvAttachment *attachment) { g_return_val_if_fail (EV_IS_ATTACHMENT (attachment), 0); return attachment->priv->mtime; } GTime ev_attachment_get_creation_date (EvAttachment *attachment) { g_return_val_if_fail (EV_IS_ATTACHMENT (attachment), 0); return attachment->priv->ctime; } const gchar * ev_attachment_get_mime_type (EvAttachment *attachment) { g_return_val_if_fail (EV_IS_ATTACHMENT (attachment), NULL); return attachment->priv->mime_type; } gboolean ev_attachment_save (EvAttachment *attachment, GFile *file, GError **error) { GFileOutputStream *output_stream; GError *ioerror = NULL; gssize written_bytes; g_return_val_if_fail (EV_IS_ATTACHMENT (attachment), FALSE); g_return_val_if_fail (G_IS_FILE (file), FALSE); output_stream = g_file_replace (file, NULL, FALSE, 0, NULL, &ioerror); if (output_stream == NULL) { char *uri; uri = g_file_get_uri (file); g_set_error (error, EV_ATTACHMENT_ERROR, ioerror->code, _("Couldn't save attachment “%s”: %s"), uri, ioerror->message); g_error_free (ioerror); g_free (uri); return FALSE; } written_bytes = g_output_stream_write (G_OUTPUT_STREAM (output_stream), attachment->priv->data, attachment->priv->size, NULL, &ioerror); if (written_bytes == -1) { char *uri; uri = g_file_get_uri (file); g_set_error (error, EV_ATTACHMENT_ERROR, ioerror->code, _("Couldn't save attachment “%s”: %s"), uri, ioerror->message); g_output_stream_close (G_OUTPUT_STREAM (output_stream), NULL, NULL); g_error_free (ioerror); g_free (uri); return FALSE; } g_output_stream_close (G_OUTPUT_STREAM (output_stream), NULL, NULL); return TRUE; } static gboolean ev_attachment_launch_app (EvAttachment *attachment, GdkScreen *screen, guint32 timestamp, GError **error) { gboolean result; GList *files = NULL; #if GTK_CHECK_VERSION (3, 0, 0) GdkAppLaunchContext *context; GdkDisplay *display; #else GAppLaunchContext *context = NULL; #endif GError *ioerror = NULL; g_assert (G_IS_FILE (attachment->priv->tmp_file)); g_assert (G_IS_APP_INFO (attachment->priv->app)); files = g_list_prepend (files, attachment->priv->tmp_file); #if GTK_CHECK_VERSION (3, 0, 0) display = screen ? gdk_screen_get_display (screen) : gdk_display_get_default (); context = gdk_display_get_app_launch_context (display); gdk_app_launch_context_set_screen (context, screen); gdk_app_launch_context_set_timestamp (context, timestamp); result = g_app_info_launch (attachment->priv->app, files, G_APP_LAUNCH_CONTEXT (context), &ioerror); g_object_unref (context); #else context = G_APP_LAUNCH_CONTEXT (gdk_app_launch_context_new ()); gdk_app_launch_context_set_screen (GDK_APP_LAUNCH_CONTEXT (context), screen); gdk_app_launch_context_set_timestamp (GDK_APP_LAUNCH_CONTEXT (context), timestamp); result = g_app_info_launch (attachment->priv->app, files, context, &ioerror); if (context) g_object_unref (context); #endif if (!result) { g_set_error (error, EV_ATTACHMENT_ERROR, (gint) result, _("Couldn't open attachment “%s”: %s"), attachment->priv->name, ioerror->message); g_list_free (files); g_error_free (ioerror); return FALSE; } g_list_free (files); return TRUE; } gboolean ev_attachment_open (EvAttachment *attachment, GdkScreen *screen, guint32 timestamp, GError **error) { GAppInfo *app_info; gboolean retval = FALSE; g_return_val_if_fail (EV_IS_ATTACHMENT (attachment), FALSE); if (!attachment->priv->app) { app_info = g_app_info_get_default_for_type (attachment->priv->mime_type, FALSE); attachment->priv->app = app_info; } if (!attachment->priv->app) { g_set_error (error, EV_ATTACHMENT_ERROR, 0, _("Couldn't open attachment “%s”"), attachment->priv->name); return FALSE; } if (attachment->priv->tmp_file) { retval = ev_attachment_launch_app (attachment, screen, timestamp, error); } else { char *basename; char *template; GFile *file; /* FIXMEchpe: convert to filename encoding first! */ basename = g_path_get_basename (ev_attachment_get_name (attachment)); template = g_strdup_printf ("%s.XXXXXX", basename); file = ev_mkstemp_file (template, error); g_free (template); g_free (basename); if (file != NULL && ev_attachment_save (attachment, file, error)) { if (attachment->priv->tmp_file) g_object_unref (attachment->priv->tmp_file); attachment->priv->tmp_file = g_object_ref (file); retval = ev_attachment_launch_app (attachment, screen, timestamp, error); } g_object_unref (file); } return retval; }