Blame view

mimeview/mimeview.c 6.85 KB
1
/* GNU Mailutils -- a suite of utilities for electronic mail
2 3
   Copyright (C) 2005, 2007, 2008, 2009, 2010 Free Software Foundation,
   Inc.
4 5 6

   GNU Mailutils is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
7
   the Free Software Foundation; either version 3, or (at your option)
8 9 10 11 12 13 14 15
   any later version.

   GNU Mailutils 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
16
   along with GNU Mailutils.  If not, see <http://www.gnu.org/licenses/>. */
17 18 19 20 21 22

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif

#include <mimeview.h>
23
#include <sys/types.h>
24
#include <sys/stat.h>
25
#include <sys/wait.h>
26 27
#include <unistd.h>
#include <fcntl.h>
28

29
#include "mailutils/libargp.h"
30 31 32
#include "mailutils/argcv.h"

#include "mailcap.h"
33

34 35 36
static char doc[] = N_("GNU mimeview -- display files, using mailcap mechanism.")
"\v"     
N_("Default mime.types file is ") DEFAULT_CUPS_CONFDIR "/mime.types"
37
N_("\n\nDebug flags are:\n\
38 39 40 41 42 43 44
  g - Mime.types parser traces\n\
  l - Mime.types lexical analyzer traces\n\
  0-9 - Set debugging level\n");

#define OPT_METAMAIL 256

static struct argp_option options[] = {
45
  {"no-ask", 'a', N_("TYPE-LIST"), OPTION_ARG_OPTIONAL,
Sergey Poznyakoff authored
46
   N_("do not ask for confirmation before displaying files, or, if TYPE-LIST is given, do not ask for confirmation before displaying such files whose MIME type matches one of the patterns from TYPE-LIST"), 0},
47
  {"no-interactive", 'h', NULL, 0,
Sergey Poznyakoff authored
48
   N_("disable interactive mode"), 0 },
49
  {"print", 0, NULL, OPTION_ALIAS, NULL, 0 },
50
  {"debug",  'd', N_("FLAGS"),  OPTION_ARG_OPTIONAL,
Sergey Poznyakoff authored
51
   N_("enable debugging output"), 0},
52
  {"mimetypes", 't', N_("FILE"), 0,
Sergey Poznyakoff authored
53
   N_("use this mime.types file"), 0},
54
  {"dry-run", 'n', NULL, 0,
Sergey Poznyakoff authored
55
   N_("do not do anything, just print what whould be done"), 0},
56
  {"metamail", OPT_METAMAIL, N_("FILE"), OPTION_ARG_OPTIONAL,
Sergey Poznyakoff authored
57
   N_("use metamail to display files"), 0},
58 59 60 61 62 63
  {0, 0, 0, 0}
};

int debug_level;       /* Debugging level set by --debug option */
static int dry_run;    /* Dry run mode */
static char *metamail; /* Name of metamail program, if requested */
64
static char *mimetypes_config = DEFAULT_CUPS_CONFDIR;
65
static char *no_ask_types;  /* List of MIME types for which no questions
66 67
			       should be asked */
static int interactive = -1; 
68
char *mimeview_file;       /* Name of the file to view */
69
mu_stream_t mimeview_stream;    /* The corresponding stream */
70

71
static void
72
set_debug_flags (const char *arg)
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
{
  for (; *arg; arg++)
    {
      switch (*arg)
	{
	case 'l':
	  mimetypes_lex_debug (1);
	  break;

	case 'g':
	  mimetypes_gram_debug (1);
	  break;
	  
	default:
	  debug_level = *arg - '0';
	}
    }
}  

92 93 94
static error_t
parse_opt (int key, char *arg, struct argp_state *state)
{
95
  static mu_list_t lst;
96

97 98 99 100 101
  switch (key)
    {
    case ARGP_KEY_INIT:
      mimetypes_lex_debug (0);
      mimetypes_gram_debug (0);
102 103
      if (interactive == -1)
	interactive = isatty (fileno (stdin));
104
      mu_argp_node_list_init (&lst);
105 106 107 108 109
      break;

    case ARGP_KEY_FINI:
      if (dry_run && !debug_level)
	debug_level = 1;
110
      mu_argp_node_list_finish (lst, NULL, NULL);
111
      break;
112 113

    case 'a':
114
      no_ask_types = arg ? arg : "*";
115 116
      setenv ("MM_NOASK", arg, 1); /* In case we are given --metamail option */
      break;
117 118
      
    case 'd':
119
      mu_argp_node_list_new (lst, "debug", arg ? arg : "9");
120 121
      break;

122 123 124 125
    case 'h':
      interactive = 0;
      break;
      
126 127 128 129 130
    case 'n':
      dry_run = 1;
      break;
      
    case 't':
131
      mu_argp_node_list_new (lst, "mimetypes", arg);
132 133 134
      break;

    case OPT_METAMAIL:
135
      mu_argp_node_list_new (lst, "metamail", arg ? arg : "metamail");
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
      break;
      
    default: 
      return ARGP_ERR_UNKNOWN;
    }
  return 0;
}

static struct argp argp = {
  options,
  parse_opt,
  N_("FILE [FILE ...]"),
  doc,
  NULL,
  NULL, NULL
};

153 154

static int
155
cb_debug (void *data, mu_config_value_t *val)
156
{
157
  if (mu_cfg_assert_value_type (val, MU_CFG_STRING))
158
    return 1;
159
  set_debug_flags (val->v.string);
160 161 162
  return 0;
}

163
struct mu_cfg_param mimeview_cfg_param[] = {
164
  { "debug", mu_cfg_callback, NULL, 0, cb_debug,
165 166
    N_("Set debug verbosity level."),
    N_("flags") },
167
  { "mimetypes", mu_cfg_string, &mimetypes_config, 0, NULL,
168 169
    N_("Use this mime.types file."),
    N_("file") },
170
  { "metamail", mu_cfg_string, &metamail, 0, NULL,
171 172
    N_("Use this program to display files."),
    N_("prog") },
173 174 175 176 177
  { NULL }
};



178 179
static const char *capa[] = {
  "common",
180
  "debug",
181 182 183 184 185 186
  NULL
};

static int
open_file (char *name)
{
187
  int rc;
188
  struct stat st;
189
  
190 191
  if (stat (name, &st))
    {
192
      mu_error (_("cannot stat `%s': %s"), name, mu_strerror (errno));
193 194 195 196
      return -1;
    }
  if (!S_ISREG (st.st_mode) && !S_ISLNK (st.st_mode))
    {
197
      mu_error (_("not a regular file or symbolic link: `%s'"), name);
198 199 200 201
      return -1;
    }

  mimeview_file = name;
202 203
  rc = mu_file_stream_create (&mimeview_stream, mimeview_file, MU_STREAM_READ);
  if (rc)
204
    {
205
      mu_error (_("Cannot open `%s': %s"), name, mu_strerror (rc));
206 207 208 209 210 211 212 213
      return -1;
    }
  return 0;
}

void
close_file ()
{
214
  mu_stream_close (mimeview_stream);
215 216
}

217
void
218
display_file (const char *type)
219 220
{
  int status;
221 222 223
  
  if (metamail)
    {
224
      char *argv[7];
225
      
226 227
      argv[0] = "metamail";
      argv[1] = "-b";
228 229 230 231

      argv[2] = interactive ? "-p" : "-h";
      
      argv[3] = "-c";
232
      argv[4] = (char*) type;
233 234
      argv[5] = mimeview_file;
      argv[6] = NULL;
235 236 237 238
      
      if (debug_level)
	{
	  char *string;
239
	  mu_argcv_string (6, argv, &string);
240 241 242 243 244
	  printf (_("Executing %s...\n"), string);
	  free (string);
	}
      
      if (!dry_run)
245
	mu_spawnvp (metamail, argv, &status);
246 247
    }
  else
248
    {
249
      mu_header_t hdr;
250 251
      char *text;

252
      mu_asprintf (&text, "Content-Type: %s\n", type);
253
      status = mu_header_create (&hdr, text, strlen (text));
254
      if (status)
255
	mu_error (_("cannot create header: %s"), mu_strerror (status));
256 257
      else
	{
258
	  display_stream_mailcap (mimeview_file, mimeview_stream, hdr,
259 260
				  no_ask_types, interactive, dry_run,
				  debug_level);
261
	  mu_header_destroy (&hdr);
262 263
	}
    }
264 265 266 267 268 269 270
}

int
main (int argc, char **argv)
{
  int index;
  
Sergey Poznyakoff authored
271
  MU_APP_INIT_NLS ();
272
  mu_argp_init (NULL, NULL);
273 274 275
  if (mu_app_init (&argp, capa, mimeview_cfg_param, 
		   argc, argv, 0, &index, NULL))
    exit (1);
276 277 278 279 280 281

  argc -= index;
  argv += index;

  if (argc == 0)
    {
282
      mu_error (_("no files given"));
283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303
      return 1;
    }

  if (mimetypes_parse (mimetypes_config))
    return 1;
  
  while (argc--)
    {
      const char *type;
      
      if (open_file (*argv++))
	continue;
      type = get_file_type ();
      DEBUG (1, ("%s: %s\n", mimeview_file, type ? type : "?"));
      if (type)
	display_file (type);
      close_file ();
    }
  
  return 0;
}