Commit 071c0552 071c05523b657a805576f7bfc9562445b43afc20 by Sergey Poznyakoff

Added to the repository

1 parent 09617f83
## Process this file with GNU Automake to create Makefile.in
## Copyright (C) 2005 Free Software Foundation, Inc.
##
## 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 the Free Software Foundation; either version 2, 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. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/lib\
-I${top_builddir}/include/mailutils/gnu @INTLINCS@
AM_CFLAGS = -DSYSCONFDIR=\"$(sysconfdir)\"
bin_PROGRAMS = mimeview
mimeview_SOURCES = \
mimeview.c \
mimetypes-gram.c \
mimetypes-lex.c \
mimetypes-decl.h \
mimeview.h
YLWRAP = $(SHELL) $(top_srcdir)/scripts/ylwrap
AM_YFLAGS=-vt
AM_LEXFLAGS=-d
EXTRA_DIST = mimetypes.y mimetypes.l
mimetypes-gram.c mimetypes-decl.h: $(srcdir)/mimetypes.y
$(YLWRAP) "$(YACC) $(AM_YFLAGS) -d" $< \
y.tab.c mimetypes-gram.c y.tab.h mimetypes-decl.h \
y.output mimetypes.output \
-- -yy mimetypes_yy
mimetypes-lex.c: $(srcdir)/mimetypes.l mimetypes-decl.h
$(YLWRAP) "$(LEX) $(AM_LEXFLAGS) $(LEXFLAGS)" \
$(srcdir)/mimetypes.l lex.yy.c mimetypes-lex.c \
-- -yy mimetypes_yy
BUILT_SOURCES = mimetypes-gram.c mimetypes-lex.c mimetypes-decl.h
mimeview_LDADD = \
../mailbox/libmailbox.la\
../lib/libmailutils.la \
@LTLIBINTL@
%{
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 2005 Free Software Foundation, Inc.
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
the Free Software Foundation; either version 2, or (at your option)
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
along with GNU Mailutils; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <mimeview.h>
#include <mimetypes-decl.h>
#include <mu_asprintf.h>
#include <unistd.h>
#include <sys/stat.h>
static int line_num;
static const char *file_name;
static int file_name_alloc;
static struct obstack stack;
static int prev_state;
static unsigned
digit_to_number (char c)
{
return (unsigned) (c >= '0' && c <= '9' ? c-'0' :
c >= 'A' && c <= 'Z' ? c-'A'+10 :
c-'a'+10);
}
%}
%x ARGS HEX
X [0-9a-fA-F]
IDENT [a-zA-Z_\.][a-zA-Z0-9_\.-]*
WS [ \t]*
%%
/* Comments */
<INITIAL>#.*\n { line_num++; }
<INITIAL>#.* /* end-of-file comment */;
/* Tokens */
\\\n { line_num++; }
\n { line_num++; return EOL; }
{WS} ;
{IDENT} {
obstack_grow (&stack, yytext, yyleng);
yylval.string.len = obstack_object_size (&stack);
obstack_1grow (&stack, 0);
yylval.string.ptr = obstack_finish (&stack);
return IDENT;
}
<INITIAL>{IDENT}"(" {
obstack_grow (&stack, yytext, yyleng-1);
yylval.string.len = obstack_object_size (&stack);
obstack_1grow (&stack, 0);
yylval.string.ptr = obstack_finish (&stack);
BEGIN(ARGS);
return IDENT_L;
}
<INITIAL,ARGS>\"[^\\"\n]*\" {
obstack_grow (&stack, yytext+1, yyleng-2);
yylval.string.len = obstack_object_size (&stack);
obstack_1grow (&stack, 0);
yylval.string.ptr = obstack_finish (&stack);
return STRING;
}
<INITIAL,ARGS>"<" {
prev_state = YYSTATE;
BEGIN(HEX);
}
<ARGS>[^ \t<\\\n),]+/[),] {
obstack_grow (&stack, yytext, yyleng);
yylval.string.len = obstack_object_size (&stack);
obstack_1grow (&stack, 0);
yylval.string.ptr = obstack_finish (&stack);
return STRING;
}
<ARGS>[^ \t<\\\n),]+< {
obstack_grow (&stack, yytext, yyleng);
prev_state = YYSTATE;
BEGIN(HEX);
}
<INITIAL>[^ \t<\\\n)+&]/[ \t\\\n)+&] {
obstack_grow (&stack, yytext, yyleng);
yylval.string.len = obstack_object_size (&stack);
obstack_1grow (&stack, 0);
yylval.string.ptr = obstack_finish (&stack);
return STRING;
}
<ARGS>[^ \t<\\\n),]/[ \t\\\n] {
obstack_grow (&stack, yytext, yyleng);
yylval.string.len = obstack_object_size (&stack);
obstack_1grow (&stack, 0);
yylval.string.ptr = obstack_finish (&stack);
return STRING;
}
<HEX>{X}{X} {
int c = digit_to_number (yytext[0]*16 + yytext[1]);
obstack_1grow (&stack, c);
}
<HEX>">"/[ \t\\\n,)] {
BEGIN(prev_state);
yylval.string.len = obstack_object_size (&stack);
obstack_1grow (&stack, 0);
yylval.string.ptr = obstack_finish (&stack);
return STRING;
}
<HEX>">" {
BEGIN(prev_state);
}
/* Special cases: && and ||. Docs don't say anything about them, but
I've found them in my mime.types file... --Sergey */
"&&" return '+';
"||" return ',';
/* Operators */
"!"|"+"|"("|")"|"/" return yytext[0];
<ARGS>"," return yytext[0];
<ARGS>")" { BEGIN(INITIAL); return yytext[0]; }
<INITIAL,ARGS,HEX>. {
fprintf (stderr, "Invalid character '%c', state %d\n", yytext[0], YYSTATE);
abort();
}
%%
void
mimetypes_lex_debug (int level)
{
yy_flex_debug = level;
}
int
mimetypes_open (const char *name)
{
struct stat st;
if (stat (name, &st))
{
mu_error (_("Cannot stat `%s': %s"), name, mu_strerror (errno));
return -1;
}
if (S_ISDIR (st.st_mode))
{
asprintf (&file_name, "%s/mime.types", name);
file_name_alloc = 1;
}
else
{
file_name = name;
file_name_alloc = 0;
}
yyin = fopen (file_name, "r");
if (!yyin)
{
mu_error (_("Cannot open `%s': %s"), file_name, mu_strerror (errno));
if (file_name_alloc)
{
free (file_name);
file_name_alloc = 0;
}
return -1;
}
line_num = 1;
obstack_init (&stack);
return 0;
}
void
mimetypes_close ()
{
fclose (yyin);
if (file_name_alloc)
{
free (file_name);
file_name_alloc = 0;
}
}
int
yyerror (char *s)
{
mu_error ("%s:%lu: %s", file_name, line_num, s);
return 0;
}
int
yywrap ()
{
return 1;
}
struct mimetypes_string
mimetypes_append_string2 (struct mimetypes_string *s1,
char c,
struct mimetypes_string *s2)
{
struct mimetypes_string r;
r.len = s1->len + s2->len + 1;
obstack_grow (&stack, s1->ptr, s1->len);
obstack_1grow (&stack, c);
obstack_grow (&stack, s2->ptr, s2->len);
obstack_1grow (&stack, 0);
r.ptr = obstack_finish (&stack);
return r;
}
struct mimetypes_string *
mimetypes_string_dup (struct mimetypes_string *s)
{
obstack_grow (&stack, s, sizeof *s);
return obstack_finish (&stack);
}
void *
mimetypes_malloc (size_t size)
{
return obstack_alloc(&stack, size);
}
void
reset_lex ()
{
BEGIN(INITIAL);
}
%{
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 2005 Free Software Foundation, Inc.
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
the Free Software Foundation; either version 2, or (at your option)
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
along with GNU Mailutils; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <mimeview.h>
#include <mimetypes-decl.h>
static void
yyprint (FILE *output, unsigned short toknum, YYSTYPE val)
{
switch (toknum)
{
case IDENT:
case IDENT_L:
case STRING:
fprintf (output, "[%lu] %s", (unsigned long) val.string.len,
val.string.ptr);
break;
case EOL:
default:
break;
}
}
#define YYPRINT yyprint
static list_t arg_list; /* For error recovery */
#define L_OR 0
#define L_AND 1
enum node_type
{
functional_node,
binary_node,
negation_node,
suffix_node
};
union argument
{
struct mimetypes_string *string;
unsigned number;
int c;
};
typedef int (*builtin_t) (union argument *args);
struct node
{
enum node_type type;
union
{
struct
{
builtin_t fun;
union argument *args;
} function;
struct node *arg;
struct
{
int op;
struct node *arg1;
struct node *arg2;
} bin;
struct mimetypes_string suffix;
} v;
};
static struct node *make_binary_node (int op,
struct node *left, struct node *rigth);
static struct node *make_negation_node (struct node *p);
static struct node *make_suffix_node (struct mimetypes_string *suffix);
static struct node *make_functional_node (char *ident, list_t list);
static int eval_rule (struct node *root);
struct rule_tab
{
char *type;
struct node *node;
};
static list_t rule_list;
%}
%token <string> IDENT IDENT_L
%token <string> STRING
%token EOL BOGUS
%type <string> string arg type
%type <list> arglist
%type <node> function stmt rule
%union {
struct mimetypes_string string;
list_t list;
int result;
struct node *node;
}
%%
input : list
;
list : rule_line
| list eol rule_line
;
rule_line: /* empty */
| type rule
{
struct rule_tab *p = mimetypes_malloc (sizeof (*p));
if (!rule_list)
list_create (&rule_list);
p->type = $1.ptr;
p->node = $2;
list_append (rule_list, p);
}
| error eol
{
if (arg_list)
list_destroy (&arg_list);
arg_list = NULL;
reset_lex ();
}
;
eol : EOL
| eol EOL
;
type : IDENT '/' IDENT
{
$$ = mimetypes_append_string2 (&$1, '/', &$3);
}
;
rule : stmt
| rule stmt
{
$$ = make_binary_node (L_OR, $1, $2);
}
| rule ',' stmt
{
$$ = make_binary_node (L_OR, $1, $3);
}
| rule '+' stmt
{
$$ = make_binary_node (L_AND, $1, $3);
}
;
stmt : '!' stmt
{
$$ = make_negation_node ($2);
}
| '(' rule ')'
{
$$ = $2;
}
| string
{
$$ = make_suffix_node (&$1);
}
| function
;
string : STRING
| IDENT
;
function : IDENT_L arglist ')'
{
reset_lex ();
$$ = make_functional_node ($1.ptr, $2);
if (!$$)
YYERROR;
}
;
arglist : arg
{
list_create (&arg_list);
$$ = arg_list;
list_append ($$, mimetypes_string_dup (&$1));
}
| arglist ',' arg
{
list_append ($1, mimetypes_string_dup (&$3));
$$ = $1;
}
;
arg : string
;
%%
int
mimetypes_parse (const char *name)
{
int rc;
if (mimetypes_open (name))
return 1;
rc = yyparse ();
mimetypes_close ();
return rule_list == NULL;
}
void
mimetypes_gram_debug (int level)
{
yydebug = level;
}
static struct node *
make_node (enum node_type type)
{
struct node *p = mimetypes_malloc (sizeof *p);
p->type = type;
return p;
}
static struct node *
make_binary_node (int op, struct node *left, struct node *right)
{
struct node *node = make_node (binary_node);
node->v.bin.op = op;
node->v.bin.arg1 = left;
node->v.bin.arg2 = right;
return node;
}
struct node *
make_negation_node (struct node *p)
{
struct node *node = make_node (negation_node);
node->v.arg = p;
return node;
}
struct node *
make_suffix_node (struct mimetypes_string *suffix)
{
struct node *node = make_node (suffix_node);
node->v.suffix = *suffix;
return node;
}
struct builtin_tab
{
char *name;
char *args;
builtin_t handler;
};
/* match("pattern")
Pattern match on filename
*/
static int
b_match (union argument *args)
{
return fnmatch (args[0].string->ptr, mimeview_file, 0) == 0;
}
/* ascii(offset,length)
True if bytes are valid printable ASCII (CR, NL, TAB,
BS, 32-126)
*/
static int
b_ascii (union argument *args)
{
int i;
if (fseek (mimeview_fp, args[0].number, SEEK_SET) == -1)
{
mu_error ("fseek: %s", mu_strerror (errno));
return 0;
}
for (i = 0; i < args[1].number; i++)
{
int c = getc (mimeview_fp);
if (c == EOF)
break;
if (!isascii (c))
return 0;
}
return 1;
}
/* printable(offset,length)
True if bytes are printable 8-bit chars (CR, NL, TAB,
BS, 32-126, 128-254)
*/
#define ISPRINT(c) ((c) &&\
(strchr ("\n\r\t\b",c) \
|| (32<=(c) && (c)<=126) \
|| (128<=(c) && (c)<=254)))
static int
b_printable (union argument *args)
{
int i;
if (fseek (mimeview_fp, args[0].number, SEEK_SET) == -1)
{
mu_error ("fseek: %s", mu_strerror (errno));
return 0;
}
for (i = 0; i < args[1].number; i++)
{
int c = getc (mimeview_fp);
if (c == EOF)
break;
if (!ISPRINT ((unsigned)c))
return 0;
}
return 1;
}
/* string(offset,"string")
True if bytes are identical to string
*/
static int
b_string (union argument *args)
{
struct mimetypes_string *str = args[1].string;
int i;
if (fseek (mimeview_fp, args[0].number, SEEK_SET) == -1)
{
mu_error ("fseek: %s", mu_strerror (errno));
return 0;
}
for (i = 0; i < str->len; i++)
{
int c = getc (mimeview_fp);
if (c == EOF || c != str->ptr[i])
return 0;
}
return 1;
}
/* istring(offset,"string")
True if a case-insensitive comparison of the bytes is
identical
*/
static int
b_istring (union argument *args)
{
int i;
struct mimetypes_string *str = args[1].string;
if (fseek (mimeview_fp, args[0].number, SEEK_SET) == -1)
{
mu_error ("fseek: %s", mu_strerror (errno));
return 0;
}
for (i = 0; i < str->len; i++)
{
int c = getc (mimeview_fp);
if (c == EOF || tolower (c) != tolower (str->ptr[i]))
return 0;
}
return 1;
}
/* char(offset,value)
True if byte is identical
*/
static int
b_char (union argument *args)
{
if (fseek (mimeview_fp, args[0].number, SEEK_SET) == -1)
{
mu_error ("fseek: %s", mu_strerror (errno));
return 0;
}
return getc (mimeview_fp) == args[1].number;
}
/* short(offset,value)
True if 16-bit integer is identical
FIXME: Byte order
*/
static int
b_short (union argument *args)
{
unsigned short val;
int rc;
if (fseek (mimeview_fp, args[0].number, SEEK_SET) == -1)
{
mu_error ("fseek: %s", mu_strerror (errno));
return 0;
}
rc = fread (&val, sizeof val, 1, mimeview_fp);
if (rc == -1)
{
mu_error ("fread: %s", mu_strerror (errno));
return 0;
}
else if (rc == 0)
return 0;
return val == args[1].number;
}
/* int(offset,value)
True if 32-bit integer is identical
FIXME: Byte order
*/
static int
b_int (union argument *args)
{
unsigned int val;
int rc;
if (fseek (mimeview_fp, args[0].number, SEEK_SET) == -1)
{
mu_error ("fseek: %s", mu_strerror (errno));
return 0;
}
rc = fread (&val, sizeof val, 1, mimeview_fp);
if (rc == -1)
{
mu_error ("fread: %s", mu_strerror (errno));
return 0;
}
else if (rc == 0)
return 0;
return val == args[1].number;
}
/* locale("string")
True if current locale matches string
*/
static int
b_locale (union argument *args)
{
abort (); /* FIXME */
return 0;
}
/* contains(offset,range,"string")
True if the range contains the string
*/
static int
b_contains (union argument *args)
{
int i, count;
char *buf;
struct mimetypes_string *str = args[2].string;
if (fseek (mimeview_fp, args[0].number, SEEK_SET) == -1)
{
mu_error ("fseek: %s", mu_strerror (errno));
return 0;
}
buf = xmalloc (args[1].number);
count = fread (buf, 1, args[1].number, mimeview_fp);
if (count == -1)
{
mu_error ("fread: %s", mu_strerror (errno));
}
else if (count > str->len)
for (i = 0; i < count - str->len; i++)
if (buf[i] == str->ptr[0] && memcmp (buf + i, str->ptr, str->len) == 0)
{
free (buf);
return 1;
}
free (buf);
return 0;
}
static struct builtin_tab builtin_tab[] = {
{ "match", "s", b_match },
{ "ascii", "dd", b_ascii },
{ "printable", "dd", b_printable },
{ "string", "ds", b_string },
{ "istring", "ds", b_istring },
{ "char", "dc", b_char },
{ "short", "dd", b_short },
{ "int", "dd", b_int },
{ "locale", "s", b_locale },
{ "contains", "dds", b_contains },
{ NULL }
};
struct node *
make_functional_node (char *ident, list_t list)
{
size_t count, i;
struct builtin_tab *p;
struct node *node;
union argument *args;
iterator_t itr;
for (p = builtin_tab; ; p++)
{
if (!p->name)
{
char *s;
asprintf (&s, _("%s: unknown function"), ident);
yyerror (s);
free (s);
return NULL;
}
if (strcmp (ident, p->name) == 0)
break;
}
list_count (list, &count);
i = strlen (p->args);
if (count < i)
{
char *s;
asprintf (&s, _("too few arguments in call to `%s'"), ident);
yyerror (s);
free (s);
return NULL;
}
else if (count > i)
{
char *s;
asprintf (&s, _("too many arguments in call to `%s'"), ident);
yyerror (s);
free (s);
return NULL;
}
args = mimetypes_malloc (count * sizeof *args);
list_get_iterator (list, &itr);
for (i = 0, iterator_first (itr); !iterator_is_done (itr);
iterator_next (itr), i++)
{
struct mimetypes_string *data;
char *tmp;
iterator_current (itr, (void **)&data);
switch (p->args[i])
{
case 'd':
args[i].number = strtoul (data->ptr, &tmp, 0);
if (*tmp)
goto err;
break;
case 's':
args[i].string = data;
break;
case 'c':
args[i].c = strtoul (data->ptr, &tmp, 0);
if (*tmp)
goto err;
break;
default:
abort ();
}
}
node = make_node (functional_node);
node->v.function.fun = p->handler;
node->v.function.args = args;
return node;
err:
{
char *s;
asprintf (&s,
_("argument %d has wrong type in call to `%s'"),
i, ident);
yyerror (s);
free (s);
return NULL;
}
}
static int
check_suffix (char *suf)
{
char *p = strrchr (mimeview_file, '.');
if (!p)
return 0;
return strcmp (p+1, suf) == 0;
}
static int
eval_rule (struct node *root)
{
int result;
switch (root->type)
{
case functional_node:
result = root->v.function.fun (root->v.function.args);
break;
case binary_node:
result = eval_rule (root->v.bin.arg1);
switch (root->v.bin.op)
{
case L_OR:
if (!result)
result |= eval_rule (root->v.bin.arg2);
break;
case L_AND:
if (result)
result &= eval_rule (root->v.bin.arg2);
break;
default:
abort ();
}
break;
case negation_node:
result = !eval_rule (root->v.arg);
break;
case suffix_node:
result = check_suffix (root->v.suffix.ptr);
break;
default:
abort ();
}
return result;
}
static int
evaluate (void *item, void *data)
{
struct rule_tab *p = item;
char **ptype = data;
if (eval_rule (p->node))
{
*ptype = p->type;
return 1;
}
return 0;
}
const char *
get_file_type ()
{
const char *type = NULL;
list_do (rule_list, evaluate, &type);
return type;
}
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 2005 Free Software Foundation, Inc.
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
the Free Software Foundation; either version 2, or (at your option)
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
along with GNU Mailutils; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <mimeview.h>
#include <sys/stat.h>
const char *program_version = "mimeview (" PACKAGE_STRING ")";
static char doc[] = N_("GNU mimeview -- display MIME files \
Default mime.types file is ") SYSCONFDIR "/cups/mime.types"
N_("\nDebug flags are:\n\
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[] = {
{"debug", 'd', N_("FLAGS"), OPTION_ARG_OPTIONAL,
N_("Enable debugging output"), 0},
{"mimetypes", 't', N_("FILE"), 0,
N_("Use this mime.types file"), 0},
{"dry-run", 'n', NULL, 0,
N_("Do not do anything, just print what whould be done"), 0},
{"metamail", OPT_METAMAIL, N_("FILE"), OPTION_ARG_OPTIONAL,
N_("Use metamail to display files"), 0},
{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 */
static char *mimetypes_config = SYSCONFDIR "/cups";
char *mimeview_file; /* Name of the file to view */
FILE *mimeview_fp; /* Its descriptor */
/* Default mailcap path, the $HOME/.mailcap: entry is prepended to it */
#define DEFAULT_MAILCAP \
"/usr/local/etc/mailcap:"\
"/usr/etc/mailcap:"\
"/etc/mailcap:"\
"/etc/mail/mailcap:"\
"/usr/public/lib/mailcap"
static error_t
parse_opt (int key, char *arg, struct argp_state *state)
{
switch (key)
{
case ARGP_KEY_INIT:
mimetypes_lex_debug (0);
mimetypes_gram_debug (0);
break;
case ARGP_KEY_FINI:
if (dry_run && !debug_level)
debug_level = 1;
break;
case 'd':
if (!arg)
arg = "9";
for (; *arg; arg++)
{
switch (*arg)
{
case 'l':
mimetypes_lex_debug (1);
break;
case 'g':
mimetypes_gram_debug (1);
break;
default:
debug_level = *arg - '0';
}
}
break;
case 'n':
dry_run = 1;
break;
case 't':
mimetypes_config = arg;
break;
case OPT_METAMAIL:
metamail = arg ? arg : "metamail";
break;
default:
return ARGP_ERR_UNKNOWN;
}
return 0;
}
static struct argp argp = {
options,
parse_opt,
N_("FILE [FILE ...]"),
doc,
NULL,
NULL, NULL
};
static const char *capa[] = {
"common",
"license",
NULL
};
static int
open_file (char *name)
{
struct stat st;
if (stat (name, &st))
{
mu_error (_("Cannot stat `%s': %s"), name, mu_strerror (errno));
return -1;
}
if (!S_ISREG (st.st_mode) && !S_ISLNK (st.st_mode))
{
mu_error (_("Not a regular file or symbolic link: `%s'"), name);
return -1;
}
mimeview_file = name;
mimeview_fp = fopen (name, "r");
if (mimeview_fp == NULL)
{
mu_error (_("Cannot open `%s': %s"), name, mu_strerror (errno));
return -1;
}
return 0;
}
void
close_file ()
{
fclose (mimeview_fp);
}
static struct obstack expand_stack;
static void
expand_string (char **pstr, const char *filename, const char *type)
{
char *p;
size_t namelen = strlen (filename);
size_t typelen = strlen (type);
for (p = *pstr; *p; )
{
switch (p[0])
{
case '%':
switch (p[1])
{
case 's':
obstack_grow (&expand_stack, filename, namelen);
p += 2;
break;
case 't':
obstack_grow (&expand_stack, type, typelen);
p += 2;
break;
case '{':
/* Hmm, we don't have content-type field, sorry... */
while (*p && *p != '}')
p++;
if (*p)
p++;
break;
/* FIXME: Handle %F and %n */
default:
obstack_1grow (&expand_stack, p[0]);
}
break;
case '\\':
if (p[1])
{
obstack_1grow (&expand_stack, p[1]);
p += 2;
}
else
{
obstack_1grow (&expand_stack, p[0]);
p++;
}
break;
case '"':
if (p[1] == p[0])
{
obstack_1grow (&expand_stack, '%');
p++;
}
else
{
obstack_1grow (&expand_stack, p[0]);
p++;
}
break;
default:
obstack_1grow (&expand_stack, p[0]);
p++;
}
}
obstack_1grow (&expand_stack, 0);
free (*pstr);
*pstr = obstack_finish (&expand_stack);
}
static int
find_entry (const char *file, const char *type,
mu_mailcap_entry_t *pentry,
mu_mailcap_t *pmc)
{
mu_mailcap_t mailcap;
int status;
stream_t stream;
DEBUG (2, (_("Trying %s...\n"), file));
status = file_stream_create (&stream, file, MU_STREAM_READ);
if (status)
{
mu_error ("cannot create file stream %s: %s",
file, mu_strerror (status));
return 0;
}
status = stream_open (stream);
if (status)
{
stream_destroy (&stream, stream_get_owner (stream));
if (status != ENOENT)
mu_error ("cannot open file stream %s: %s",
file, mu_strerror (status));
return 0;
}
status = mu_mailcap_create (&mailcap, stream);
if (status == 0)
{
size_t i, count = 0;
mu_mailcap_entries_count (mailcap, &count);
for (i = 1; i <= count; i++)
{
mu_mailcap_entry_t entry;
char buffer[256];
if (mu_mailcap_get_entry (mailcap, i, &entry))
continue;
/* typefield. */
mu_mailcap_entry_get_typefield (entry,
buffer, sizeof (buffer), NULL);
if (fnmatch (buffer, type, FNM_CASEFOLD) == 0)
{
DEBUG (2, (_("Found in %s\n"), file));
/* FIXME: Run test entry, if any */
*pmc = mailcap;
*pentry = entry;
return 1; /* We leave stream open! */
}
}
mu_mailcap_destroy (&mailcap);
}
else
{
mu_error ("cannot create mailcap for %s: %s",
file, mu_strerror (status));
}
return 0;
}
static void
dump_mailcap_entry (mu_mailcap_entry_t entry)
{
char buffer[256];
size_t i, count;
mu_mailcap_entry_get_typefield (entry, buffer,
sizeof (buffer), NULL);
printf ("typefield: %s\n", buffer);
/* view-command. */
mu_mailcap_entry_get_viewcommand (entry, buffer,
sizeof (buffer), NULL);
printf ("view-command: %s\n", buffer);
/* fields. */
mu_mailcap_entry_fields_count (entry, &count);
for (i = 1; i <= count; i++)
{
int status = mu_mailcap_entry_get_field (entry, i, buffer,
sizeof (buffer), NULL);
if (status)
{
mu_error (_("cannot retrieve field %lu: %s"),
(unsigned long) i,
mu_strerror (status));
break;
}
printf ("fields[%d]: %s\n", i, buffer);
}
printf ("\n");
}
int
run_mailcap (mu_mailcap_entry_t entry, const char *type)
{
char *view_command;
size_t size;
int flag;
int status;
int argc;
char **argv;
/* pid_t pager = -1; */
if (debug_level > 1)
dump_mailcap_entry (entry);
mu_mailcap_entry_get_viewcommand (entry, NULL, 0, &size);
size++;
view_command = xmalloc (size);
mu_mailcap_entry_get_viewcommand (entry, view_command, size, NULL);
/* NOTE: We don't create temporary file for %s, we just use
mimeview_file instead */
expand_string (&view_command, mimeview_file, type);
DEBUG (0, (_("Executing %s...\n"), view_command));
if (dry_run)
return 0;
status = argcv_get (view_command, "", NULL, &argc, &argv);
free (view_command);
if (status)
{
mu_error (_("Cannot parse command line: %s"), mu_strerror (status));
return 1;
}
/*
if (mu_mailcap_entry_coupiousoutput (entry, &flag) == 0 && flag)
pager = open_pager ();
*/
if (pager <= 0)
{
if (mu_spawnvp (argv[0], argv, &status))
mu_error (_("Cannot execute command: %s"), mu_strerror (status));
if (debug_level)
{
if (WIFEXITED (status))
printf (_("Command exited with status %d\n"), WEXITSTATUS(status));
else if (WIFSIGNALED (status))
printf(_("Command terminated on signal %d\n"), WTERMSIG(status));
else
printf (_("Command terminated"));
}
}
argcv_free (argc, argv);
/* close_pager (pager); */
}
void
display_file_mailcap (const char *type)
{
char *p, *sp;
char *mailcap_path;
mu_mailcap_t mailcap = NULL;
mu_mailcap_entry_t entry = NULL;
mailcap_path = getenv ("MAILCAP");
if (!mailcap_path)
{
char *home = mu_get_homedir ();
asprintf (&mailcap_path, "%s/.mailcap:%s", home, DEFAULT_MAILCAP);
}
else
mailcap_path = strdup (mailcap_path);
obstack_init (&expand_stack);
for (p = strtok_r (mailcap_path, ":", &sp); p; p = strtok_r (NULL, ":", &sp))
{
if (find_entry (p, type, &entry, &mailcap))
{
run_mailcap (entry, type);
mu_mailcap_destroy (&mailcap);
break;
}
}
}
void
display_file (const char *type)
{
if (metamail)
{
int status;
const char *argv[6];
argv[0] = "metamail";
argv[1] = "-b";
argv[2] = "-c";
argv[3] = type;
argv[4] = mimeview_file;
argv[5] = NULL;
if (debug_level)
{
char *string;
argcv_string (5, argv, &string);
printf (_("Executing %s...\n"), string);
free (string);
}
if (!dry_run)
mu_spawnvp (metamail, argv, &status);
}
else
display_file_mailcap (type);
}
int
main (int argc, char **argv)
{
int index;
mu_init_nls ();
mu_argp_init (program_version, NULL);
mu_argp_parse (&argp, &argc, &argv, 0, capa, &index, NULL);
argc -= index;
argv += index;
if (argc == 0)
{
mu_error (_("No files given"));
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;
}
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 2005 Free Software Foundation, Inc.
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
the Free Software Foundation; either version 2, or (at your option)
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
along with GNU Mailutils; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#ifdef HAVE_STRINGS_H
# include <strings.h>
#endif
#include <mailutils/mailutils.h>
#include <xalloc.h>
#include <fnmatch.h>
#define obstack_chunk_alloc malloc
#define obstack_chunk_free free
#include <obstack.h>
struct mimetypes_string
{
char *ptr;
size_t len;
};
int mimetypes_yylex (void);
int mimetypes_yyerror (char *s);
int mimetypes_open (const char *name);
void mimetypes_close (void);
int mimetypes_parse (const char *name);
void mimetypes_gram_debug (int level);
void mimetypes_lex_debug (int level);
void mimetypes_lex_init (void);
void reset_lex (void);
void *mimetypes_malloc (size_t size);
struct mimetypes_string mimetypes_append_string2 (struct mimetypes_string *s1,
char c,
struct mimetypes_string *s2);
struct mimetypes_string *mimetypes_string_dup (struct mimetypes_string *s);
const char *get_file_type (void);
extern char *mimeview_file;
extern FILE *mimeview_fp;
extern int debug_level;
#define DEBUG(l,f) if (debug_level > (l)) printf f