Logo Search packages:      
Sourcecode: deb-gview version File versions  Download package

dvpreview.c

/********************************************************************
 *            dvpreview.c
 *
 *  Thu Sep 14 21:36:56 2006
 *  Copyright  2006  Neil Williams
 *  linux@codehelp.co.uk
 *******************************************************************/
/*
 *  This program 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.
 *
 *  This program 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.
 */

#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif
#include <stdio.h>
#include <unistd.h>
#include <glib.h>
#include <glib/gstdio.h>
#include <string.h>
#include "dvpreview.h"
#include "support.h"

/* location of key file in user home */
#define DVKEYDIR ".deb-gview"
/* name of key file in location. */
#define DVKEYFILE "preview"
/* key name for glob pattern */
#define DVKEYGLOB "pattern"
/* key name for application to spawn */
#define DVKEYPROG "viewer"
/* key name for whether to use a terminal. */
#define DVKEYTERM "use_terminal"
/* default terminal application */
#define DVDEFAULT "xterm"
/* default execute command */
#define DVEXECUTE "-e"
/* key name for execute command */
#define DVXCOMMAND "execute_command"
/* default man command */
#define DVMAN "man"
/* package terminal command */
#define DVCOMMAND "terminal"
/* key name for whether content is binary */
#define DVBINARY "binary_file"
/* key name for suffix, if any */
#define DVSUFFIX "file_suffix"

#define TMPPREFIX "dvXXXXXX"

static const gchar * comment = NULL;
static gchar * terminal = NULL;
static gchar * execute = NULL;
static GList * preview_list = NULL;

typedef struct
{
      gboolean use_term;
      gboolean use_binary;
      gchar * suffix;
      gchar * pattern;
      gchar * viewer;
      GPatternSpec * spec;
      const gchar * filename;
} DVPreview;

static void
dv_push_error (DVContents * deb, GError *gerr)
{
      GtkWidget *sbar;
      guint s_id;
      gchar * msg;

      sbar = lookup_widget(GTK_WIDGET(dv_get_parent(deb)), 
            "dvstatusbar");
      s_id = gtk_statusbar_get_context_id (GTK_STATUSBAR(sbar), 
            "errors");
      gtk_statusbar_pop (GTK_STATUSBAR(sbar), s_id);
      msg = g_strdup_printf (_("Unable to preview '%s'. "
            "%s"), dv_get_selected_file (deb), gerr->message);
      gtk_statusbar_push (GTK_STATUSBAR(sbar), s_id, msg);
      g_error_free (gerr);
}

static gchar**
create_groups (GKeyFile * kf, const gchar * keyfile)
{
      gsize len, num;
      gchar * kfdata;
      gchar **groups;
      GError * gerr = NULL;

      /* Translators: This text is much easier to read with
      a space after each newline */
      comment = g_strconcat (_(" deb-gview can use this "
      "dot-file in your home directory \n "
      "(~/.deb-gview/preview) to specify which applications "
      "should\n be used to preview files from the package.\n "
      "You are free to edit this file, deb-gview will\n "
      "not modify it, although it will be replaced if it is\n "
      "deleted.\n The first matching pattern will be used, so\n "
      "put the most general wildcards (like *) at the end of\n "
      "this file.\n\n "),
      DVKEYGLOB, " = ", _("glob-style pattern to match the "
      "location of\n the file in the package (not the filesystem).\n "),
      DVKEYPROG, " = ", _("the program to call to view the file "
      "content\n (which must exist in your system PATH).\n "),
      DVKEYTERM, " = ", _("whether to use a terminal, TRUE or FALSE.\n "),
      DVBINARY, " = ", _("whether the viewer needs a binary file"
      ",\n TRUE or FALSE.\n "),
      DVSUFFIX, " = ", _("if the viewer needs a specific suffix, add "
      "it here\n "), NULL);
      g_key_file_set_comment (kf, NULL, NULL, comment, NULL);

      /* package defaults */
      comment = _(" Your choice of terminal application.\n");
      g_key_file_set_string  (kf, PACKAGE, DVCOMMAND, DVDEFAULT);
      g_key_file_set_comment (kf, PACKAGE, NULL, comment, NULL);
      g_key_file_set_string  (kf, PACKAGE, DVXCOMMAND, DVEXECUTE);

      /* man pages */
      g_key_file_set_string (kf, _("manual pages"), DVKEYGLOB, 
            "./usr/share/man/man*/*");
      g_key_file_set_string (kf, _("manual pages"), DVKEYPROG, 
            DVMAN);
      g_key_file_set_boolean (kf, _("manual pages"), DVKEYTERM,
            TRUE);
      g_key_file_set_boolean (kf, _("manual pages"), DVBINARY,
            FALSE);
      g_key_file_set_string (kf, _("manual pages"), DVSUFFIX,     "");

      /* html */
      g_key_file_set_string (kf, "HTML", DVKEYGLOB, 
            "*.html");
      g_key_file_set_string (kf, "HTML", DVKEYPROG, 
            "sensible-browser");
      g_key_file_set_boolean (kf, "HTML", DVKEYTERM,
            FALSE);
      g_key_file_set_boolean (kf, "HTML", DVBINARY,
            FALSE);
      g_key_file_set_string (kf, "HTML", DVSUFFIX,
            "html");

      /* png */
      g_key_file_set_string (kf, "PNG", DVKEYGLOB, 
            "*.png");
      g_key_file_set_string (kf, "PNG", DVKEYPROG, 
            "qiv");
      g_key_file_set_boolean (kf, "PNG", DVKEYTERM,
            FALSE);
      g_key_file_set_boolean (kf, "PNG", DVBINARY,
            TRUE);
      g_key_file_set_string (kf, "PNG", DVSUFFIX,
            "png");

      /* text */
      g_key_file_set_string (kf, "text", DVKEYGLOB, 
            "*");
      g_key_file_set_string (kf, "text", DVKEYPROG, 
            "gedit");
      g_key_file_set_boolean (kf, "text", DVKEYTERM,
            FALSE);
      g_key_file_set_boolean (kf, "text", DVBINARY,
            FALSE);
      g_key_file_set_string (kf, "text", DVSUFFIX, "");

      kfdata = g_key_file_to_data(kf, &len, &gerr);
      if (gerr != NULL)
      {
            g_warning (gerr->message);
            g_clear_error (&gerr);
            return NULL;
      }
      g_file_set_contents (keyfile, kfdata, len, &gerr);
      if (gerr != NULL)
      {
            g_warning (gerr->message);
            g_clear_error (&gerr);
            return NULL;
      }
      groups = g_key_file_get_groups (kf, &num);
      return groups;
}

static gboolean
parse_groups (GKeyFile * kf, gchar **groups, const gchar * keyfile)
{
      guint num, c;
      gchar * file_glob, * prog, * path_prog;
      GError * gerr;
      gboolean use_term;
      DVPreview * prev;

      gerr = NULL;
      use_term = FALSE;
      num = g_strv_length(groups);
      if (num == 0)
      {
            groups = create_groups (kf, keyfile);
            num = g_strv_length(groups);
      }
      if (!groups)
            return FALSE;
      terminal = g_key_file_get_string (kf, PACKAGE, DVCOMMAND, &gerr);
      if (gerr != NULL)
      {
            g_warning (gerr->message);
            g_clear_error (&gerr);
      }
      execute  = g_key_file_get_string (kf, PACKAGE, DVXCOMMAND, &gerr);
      if (gerr != NULL)
      {
            g_warning (gerr->message);
            g_clear_error (&gerr);
      }
      for (c = 0;c < num; c++)
      {
            if (0 == g_ascii_strcasecmp(groups[c], PACKAGE))
                  continue;
            file_glob = g_key_file_get_string (kf, groups[c], 
                  DVKEYGLOB, &gerr);
            if (!file_glob)
            {
                  g_warning (gerr->message);
                  g_clear_error (&gerr);
                  continue;
            }
            use_term = g_key_file_get_boolean (kf, groups[c], 
                  DVKEYTERM, &gerr);
            if (gerr != NULL)
            {
                  g_warning (gerr->message);
                  g_clear_error (&gerr);
                  continue;
            }
            prog = g_key_file_get_string (kf, groups[c], 
                  DVKEYPROG, &gerr);
            if (!prog)
            {
                  g_warning (gerr->message);
                  g_clear_error (&gerr);
                  continue;
            }
            prev = g_new0 (DVPreview, 1);
            if (!use_term)
            {
                  path_prog = g_find_program_in_path (prog);
                  prev->viewer = path_prog;
            }
            else
                  prev->viewer = prog;
            prev->use_binary = g_key_file_get_boolean (kf, groups[c],
                  DVBINARY, &gerr);
            prev->suffix = g_key_file_get_string (kf, groups[c],
                  DVSUFFIX, &gerr);
            prev->pattern = file_glob;
            prev->spec = g_pattern_spec_new (prev->pattern);
            prev->use_term = use_term;
            preview_list = g_list_append (preview_list, prev);
            g_free (file_glob);
      }
      return TRUE;
}

gboolean
preview_init (void)
{
      const gchar * home;
      gchar * path, * file;
      gchar **groups;
      GKeyFile * kf;
      GError * gerr;
      gboolean success;

      gerr = NULL;
      home = g_get_home_dir ();
      path = g_strconcat (home, "/", DVKEYDIR, NULL);
      if (!g_file_test (path, G_FILE_TEST_IS_DIR))
            g_mkdir_with_parents (path, 0755);
      kf = g_key_file_new ();
      file = g_strconcat (path, "/", DVKEYFILE, NULL);
      success = g_key_file_load_from_file (kf, file, 
            G_KEY_FILE_KEEP_COMMENTS, &gerr);
      groups = g_key_file_get_groups (kf, NULL);
      success = parse_groups (kf, groups, file);
      if (g_strv_length(groups) > 0)
            g_strfreev (groups);
      return success;
}

static void
clear_list (gpointer value, gpointer user_data)
{
      DVPreview * prev = (DVPreview*)value;
      if (!prev)
            return;
      g_pattern_spec_free (prev->spec);
      if (prev->viewer)
            g_free (prev->viewer);
      g_free (prev);
}

void
preview_shutdown (void)
{
      if (g_list_length(preview_list) > 0)
            g_list_foreach (preview_list, clear_list, NULL);
}

static DVPreview *
glob_key_pattern (const gchar * file, gssize len, const gchar * rev)
{
      GList * run;
      DVPreview * prev;
      gboolean match;

      match = FALSE;
      for (run = preview_list; run != NULL; run = g_list_next(run))
      {
            prev = (DVPreview*)run->data;
            if (!prev)
                  return NULL;
            match = g_pattern_match (prev->spec, len, file, rev);
            if (match)
                  return prev;
      }
      return NULL;
}

static DVPreview *
get_preview_data (DVContents * deb)
{
      const gchar * file;
      DVPreview * globbed;
      gchar * file_rev;
      GError * gerr;
      gssize len;

      gerr = NULL;
      /* match the archive filename against the pattern
      but pass the uncompressed temporary file to the
      spawned app. */
      file = g_filename_to_utf8(dv_get_selected_file (deb),
            -1, NULL, NULL, &gerr);
      if (!file)
      {
            dv_push_error (deb, gerr);
            return NULL;
      }
      len = g_utf8_strlen (file, 255);
      if (len == 0)
            return NULL;
      file_rev = g_utf8_strreverse (file, len);
      /* look up filename in keyfile list
      and glob the pattern */
      globbed = glob_key_pattern (file, len, file_rev);
      if (!globbed)
            return NULL;
      globbed->filename = file;
      return globbed;
}

void
dv_spawn_external (GtkWidget * widget, DVContents * deb)
{
      gchar *temp_file, * tmp_name, **argv;
      gpointer content;
      DVPreview * prev;
      GError * gerr;
      gint argc, f;
      gint64 size;
      FILE * tmp;

      gerr = NULL;
      temp_file = NULL;
      deb = (DVContents*) lookup_widget (GTK_WIDGET(widget), 
            DVCONTENTS);
      g_return_if_fail (deb);
      prev = get_preview_data (deb);
      if (!prev)
      {
            g_set_error (&gerr, 1001, 1002, 
                  _("No matching pattern in the key file."));
            dv_push_error (deb, gerr);
            return;
      }
      /* glib temp files don't cope well with suffixes. */
      f = g_file_open_tmp (TMPPREFIX,     &tmp_name, &gerr);
      if (g_strcasecmp ("", prev->suffix))
      {
            temp_file = g_strconcat (tmp_name, ".", 
                  prev->suffix, NULL);
            g_remove (tmp_name);
      }
      else
            temp_file = g_strdup (tmp_name);
      close (f);
      if (gerr != NULL)
            dv_push_error (deb, gerr);
      if (prev->use_binary == TRUE)
      {
            content = dv_get_raw_content (deb);
            if (!content)
                  return;
            size = dv_get_content_length (deb);
            if (size == 0)
                  return;
            tmp = fopen (temp_file, "wb");
            fwrite (content, size, 1, tmp);
            fclose (tmp);
      }
      else
      {
            content = dv_get_data_content (prev->filename, 
                  GTK_WIDGET(widget));
            if (!content)
                  return;
            tmp = fopen (temp_file, "w");
            fwrite ((gchar*)content, strlen ((gchar*)content), 1, tmp);
            fclose (tmp);
      }
      g_clear_error (&gerr);
      if (!prev->use_term)
      {
            gchar * gui_cmd;

            if (!prev->viewer)
            {
                  g_set_error (&gerr, 1001, 1002, 
                        _("Could not find a suitable viewer "
                        "in the key file."));
                  dv_push_error (deb, gerr);
                  return;
            }
            gui_cmd = g_strconcat (prev->viewer, 
                  " ", temp_file, NULL);
            g_shell_parse_argv (gui_cmd, &argc, &argv, &gerr);
            if (gerr != NULL)
                  dv_push_error (deb, gerr);
            g_free (gui_cmd);
      }
      else
      {
            gchar * term_cmd;

            term_cmd = g_strconcat (terminal, " ", execute, 
                  " \"", prev->viewer, " ", temp_file, "\"", NULL);
            g_shell_parse_argv (term_cmd, &argc, &argv, &gerr);
            if (gerr != NULL)
                  dv_push_error (deb, gerr);
            g_free (term_cmd);
      }
      g_free (temp_file);
      g_spawn_async (NULL, argv, NULL, G_SPAWN_SEARCH_PATH,
            NULL, NULL, NULL, &gerr);
      if (gerr != NULL)
      {
            dv_push_error (deb, gerr);
            return;
      }
      return;
}

gboolean
dv_show_our_manpage (DVContents * deb)
{
      GError * gerr;
      gchar **argv;
      gchar * command, * file, * file_rev, *ourterm;
      gint argc;
      DVPreview * globbed;
      gssize len;

      gerr = NULL;
      globbed = NULL;
      ourterm = (g_strcasecmp ("", terminal))   ? terminal : DVDEFAULT;
      file = "./usr/share/man/man1/deb-gview.1.gz";
      len = g_utf8_strlen (file, 255);
      file_rev = g_utf8_strreverse (file, len);
      globbed = glob_key_pattern (file, len, file_rev);
      if (!globbed)
            command = g_strconcat (ourterm, " ", execute, " \"", 
                  DVMAN, " ", PACKAGE, "\"", NULL);
      else
            command = g_strconcat (ourterm, " ", execute, " \"", 
                  globbed->viewer, " ", PACKAGE, "\"", NULL);
      g_shell_parse_argv (command, &argc, &argv, &gerr);
      g_free (command);
      g_spawn_async (NULL, argv, NULL, G_SPAWN_SEARCH_PATH,
            NULL, NULL, NULL, &gerr);
      if (gerr != NULL)
      {
            dv_push_error (deb, gerr);
            return FALSE;
      }
      return TRUE;
}

Generated by  Doxygen 1.6.0   Back to index