Added to the repository
Showing
5 changed files
with
1532 additions
and
0 deletions
mimeview/Makefile.am
0 → 100644
1 | ## Process this file with GNU Automake to create Makefile.in | ||
2 | |||
3 | ## Copyright (C) 2005 Free Software Foundation, Inc. | ||
4 | ## | ||
5 | ## GNU Mailutils is free software; you can redistribute it and/or | ||
6 | ## modify it under the terms of the GNU General Public License as | ||
7 | ## published by the Free Software Foundation; either version 2, or (at | ||
8 | ## your option) any later version. | ||
9 | ## | ||
10 | ## This program 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. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | |||
19 | INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/lib\ | ||
20 | -I${top_builddir}/include/mailutils/gnu @INTLINCS@ | ||
21 | |||
22 | AM_CFLAGS = -DSYSCONFDIR=\"$(sysconfdir)\" | ||
23 | |||
24 | bin_PROGRAMS = mimeview | ||
25 | mimeview_SOURCES = \ | ||
26 | mimeview.c \ | ||
27 | mimetypes-gram.c \ | ||
28 | mimetypes-lex.c \ | ||
29 | mimetypes-decl.h \ | ||
30 | mimeview.h | ||
31 | |||
32 | YLWRAP = $(SHELL) $(top_srcdir)/scripts/ylwrap | ||
33 | AM_YFLAGS=-vt | ||
34 | AM_LEXFLAGS=-d | ||
35 | EXTRA_DIST = mimetypes.y mimetypes.l | ||
36 | |||
37 | mimetypes-gram.c mimetypes-decl.h: $(srcdir)/mimetypes.y | ||
38 | $(YLWRAP) "$(YACC) $(AM_YFLAGS) -d" $< \ | ||
39 | y.tab.c mimetypes-gram.c y.tab.h mimetypes-decl.h \ | ||
40 | y.output mimetypes.output \ | ||
41 | -- -yy mimetypes_yy | ||
42 | |||
43 | mimetypes-lex.c: $(srcdir)/mimetypes.l mimetypes-decl.h | ||
44 | $(YLWRAP) "$(LEX) $(AM_LEXFLAGS) $(LEXFLAGS)" \ | ||
45 | $(srcdir)/mimetypes.l lex.yy.c mimetypes-lex.c \ | ||
46 | -- -yy mimetypes_yy | ||
47 | |||
48 | BUILT_SOURCES = mimetypes-gram.c mimetypes-lex.c mimetypes-decl.h | ||
49 | |||
50 | mimeview_LDADD = \ | ||
51 | ../mailbox/libmailbox.la\ | ||
52 | ../lib/libmailutils.la \ | ||
53 | @LTLIBINTL@ | ||
54 |
mimeview/mimetypes.l
0 → 100644
1 | %{ | ||
2 | /* GNU Mailutils -- a suite of utilities for electronic mail | ||
3 | Copyright (C) 2005 Free Software Foundation, Inc. | ||
4 | |||
5 | GNU Mailutils is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published by | ||
7 | the Free Software Foundation; either version 2, or (at your option) | ||
8 | any later version. | ||
9 | |||
10 | GNU Mailutils is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | GNU General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with GNU Mailutils; if not, write to the Free Software | ||
17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ | ||
18 | |||
19 | #ifdef HAVE_CONFIG_H | ||
20 | # include <config.h> | ||
21 | #endif | ||
22 | |||
23 | #include <mimeview.h> | ||
24 | #include <mimetypes-decl.h> | ||
25 | #include <mu_asprintf.h> | ||
26 | #include <unistd.h> | ||
27 | #include <sys/stat.h> | ||
28 | |||
29 | static int line_num; | ||
30 | static const char *file_name; | ||
31 | static int file_name_alloc; | ||
32 | |||
33 | static struct obstack stack; | ||
34 | static int prev_state; | ||
35 | |||
36 | static unsigned | ||
37 | digit_to_number (char c) | ||
38 | { | ||
39 | return (unsigned) (c >= '0' && c <= '9' ? c-'0' : | ||
40 | c >= 'A' && c <= 'Z' ? c-'A'+10 : | ||
41 | c-'a'+10); | ||
42 | } | ||
43 | %} | ||
44 | %x ARGS HEX | ||
45 | X [0-9a-fA-F] | ||
46 | IDENT [a-zA-Z_\.][a-zA-Z0-9_\.-]* | ||
47 | WS [ \t]* | ||
48 | %% | ||
49 | /* Comments */ | ||
50 | <INITIAL>#.*\n { line_num++; } | ||
51 | <INITIAL>#.* /* end-of-file comment */; | ||
52 | /* Tokens */ | ||
53 | \\\n { line_num++; } | ||
54 | \n { line_num++; return EOL; } | ||
55 | {WS} ; | ||
56 | {IDENT} { | ||
57 | obstack_grow (&stack, yytext, yyleng); | ||
58 | yylval.string.len = obstack_object_size (&stack); | ||
59 | obstack_1grow (&stack, 0); | ||
60 | yylval.string.ptr = obstack_finish (&stack); | ||
61 | return IDENT; | ||
62 | } | ||
63 | <INITIAL>{IDENT}"(" { | ||
64 | obstack_grow (&stack, yytext, yyleng-1); | ||
65 | yylval.string.len = obstack_object_size (&stack); | ||
66 | obstack_1grow (&stack, 0); | ||
67 | yylval.string.ptr = obstack_finish (&stack); | ||
68 | BEGIN(ARGS); | ||
69 | return IDENT_L; | ||
70 | } | ||
71 | <INITIAL,ARGS>\"[^\\"\n]*\" { | ||
72 | obstack_grow (&stack, yytext+1, yyleng-2); | ||
73 | yylval.string.len = obstack_object_size (&stack); | ||
74 | obstack_1grow (&stack, 0); | ||
75 | yylval.string.ptr = obstack_finish (&stack); | ||
76 | return STRING; | ||
77 | } | ||
78 | <INITIAL,ARGS>"<" { | ||
79 | prev_state = YYSTATE; | ||
80 | BEGIN(HEX); | ||
81 | } | ||
82 | <ARGS>[^ \t<\\\n),]+/[),] { | ||
83 | obstack_grow (&stack, yytext, yyleng); | ||
84 | yylval.string.len = obstack_object_size (&stack); | ||
85 | obstack_1grow (&stack, 0); | ||
86 | yylval.string.ptr = obstack_finish (&stack); | ||
87 | return STRING; | ||
88 | } | ||
89 | <ARGS>[^ \t<\\\n),]+< { | ||
90 | obstack_grow (&stack, yytext, yyleng); | ||
91 | prev_state = YYSTATE; | ||
92 | BEGIN(HEX); | ||
93 | } | ||
94 | <INITIAL>[^ \t<\\\n)+&]/[ \t\\\n)+&] { | ||
95 | obstack_grow (&stack, yytext, yyleng); | ||
96 | yylval.string.len = obstack_object_size (&stack); | ||
97 | obstack_1grow (&stack, 0); | ||
98 | yylval.string.ptr = obstack_finish (&stack); | ||
99 | return STRING; | ||
100 | } | ||
101 | <ARGS>[^ \t<\\\n),]/[ \t\\\n] { | ||
102 | obstack_grow (&stack, yytext, yyleng); | ||
103 | yylval.string.len = obstack_object_size (&stack); | ||
104 | obstack_1grow (&stack, 0); | ||
105 | yylval.string.ptr = obstack_finish (&stack); | ||
106 | return STRING; | ||
107 | } | ||
108 | <HEX>{X}{X} { | ||
109 | int c = digit_to_number (yytext[0]*16 + yytext[1]); | ||
110 | obstack_1grow (&stack, c); | ||
111 | } | ||
112 | <HEX>">"/[ \t\\\n,)] { | ||
113 | BEGIN(prev_state); | ||
114 | yylval.string.len = obstack_object_size (&stack); | ||
115 | obstack_1grow (&stack, 0); | ||
116 | yylval.string.ptr = obstack_finish (&stack); | ||
117 | return STRING; | ||
118 | } | ||
119 | <HEX>">" { | ||
120 | BEGIN(prev_state); | ||
121 | } | ||
122 | /* Special cases: && and ||. Docs don't say anything about them, but | ||
123 | I've found them in my mime.types file... --Sergey */ | ||
124 | "&&" return '+'; | ||
125 | "||" return ','; | ||
126 | /* Operators */ | ||
127 | "!"|"+"|"("|")"|"/" return yytext[0]; | ||
128 | <ARGS>"," return yytext[0]; | ||
129 | <ARGS>")" { BEGIN(INITIAL); return yytext[0]; } | ||
130 | <INITIAL,ARGS,HEX>. { | ||
131 | fprintf (stderr, "Invalid character '%c', state %d\n", yytext[0], YYSTATE); | ||
132 | abort(); | ||
133 | } | ||
134 | %% | ||
135 | |||
136 | void | ||
137 | mimetypes_lex_debug (int level) | ||
138 | { | ||
139 | yy_flex_debug = level; | ||
140 | } | ||
141 | |||
142 | int | ||
143 | mimetypes_open (const char *name) | ||
144 | { | ||
145 | struct stat st; | ||
146 | if (stat (name, &st)) | ||
147 | { | ||
148 | mu_error (_("Cannot stat `%s': %s"), name, mu_strerror (errno)); | ||
149 | return -1; | ||
150 | } | ||
151 | |||
152 | if (S_ISDIR (st.st_mode)) | ||
153 | { | ||
154 | asprintf (&file_name, "%s/mime.types", name); | ||
155 | file_name_alloc = 1; | ||
156 | } | ||
157 | else | ||
158 | { | ||
159 | file_name = name; | ||
160 | file_name_alloc = 0; | ||
161 | } | ||
162 | |||
163 | yyin = fopen (file_name, "r"); | ||
164 | if (!yyin) | ||
165 | { | ||
166 | mu_error (_("Cannot open `%s': %s"), file_name, mu_strerror (errno)); | ||
167 | if (file_name_alloc) | ||
168 | { | ||
169 | free (file_name); | ||
170 | file_name_alloc = 0; | ||
171 | } | ||
172 | return -1; | ||
173 | } | ||
174 | line_num = 1; | ||
175 | obstack_init (&stack); | ||
176 | return 0; | ||
177 | } | ||
178 | |||
179 | void | ||
180 | mimetypes_close () | ||
181 | { | ||
182 | fclose (yyin); | ||
183 | if (file_name_alloc) | ||
184 | { | ||
185 | free (file_name); | ||
186 | file_name_alloc = 0; | ||
187 | } | ||
188 | } | ||
189 | |||
190 | int | ||
191 | yyerror (char *s) | ||
192 | { | ||
193 | mu_error ("%s:%lu: %s", file_name, line_num, s); | ||
194 | return 0; | ||
195 | } | ||
196 | |||
197 | int | ||
198 | yywrap () | ||
199 | { | ||
200 | return 1; | ||
201 | } | ||
202 | |||
203 | struct mimetypes_string | ||
204 | mimetypes_append_string2 (struct mimetypes_string *s1, | ||
205 | char c, | ||
206 | struct mimetypes_string *s2) | ||
207 | { | ||
208 | struct mimetypes_string r; | ||
209 | |||
210 | r.len = s1->len + s2->len + 1; | ||
211 | obstack_grow (&stack, s1->ptr, s1->len); | ||
212 | obstack_1grow (&stack, c); | ||
213 | obstack_grow (&stack, s2->ptr, s2->len); | ||
214 | obstack_1grow (&stack, 0); | ||
215 | r.ptr = obstack_finish (&stack); | ||
216 | return r; | ||
217 | } | ||
218 | |||
219 | struct mimetypes_string * | ||
220 | mimetypes_string_dup (struct mimetypes_string *s) | ||
221 | { | ||
222 | obstack_grow (&stack, s, sizeof *s); | ||
223 | return obstack_finish (&stack); | ||
224 | } | ||
225 | |||
226 | void * | ||
227 | mimetypes_malloc (size_t size) | ||
228 | { | ||
229 | return obstack_alloc(&stack, size); | ||
230 | } | ||
231 | |||
232 | void | ||
233 | reset_lex () | ||
234 | { | ||
235 | BEGIN(INITIAL); | ||
236 | } | ||
237 | |||
238 |
mimeview/mimetypes.y
0 → 100644
1 | %{ | ||
2 | /* GNU Mailutils -- a suite of utilities for electronic mail | ||
3 | Copyright (C) 2005 Free Software Foundation, Inc. | ||
4 | |||
5 | GNU Mailutils is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published by | ||
7 | the Free Software Foundation; either version 2, or (at your option) | ||
8 | any later version. | ||
9 | |||
10 | GNU Mailutils is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | GNU General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with GNU Mailutils; if not, write to the Free Software | ||
17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ | ||
18 | |||
19 | #ifdef HAVE_CONFIG_H | ||
20 | # include <config.h> | ||
21 | #endif | ||
22 | |||
23 | #include <mimeview.h> | ||
24 | #include <mimetypes-decl.h> | ||
25 | |||
26 | static void | ||
27 | yyprint (FILE *output, unsigned short toknum, YYSTYPE val) | ||
28 | { | ||
29 | switch (toknum) | ||
30 | { | ||
31 | case IDENT: | ||
32 | case IDENT_L: | ||
33 | case STRING: | ||
34 | fprintf (output, "[%lu] %s", (unsigned long) val.string.len, | ||
35 | val.string.ptr); | ||
36 | break; | ||
37 | |||
38 | case EOL: | ||
39 | default: | ||
40 | break; | ||
41 | } | ||
42 | } | ||
43 | |||
44 | #define YYPRINT yyprint | ||
45 | |||
46 | static list_t arg_list; /* For error recovery */ | ||
47 | |||
48 | #define L_OR 0 | ||
49 | #define L_AND 1 | ||
50 | |||
51 | enum node_type | ||
52 | { | ||
53 | functional_node, | ||
54 | binary_node, | ||
55 | negation_node, | ||
56 | suffix_node | ||
57 | }; | ||
58 | |||
59 | union argument | ||
60 | { | ||
61 | struct mimetypes_string *string; | ||
62 | unsigned number; | ||
63 | int c; | ||
64 | }; | ||
65 | |||
66 | typedef int (*builtin_t) (union argument *args); | ||
67 | |||
68 | struct node | ||
69 | { | ||
70 | enum node_type type; | ||
71 | union | ||
72 | { | ||
73 | struct | ||
74 | { | ||
75 | builtin_t fun; | ||
76 | union argument *args; | ||
77 | } function; | ||
78 | struct node *arg; | ||
79 | struct | ||
80 | { | ||
81 | int op; | ||
82 | struct node *arg1; | ||
83 | struct node *arg2; | ||
84 | } bin; | ||
85 | struct mimetypes_string suffix; | ||
86 | } v; | ||
87 | }; | ||
88 | |||
89 | static struct node *make_binary_node (int op, | ||
90 | struct node *left, struct node *rigth); | ||
91 | static struct node *make_negation_node (struct node *p); | ||
92 | |||
93 | static struct node *make_suffix_node (struct mimetypes_string *suffix); | ||
94 | static struct node *make_functional_node (char *ident, list_t list); | ||
95 | |||
96 | static int eval_rule (struct node *root); | ||
97 | |||
98 | struct rule_tab | ||
99 | { | ||
100 | char *type; | ||
101 | struct node *node; | ||
102 | }; | ||
103 | |||
104 | static list_t rule_list; | ||
105 | |||
106 | %} | ||
107 | |||
108 | %token <string> IDENT IDENT_L | ||
109 | %token <string> STRING | ||
110 | %token EOL BOGUS | ||
111 | |||
112 | %type <string> string arg type | ||
113 | %type <list> arglist | ||
114 | %type <node> function stmt rule | ||
115 | |||
116 | %union { | ||
117 | struct mimetypes_string string; | ||
118 | list_t list; | ||
119 | int result; | ||
120 | struct node *node; | ||
121 | } | ||
122 | |||
123 | %% | ||
124 | |||
125 | input : list | ||
126 | ; | ||
127 | |||
128 | list : rule_line | ||
129 | | list eol rule_line | ||
130 | ; | ||
131 | |||
132 | rule_line: /* empty */ | ||
133 | | type rule | ||
134 | { | ||
135 | struct rule_tab *p = mimetypes_malloc (sizeof (*p)); | ||
136 | if (!rule_list) | ||
137 | list_create (&rule_list); | ||
138 | p->type = $1.ptr; | ||
139 | p->node = $2; | ||
140 | list_append (rule_list, p); | ||
141 | } | ||
142 | | error eol | ||
143 | { | ||
144 | if (arg_list) | ||
145 | list_destroy (&arg_list); | ||
146 | arg_list = NULL; | ||
147 | reset_lex (); | ||
148 | } | ||
149 | ; | ||
150 | |||
151 | eol : EOL | ||
152 | | eol EOL | ||
153 | ; | ||
154 | |||
155 | type : IDENT '/' IDENT | ||
156 | { | ||
157 | $$ = mimetypes_append_string2 (&$1, '/', &$3); | ||
158 | } | ||
159 | ; | ||
160 | |||
161 | rule : stmt | ||
162 | | rule stmt | ||
163 | { | ||
164 | $$ = make_binary_node (L_OR, $1, $2); | ||
165 | } | ||
166 | | rule ',' stmt | ||
167 | { | ||
168 | $$ = make_binary_node (L_OR, $1, $3); | ||
169 | } | ||
170 | | rule '+' stmt | ||
171 | { | ||
172 | $$ = make_binary_node (L_AND, $1, $3); | ||
173 | } | ||
174 | ; | ||
175 | |||
176 | stmt : '!' stmt | ||
177 | { | ||
178 | $$ = make_negation_node ($2); | ||
179 | } | ||
180 | | '(' rule ')' | ||
181 | { | ||
182 | $$ = $2; | ||
183 | } | ||
184 | | string | ||
185 | { | ||
186 | $$ = make_suffix_node (&$1); | ||
187 | } | ||
188 | | function | ||
189 | ; | ||
190 | |||
191 | string : STRING | ||
192 | | IDENT | ||
193 | ; | ||
194 | |||
195 | function : IDENT_L arglist ')' | ||
196 | { | ||
197 | reset_lex (); | ||
198 | $$ = make_functional_node ($1.ptr, $2); | ||
199 | if (!$$) | ||
200 | YYERROR; | ||
201 | } | ||
202 | ; | ||
203 | |||
204 | arglist : arg | ||
205 | { | ||
206 | list_create (&arg_list); | ||
207 | $$ = arg_list; | ||
208 | list_append ($$, mimetypes_string_dup (&$1)); | ||
209 | } | ||
210 | | arglist ',' arg | ||
211 | { | ||
212 | list_append ($1, mimetypes_string_dup (&$3)); | ||
213 | $$ = $1; | ||
214 | } | ||
215 | ; | ||
216 | |||
217 | arg : string | ||
218 | ; | ||
219 | |||
220 | %% | ||
221 | |||
222 | int | ||
223 | mimetypes_parse (const char *name) | ||
224 | { | ||
225 | int rc; | ||
226 | if (mimetypes_open (name)) | ||
227 | return 1; | ||
228 | rc = yyparse (); | ||
229 | mimetypes_close (); | ||
230 | return rule_list == NULL; | ||
231 | } | ||
232 | |||
233 | void | ||
234 | mimetypes_gram_debug (int level) | ||
235 | { | ||
236 | yydebug = level; | ||
237 | } | ||
238 | |||
239 | |||
240 | static struct node * | ||
241 | make_node (enum node_type type) | ||
242 | { | ||
243 | struct node *p = mimetypes_malloc (sizeof *p); | ||
244 | p->type = type; | ||
245 | return p; | ||
246 | } | ||
247 | |||
248 | static struct node * | ||
249 | make_binary_node (int op, struct node *left, struct node *right) | ||
250 | { | ||
251 | struct node *node = make_node (binary_node); | ||
252 | |||
253 | node->v.bin.op = op; | ||
254 | node->v.bin.arg1 = left; | ||
255 | node->v.bin.arg2 = right; | ||
256 | return node; | ||
257 | } | ||
258 | |||
259 | struct node * | ||
260 | make_negation_node (struct node *p) | ||
261 | { | ||
262 | struct node *node = make_node (negation_node); | ||
263 | node->v.arg = p; | ||
264 | return node; | ||
265 | } | ||
266 | |||
267 | struct node * | ||
268 | make_suffix_node (struct mimetypes_string *suffix) | ||
269 | { | ||
270 | struct node *node = make_node (suffix_node); | ||
271 | node->v.suffix = *suffix; | ||
272 | return node; | ||
273 | } | ||
274 | |||
275 | struct builtin_tab | ||
276 | { | ||
277 | char *name; | ||
278 | char *args; | ||
279 | builtin_t handler; | ||
280 | }; | ||
281 | |||
282 | /* match("pattern") | ||
283 | Pattern match on filename | ||
284 | */ | ||
285 | static int | ||
286 | b_match (union argument *args) | ||
287 | { | ||
288 | return fnmatch (args[0].string->ptr, mimeview_file, 0) == 0; | ||
289 | } | ||
290 | |||
291 | /* ascii(offset,length) | ||
292 | True if bytes are valid printable ASCII (CR, NL, TAB, | ||
293 | BS, 32-126) | ||
294 | */ | ||
295 | static int | ||
296 | b_ascii (union argument *args) | ||
297 | { | ||
298 | int i; | ||
299 | if (fseek (mimeview_fp, args[0].number, SEEK_SET) == -1) | ||
300 | { | ||
301 | mu_error ("fseek: %s", mu_strerror (errno)); | ||
302 | return 0; | ||
303 | } | ||
304 | |||
305 | for (i = 0; i < args[1].number; i++) | ||
306 | { | ||
307 | int c = getc (mimeview_fp); | ||
308 | if (c == EOF) | ||
309 | break; | ||
310 | if (!isascii (c)) | ||
311 | return 0; | ||
312 | } | ||
313 | |||
314 | return 1; | ||
315 | } | ||
316 | |||
317 | /* printable(offset,length) | ||
318 | True if bytes are printable 8-bit chars (CR, NL, TAB, | ||
319 | BS, 32-126, 128-254) | ||
320 | */ | ||
321 | #define ISPRINT(c) ((c) &&\ | ||
322 | (strchr ("\n\r\t\b",c) \ | ||
323 | || (32<=(c) && (c)<=126) \ | ||
324 | || (128<=(c) && (c)<=254))) | ||
325 | static int | ||
326 | b_printable (union argument *args) | ||
327 | { | ||
328 | int i; | ||
329 | |||
330 | if (fseek (mimeview_fp, args[0].number, SEEK_SET) == -1) | ||
331 | { | ||
332 | mu_error ("fseek: %s", mu_strerror (errno)); | ||
333 | return 0; | ||
334 | } | ||
335 | |||
336 | for (i = 0; i < args[1].number; i++) | ||
337 | { | ||
338 | int c = getc (mimeview_fp); | ||
339 | if (c == EOF) | ||
340 | break; | ||
341 | if (!ISPRINT ((unsigned)c)) | ||
342 | return 0; | ||
343 | } | ||
344 | return 1; | ||
345 | } | ||
346 | |||
347 | /* string(offset,"string") | ||
348 | True if bytes are identical to string | ||
349 | */ | ||
350 | static int | ||
351 | b_string (union argument *args) | ||
352 | { | ||
353 | struct mimetypes_string *str = args[1].string; | ||
354 | int i; | ||
355 | |||
356 | if (fseek (mimeview_fp, args[0].number, SEEK_SET) == -1) | ||
357 | { | ||
358 | mu_error ("fseek: %s", mu_strerror (errno)); | ||
359 | return 0; | ||
360 | } | ||
361 | |||
362 | for (i = 0; i < str->len; i++) | ||
363 | { | ||
364 | int c = getc (mimeview_fp); | ||
365 | if (c == EOF || c != str->ptr[i]) | ||
366 | return 0; | ||
367 | } | ||
368 | return 1; | ||
369 | } | ||
370 | |||
371 | /* istring(offset,"string") | ||
372 | True if a case-insensitive comparison of the bytes is | ||
373 | identical | ||
374 | */ | ||
375 | static int | ||
376 | b_istring (union argument *args) | ||
377 | { | ||
378 | int i; | ||
379 | struct mimetypes_string *str = args[1].string; | ||
380 | |||
381 | if (fseek (mimeview_fp, args[0].number, SEEK_SET) == -1) | ||
382 | { | ||
383 | mu_error ("fseek: %s", mu_strerror (errno)); | ||
384 | return 0; | ||
385 | } | ||
386 | |||
387 | for (i = 0; i < str->len; i++) | ||
388 | { | ||
389 | int c = getc (mimeview_fp); | ||
390 | if (c == EOF || tolower (c) != tolower (str->ptr[i])) | ||
391 | return 0; | ||
392 | } | ||
393 | return 1; | ||
394 | } | ||
395 | |||
396 | /* char(offset,value) | ||
397 | True if byte is identical | ||
398 | */ | ||
399 | static int | ||
400 | b_char (union argument *args) | ||
401 | { | ||
402 | if (fseek (mimeview_fp, args[0].number, SEEK_SET) == -1) | ||
403 | { | ||
404 | mu_error ("fseek: %s", mu_strerror (errno)); | ||
405 | return 0; | ||
406 | } | ||
407 | return getc (mimeview_fp) == args[1].number; | ||
408 | } | ||
409 | |||
410 | /* short(offset,value) | ||
411 | True if 16-bit integer is identical | ||
412 | FIXME: Byte order | ||
413 | */ | ||
414 | static int | ||
415 | b_short (union argument *args) | ||
416 | { | ||
417 | unsigned short val; | ||
418 | int rc; | ||
419 | |||
420 | if (fseek (mimeview_fp, args[0].number, SEEK_SET) == -1) | ||
421 | { | ||
422 | mu_error ("fseek: %s", mu_strerror (errno)); | ||
423 | return 0; | ||
424 | } | ||
425 | rc = fread (&val, sizeof val, 1, mimeview_fp); | ||
426 | |||
427 | if (rc == -1) | ||
428 | { | ||
429 | mu_error ("fread: %s", mu_strerror (errno)); | ||
430 | return 0; | ||
431 | } | ||
432 | else if (rc == 0) | ||
433 | return 0; | ||
434 | return val == args[1].number; | ||
435 | } | ||
436 | |||
437 | /* int(offset,value) | ||
438 | True if 32-bit integer is identical | ||
439 | FIXME: Byte order | ||
440 | */ | ||
441 | static int | ||
442 | b_int (union argument *args) | ||
443 | { | ||
444 | unsigned int val; | ||
445 | int rc; | ||
446 | |||
447 | if (fseek (mimeview_fp, args[0].number, SEEK_SET) == -1) | ||
448 | { | ||
449 | mu_error ("fseek: %s", mu_strerror (errno)); | ||
450 | return 0; | ||
451 | } | ||
452 | rc = fread (&val, sizeof val, 1, mimeview_fp); | ||
453 | if (rc == -1) | ||
454 | { | ||
455 | mu_error ("fread: %s", mu_strerror (errno)); | ||
456 | return 0; | ||
457 | } | ||
458 | else if (rc == 0) | ||
459 | return 0; | ||
460 | return val == args[1].number; | ||
461 | } | ||
462 | |||
463 | /* locale("string") | ||
464 | True if current locale matches string | ||
465 | */ | ||
466 | static int | ||
467 | b_locale (union argument *args) | ||
468 | { | ||
469 | abort (); /* FIXME */ | ||
470 | return 0; | ||
471 | } | ||
472 | |||
473 | /* contains(offset,range,"string") | ||
474 | True if the range contains the string | ||
475 | */ | ||
476 | static int | ||
477 | b_contains (union argument *args) | ||
478 | { | ||
479 | int i, count; | ||
480 | char *buf; | ||
481 | struct mimetypes_string *str = args[2].string; | ||
482 | |||
483 | if (fseek (mimeview_fp, args[0].number, SEEK_SET) == -1) | ||
484 | { | ||
485 | mu_error ("fseek: %s", mu_strerror (errno)); | ||
486 | return 0; | ||
487 | } | ||
488 | buf = xmalloc (args[1].number); | ||
489 | count = fread (buf, 1, args[1].number, mimeview_fp); | ||
490 | if (count == -1) | ||
491 | { | ||
492 | mu_error ("fread: %s", mu_strerror (errno)); | ||
493 | } | ||
494 | else if (count > str->len) | ||
495 | for (i = 0; i < count - str->len; i++) | ||
496 | if (buf[i] == str->ptr[0] && memcmp (buf + i, str->ptr, str->len) == 0) | ||
497 | { | ||
498 | free (buf); | ||
499 | return 1; | ||
500 | } | ||
501 | free (buf); | ||
502 | return 0; | ||
503 | } | ||
504 | |||
505 | static struct builtin_tab builtin_tab[] = { | ||
506 | { "match", "s", b_match }, | ||
507 | { "ascii", "dd", b_ascii }, | ||
508 | { "printable", "dd", b_printable }, | ||
509 | { "string", "ds", b_string }, | ||
510 | { "istring", "ds", b_istring }, | ||
511 | { "char", "dc", b_char }, | ||
512 | { "short", "dd", b_short }, | ||
513 | { "int", "dd", b_int }, | ||
514 | { "locale", "s", b_locale }, | ||
515 | { "contains", "dds", b_contains }, | ||
516 | { NULL } | ||
517 | }; | ||
518 | |||
519 | struct node * | ||
520 | make_functional_node (char *ident, list_t list) | ||
521 | { | ||
522 | size_t count, i; | ||
523 | struct builtin_tab *p; | ||
524 | struct node *node; | ||
525 | union argument *args; | ||
526 | iterator_t itr; | ||
527 | |||
528 | for (p = builtin_tab; ; p++) | ||
529 | { | ||
530 | if (!p->name) | ||
531 | { | ||
532 | char *s; | ||
533 | asprintf (&s, _("%s: unknown function"), ident); | ||
534 | yyerror (s); | ||
535 | free (s); | ||
536 | return NULL; | ||
537 | } | ||
538 | |||
539 | if (strcmp (ident, p->name) == 0) | ||
540 | break; | ||
541 | } | ||
542 | |||
543 | list_count (list, &count); | ||
544 | i = strlen (p->args); | ||
545 | |||
546 | if (count < i) | ||
547 | { | ||
548 | char *s; | ||
549 | asprintf (&s, _("too few arguments in call to `%s'"), ident); | ||
550 | yyerror (s); | ||
551 | free (s); | ||
552 | return NULL; | ||
553 | } | ||
554 | else if (count > i) | ||
555 | { | ||
556 | char *s; | ||
557 | asprintf (&s, _("too many arguments in call to `%s'"), ident); | ||
558 | yyerror (s); | ||
559 | free (s); | ||
560 | return NULL; | ||
561 | } | ||
562 | |||
563 | args = mimetypes_malloc (count * sizeof *args); | ||
564 | |||
565 | list_get_iterator (list, &itr); | ||
566 | for (i = 0, iterator_first (itr); !iterator_is_done (itr); | ||
567 | iterator_next (itr), i++) | ||
568 | { | ||
569 | struct mimetypes_string *data; | ||
570 | char *tmp; | ||
571 | |||
572 | iterator_current (itr, (void **)&data); | ||
573 | switch (p->args[i]) | ||
574 | { | ||
575 | case 'd': | ||
576 | args[i].number = strtoul (data->ptr, &tmp, 0); | ||
577 | if (*tmp) | ||
578 | goto err; | ||
579 | break; | ||
580 | |||
581 | case 's': | ||
582 | args[i].string = data; | ||
583 | break; | ||
584 | |||
585 | case 'c': | ||
586 | args[i].c = strtoul (data->ptr, &tmp, 0); | ||
587 | if (*tmp) | ||
588 | goto err; | ||
589 | break; | ||
590 | |||
591 | default: | ||
592 | abort (); | ||
593 | } | ||
594 | } | ||
595 | |||
596 | node = make_node (functional_node); | ||
597 | node->v.function.fun = p->handler; | ||
598 | node->v.function.args = args; | ||
599 | return node; | ||
600 | |||
601 | err: | ||
602 | { | ||
603 | char *s; | ||
604 | asprintf (&s, | ||
605 | _("argument %d has wrong type in call to `%s'"), | ||
606 | i, ident); | ||
607 | yyerror (s); | ||
608 | free (s); | ||
609 | return NULL; | ||
610 | } | ||
611 | } | ||
612 | |||
613 | static int | ||
614 | check_suffix (char *suf) | ||
615 | { | ||
616 | char *p = strrchr (mimeview_file, '.'); | ||
617 | if (!p) | ||
618 | return 0; | ||
619 | return strcmp (p+1, suf) == 0; | ||
620 | } | ||
621 | |||
622 | static int | ||
623 | eval_rule (struct node *root) | ||
624 | { | ||
625 | int result; | ||
626 | |||
627 | switch (root->type) | ||
628 | { | ||
629 | case functional_node: | ||
630 | result = root->v.function.fun (root->v.function.args); | ||
631 | break; | ||
632 | |||
633 | case binary_node: | ||
634 | result = eval_rule (root->v.bin.arg1); | ||
635 | switch (root->v.bin.op) | ||
636 | { | ||
637 | case L_OR: | ||
638 | if (!result) | ||
639 | result |= eval_rule (root->v.bin.arg2); | ||
640 | break; | ||
641 | |||
642 | case L_AND: | ||
643 | if (result) | ||
644 | result &= eval_rule (root->v.bin.arg2); | ||
645 | break; | ||
646 | |||
647 | default: | ||
648 | abort (); | ||
649 | } | ||
650 | break; | ||
651 | |||
652 | case negation_node: | ||
653 | result = !eval_rule (root->v.arg); | ||
654 | break; | ||
655 | |||
656 | case suffix_node: | ||
657 | result = check_suffix (root->v.suffix.ptr); | ||
658 | break; | ||
659 | |||
660 | default: | ||
661 | abort (); | ||
662 | } | ||
663 | return result; | ||
664 | } | ||
665 | |||
666 | static int | ||
667 | evaluate (void *item, void *data) | ||
668 | { | ||
669 | struct rule_tab *p = item; | ||
670 | char **ptype = data; | ||
671 | |||
672 | if (eval_rule (p->node)) | ||
673 | { | ||
674 | *ptype = p->type; | ||
675 | return 1; | ||
676 | } | ||
677 | return 0; | ||
678 | } | ||
679 | |||
680 | const char * | ||
681 | get_file_type () | ||
682 | { | ||
683 | const char *type = NULL; | ||
684 | list_do (rule_list, evaluate, &type); | ||
685 | return type; | ||
686 | } | ||
687 |
mimeview/mimeview.c
0 → 100644
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | ||
2 | Copyright (C) 2005 Free Software Foundation, Inc. | ||
3 | |||
4 | GNU Mailutils is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 2, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | GNU Mailutils is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with GNU Mailutils; if not, write to the Free Software | ||
16 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ | ||
17 | |||
18 | #ifdef HAVE_CONFIG_H | ||
19 | # include <config.h> | ||
20 | #endif | ||
21 | |||
22 | #include <mimeview.h> | ||
23 | #include <sys/stat.h> | ||
24 | |||
25 | const char *program_version = "mimeview (" PACKAGE_STRING ")"; | ||
26 | static char doc[] = N_("GNU mimeview -- display MIME files\ | ||
27 | Default mime.types file is ") SYSCONFDIR "/cups/mime.types" | ||
28 | N_("\nDebug flags are:\n\ | ||
29 | g - Mime.types parser traces\n\ | ||
30 | l - Mime.types lexical analyzer traces\n\ | ||
31 | 0-9 - Set debugging level\n"); | ||
32 | |||
33 | #define OPT_METAMAIL 256 | ||
34 | |||
35 | static struct argp_option options[] = { | ||
36 | {"debug", 'd', N_("FLAGS"), OPTION_ARG_OPTIONAL, | ||
37 | N_("Enable debugging output"), 0}, | ||
38 | {"mimetypes", 't', N_("FILE"), 0, | ||
39 | N_("Use this mime.types file"), 0}, | ||
40 | {"dry-run", 'n', NULL, 0, | ||
41 | N_("Do not do anything, just print what whould be done"), 0}, | ||
42 | {"metamail", OPT_METAMAIL, N_("FILE"), OPTION_ARG_OPTIONAL, | ||
43 | N_("Use metamail to display files"), 0}, | ||
44 | {0, 0, 0, 0} | ||
45 | }; | ||
46 | |||
47 | int debug_level; /* Debugging level set by --debug option */ | ||
48 | static int dry_run; /* Dry run mode */ | ||
49 | static char *metamail; /* Name of metamail program, if requested */ | ||
50 | static char *mimetypes_config = SYSCONFDIR "/cups"; | ||
51 | |||
52 | char *mimeview_file; /* Name of the file to view */ | ||
53 | FILE *mimeview_fp; /* Its descriptor */ | ||
54 | |||
55 | /* Default mailcap path, the $HOME/.mailcap: entry is prepended to it */ | ||
56 | #define DEFAULT_MAILCAP \ | ||
57 | "/usr/local/etc/mailcap:"\ | ||
58 | "/usr/etc/mailcap:"\ | ||
59 | "/etc/mailcap:"\ | ||
60 | "/etc/mail/mailcap:"\ | ||
61 | "/usr/public/lib/mailcap" | ||
62 | |||
63 | |||
64 | static error_t | ||
65 | parse_opt (int key, char *arg, struct argp_state *state) | ||
66 | { | ||
67 | switch (key) | ||
68 | { | ||
69 | case ARGP_KEY_INIT: | ||
70 | mimetypes_lex_debug (0); | ||
71 | mimetypes_gram_debug (0); | ||
72 | break; | ||
73 | |||
74 | case ARGP_KEY_FINI: | ||
75 | if (dry_run && !debug_level) | ||
76 | debug_level = 1; | ||
77 | break; | ||
78 | |||
79 | case 'd': | ||
80 | if (!arg) | ||
81 | arg = "9"; | ||
82 | for (; *arg; arg++) | ||
83 | { | ||
84 | switch (*arg) | ||
85 | { | ||
86 | case 'l': | ||
87 | mimetypes_lex_debug (1); | ||
88 | break; | ||
89 | |||
90 | case 'g': | ||
91 | mimetypes_gram_debug (1); | ||
92 | break; | ||
93 | |||
94 | default: | ||
95 | debug_level = *arg - '0'; | ||
96 | } | ||
97 | } | ||
98 | break; | ||
99 | |||
100 | case 'n': | ||
101 | dry_run = 1; | ||
102 | break; | ||
103 | |||
104 | case 't': | ||
105 | mimetypes_config = arg; | ||
106 | break; | ||
107 | |||
108 | case OPT_METAMAIL: | ||
109 | metamail = arg ? arg : "metamail"; | ||
110 | break; | ||
111 | |||
112 | default: | ||
113 | return ARGP_ERR_UNKNOWN; | ||
114 | } | ||
115 | return 0; | ||
116 | } | ||
117 | |||
118 | static struct argp argp = { | ||
119 | options, | ||
120 | parse_opt, | ||
121 | N_("FILE [FILE ...]"), | ||
122 | doc, | ||
123 | NULL, | ||
124 | NULL, NULL | ||
125 | }; | ||
126 | |||
127 | static const char *capa[] = { | ||
128 | "common", | ||
129 | "license", | ||
130 | NULL | ||
131 | }; | ||
132 | |||
133 | static int | ||
134 | open_file (char *name) | ||
135 | { | ||
136 | struct stat st; | ||
137 | |||
138 | if (stat (name, &st)) | ||
139 | { | ||
140 | mu_error (_("Cannot stat `%s': %s"), name, mu_strerror (errno)); | ||
141 | return -1; | ||
142 | } | ||
143 | if (!S_ISREG (st.st_mode) && !S_ISLNK (st.st_mode)) | ||
144 | { | ||
145 | mu_error (_("Not a regular file or symbolic link: `%s'"), name); | ||
146 | return -1; | ||
147 | } | ||
148 | |||
149 | mimeview_file = name; | ||
150 | mimeview_fp = fopen (name, "r"); | ||
151 | if (mimeview_fp == NULL) | ||
152 | { | ||
153 | mu_error (_("Cannot open `%s': %s"), name, mu_strerror (errno)); | ||
154 | return -1; | ||
155 | } | ||
156 | return 0; | ||
157 | } | ||
158 | |||
159 | void | ||
160 | close_file () | ||
161 | { | ||
162 | fclose (mimeview_fp); | ||
163 | } | ||
164 | |||
165 | static struct obstack expand_stack; | ||
166 | |||
167 | static void | ||
168 | expand_string (char **pstr, const char *filename, const char *type) | ||
169 | { | ||
170 | char *p; | ||
171 | size_t namelen = strlen (filename); | ||
172 | size_t typelen = strlen (type); | ||
173 | |||
174 | for (p = *pstr; *p; ) | ||
175 | { | ||
176 | switch (p[0]) | ||
177 | { | ||
178 | case '%': | ||
179 | switch (p[1]) | ||
180 | { | ||
181 | case 's': | ||
182 | obstack_grow (&expand_stack, filename, namelen); | ||
183 | p += 2; | ||
184 | break; | ||
185 | |||
186 | case 't': | ||
187 | obstack_grow (&expand_stack, type, typelen); | ||
188 | p += 2; | ||
189 | break; | ||
190 | |||
191 | case '{': | ||
192 | /* Hmm, we don't have content-type field, sorry... */ | ||
193 | while (*p && *p != '}') | ||
194 | p++; | ||
195 | if (*p) | ||
196 | p++; | ||
197 | break; | ||
198 | |||
199 | /* FIXME: Handle %F and %n */ | ||
200 | default: | ||
201 | obstack_1grow (&expand_stack, p[0]); | ||
202 | } | ||
203 | break; | ||
204 | |||
205 | case '\\': | ||
206 | if (p[1]) | ||
207 | { | ||
208 | obstack_1grow (&expand_stack, p[1]); | ||
209 | p += 2; | ||
210 | } | ||
211 | else | ||
212 | { | ||
213 | obstack_1grow (&expand_stack, p[0]); | ||
214 | p++; | ||
215 | } | ||
216 | break; | ||
217 | |||
218 | case '"': | ||
219 | if (p[1] == p[0]) | ||
220 | { | ||
221 | obstack_1grow (&expand_stack, '%'); | ||
222 | p++; | ||
223 | } | ||
224 | else | ||
225 | { | ||
226 | obstack_1grow (&expand_stack, p[0]); | ||
227 | p++; | ||
228 | } | ||
229 | break; | ||
230 | |||
231 | default: | ||
232 | obstack_1grow (&expand_stack, p[0]); | ||
233 | p++; | ||
234 | } | ||
235 | } | ||
236 | obstack_1grow (&expand_stack, 0); | ||
237 | free (*pstr); | ||
238 | *pstr = obstack_finish (&expand_stack); | ||
239 | } | ||
240 | |||
241 | static int | ||
242 | find_entry (const char *file, const char *type, | ||
243 | mu_mailcap_entry_t *pentry, | ||
244 | mu_mailcap_t *pmc) | ||
245 | { | ||
246 | mu_mailcap_t mailcap; | ||
247 | int status; | ||
248 | stream_t stream; | ||
249 | |||
250 | DEBUG (2, (_("Trying %s...\n"), file)); | ||
251 | status = file_stream_create (&stream, file, MU_STREAM_READ); | ||
252 | if (status) | ||
253 | { | ||
254 | mu_error ("cannot create file stream %s: %s", | ||
255 | file, mu_strerror (status)); | ||
256 | return 0; | ||
257 | } | ||
258 | |||
259 | status = stream_open (stream); | ||
260 | if (status) | ||
261 | { | ||
262 | stream_destroy (&stream, stream_get_owner (stream)); | ||
263 | if (status != ENOENT) | ||
264 | mu_error ("cannot open file stream %s: %s", | ||
265 | file, mu_strerror (status)); | ||
266 | return 0; | ||
267 | } | ||
268 | |||
269 | status = mu_mailcap_create (&mailcap, stream); | ||
270 | if (status == 0) | ||
271 | { | ||
272 | size_t i, count = 0; | ||
273 | |||
274 | mu_mailcap_entries_count (mailcap, &count); | ||
275 | for (i = 1; i <= count; i++) | ||
276 | { | ||
277 | mu_mailcap_entry_t entry; | ||
278 | char buffer[256]; | ||
279 | |||
280 | if (mu_mailcap_get_entry (mailcap, i, &entry)) | ||
281 | continue; | ||
282 | |||
283 | /* typefield. */ | ||
284 | mu_mailcap_entry_get_typefield (entry, | ||
285 | buffer, sizeof (buffer), NULL); | ||
286 | |||
287 | if (fnmatch (buffer, type, FNM_CASEFOLD) == 0) | ||
288 | { | ||
289 | DEBUG (2, (_("Found in %s\n"), file)); | ||
290 | /* FIXME: Run test entry, if any */ | ||
291 | *pmc = mailcap; | ||
292 | *pentry = entry; | ||
293 | return 1; /* We leave stream open! */ | ||
294 | } | ||
295 | } | ||
296 | mu_mailcap_destroy (&mailcap); | ||
297 | } | ||
298 | else | ||
299 | { | ||
300 | mu_error ("cannot create mailcap for %s: %s", | ||
301 | file, mu_strerror (status)); | ||
302 | } | ||
303 | return 0; | ||
304 | } | ||
305 | |||
306 | static void | ||
307 | dump_mailcap_entry (mu_mailcap_entry_t entry) | ||
308 | { | ||
309 | char buffer[256]; | ||
310 | size_t i, count; | ||
311 | |||
312 | mu_mailcap_entry_get_typefield (entry, buffer, | ||
313 | sizeof (buffer), NULL); | ||
314 | printf ("typefield: %s\n", buffer); | ||
315 | |||
316 | /* view-command. */ | ||
317 | mu_mailcap_entry_get_viewcommand (entry, buffer, | ||
318 | sizeof (buffer), NULL); | ||
319 | printf ("view-command: %s\n", buffer); | ||
320 | |||
321 | /* fields. */ | ||
322 | mu_mailcap_entry_fields_count (entry, &count); | ||
323 | for (i = 1; i <= count; i++) | ||
324 | { | ||
325 | int status = mu_mailcap_entry_get_field (entry, i, buffer, | ||
326 | sizeof (buffer), NULL); | ||
327 | if (status) | ||
328 | { | ||
329 | mu_error (_("cannot retrieve field %lu: %s"), | ||
330 | (unsigned long) i, | ||
331 | mu_strerror (status)); | ||
332 | break; | ||
333 | } | ||
334 | printf ("fields[%d]: %s\n", i, buffer); | ||
335 | } | ||
336 | printf ("\n"); | ||
337 | } | ||
338 | |||
339 | int | ||
340 | run_mailcap (mu_mailcap_entry_t entry, const char *type) | ||
341 | { | ||
342 | char *view_command; | ||
343 | size_t size; | ||
344 | int flag; | ||
345 | int status; | ||
346 | int argc; | ||
347 | char **argv; | ||
348 | /* pid_t pager = -1; */ | ||
349 | |||
350 | if (debug_level > 1) | ||
351 | dump_mailcap_entry (entry); | ||
352 | |||
353 | mu_mailcap_entry_get_viewcommand (entry, NULL, 0, &size); | ||
354 | size++; | ||
355 | view_command = xmalloc (size); | ||
356 | mu_mailcap_entry_get_viewcommand (entry, view_command, size, NULL); | ||
357 | |||
358 | /* NOTE: We don't create temporary file for %s, we just use | ||
359 | mimeview_file instead */ | ||
360 | expand_string (&view_command, mimeview_file, type); | ||
361 | DEBUG (0, (_("Executing %s...\n"), view_command)); | ||
362 | |||
363 | if (dry_run) | ||
364 | return 0; | ||
365 | |||
366 | status = argcv_get (view_command, "", NULL, &argc, &argv); | ||
367 | free (view_command); | ||
368 | if (status) | ||
369 | { | ||
370 | mu_error (_("Cannot parse command line: %s"), mu_strerror (status)); | ||
371 | return 1; | ||
372 | } | ||
373 | |||
374 | /* | ||
375 | if (mu_mailcap_entry_coupiousoutput (entry, &flag) == 0 && flag) | ||
376 | pager = open_pager (); | ||
377 | */ | ||
378 | |||
379 | if (pager <= 0) | ||
380 | { | ||
381 | if (mu_spawnvp (argv[0], argv, &status)) | ||
382 | mu_error (_("Cannot execute command: %s"), mu_strerror (status)); | ||
383 | |||
384 | if (debug_level) | ||
385 | { | ||
386 | if (WIFEXITED (status)) | ||
387 | printf (_("Command exited with status %d\n"), WEXITSTATUS(status)); | ||
388 | else if (WIFSIGNALED (status)) | ||
389 | printf(_("Command terminated on signal %d\n"), WTERMSIG(status)); | ||
390 | else | ||
391 | printf (_("Command terminated")); | ||
392 | } | ||
393 | } | ||
394 | argcv_free (argc, argv); | ||
395 | /* close_pager (pager); */ | ||
396 | } | ||
397 | |||
398 | void | ||
399 | display_file_mailcap (const char *type) | ||
400 | { | ||
401 | char *p, *sp; | ||
402 | char *mailcap_path; | ||
403 | mu_mailcap_t mailcap = NULL; | ||
404 | mu_mailcap_entry_t entry = NULL; | ||
405 | |||
406 | mailcap_path = getenv ("MAILCAP"); | ||
407 | if (!mailcap_path) | ||
408 | { | ||
409 | char *home = mu_get_homedir (); | ||
410 | asprintf (&mailcap_path, "%s/.mailcap:%s", home, DEFAULT_MAILCAP); | ||
411 | } | ||
412 | else | ||
413 | mailcap_path = strdup (mailcap_path); | ||
414 | |||
415 | obstack_init (&expand_stack); | ||
416 | |||
417 | for (p = strtok_r (mailcap_path, ":", &sp); p; p = strtok_r (NULL, ":", &sp)) | ||
418 | { | ||
419 | if (find_entry (p, type, &entry, &mailcap)) | ||
420 | { | ||
421 | run_mailcap (entry, type); | ||
422 | mu_mailcap_destroy (&mailcap); | ||
423 | break; | ||
424 | } | ||
425 | } | ||
426 | } | ||
427 | |||
428 | void | ||
429 | display_file (const char *type) | ||
430 | { | ||
431 | if (metamail) | ||
432 | { | ||
433 | int status; | ||
434 | const char *argv[6]; | ||
435 | |||
436 | argv[0] = "metamail"; | ||
437 | argv[1] = "-b"; | ||
438 | argv[2] = "-c"; | ||
439 | argv[3] = type; | ||
440 | argv[4] = mimeview_file; | ||
441 | argv[5] = NULL; | ||
442 | |||
443 | if (debug_level) | ||
444 | { | ||
445 | char *string; | ||
446 | argcv_string (5, argv, &string); | ||
447 | printf (_("Executing %s...\n"), string); | ||
448 | free (string); | ||
449 | } | ||
450 | |||
451 | if (!dry_run) | ||
452 | mu_spawnvp (metamail, argv, &status); | ||
453 | } | ||
454 | else | ||
455 | display_file_mailcap (type); | ||
456 | } | ||
457 | |||
458 | int | ||
459 | main (int argc, char **argv) | ||
460 | { | ||
461 | int index; | ||
462 | |||
463 | mu_init_nls (); | ||
464 | mu_argp_init (program_version, NULL); | ||
465 | mu_argp_parse (&argp, &argc, &argv, 0, capa, &index, NULL); | ||
466 | |||
467 | argc -= index; | ||
468 | argv += index; | ||
469 | |||
470 | if (argc == 0) | ||
471 | { | ||
472 | mu_error (_("No files given")); | ||
473 | return 1; | ||
474 | } | ||
475 | |||
476 | if (mimetypes_parse (mimetypes_config)) | ||
477 | return 1; | ||
478 | |||
479 | while (argc--) | ||
480 | { | ||
481 | const char *type; | ||
482 | |||
483 | if (open_file (*argv++)) | ||
484 | continue; | ||
485 | type = get_file_type (); | ||
486 | DEBUG (1, ("%s: %s\n", mimeview_file, type ? type : "?")); | ||
487 | if (type) | ||
488 | display_file (type); | ||
489 | close_file (); | ||
490 | } | ||
491 | |||
492 | return 0; | ||
493 | } |
mimeview/mimeview.h
0 → 100644
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | ||
2 | Copyright (C) 2005 Free Software Foundation, Inc. | ||
3 | |||
4 | GNU Mailutils is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 2, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | GNU Mailutils is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with GNU Mailutils; if not, write to the Free Software | ||
16 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ | ||
17 | |||
18 | #include <stdlib.h> | ||
19 | #include <stdio.h> | ||
20 | #include <string.h> | ||
21 | #ifdef HAVE_STRINGS_H | ||
22 | # include <strings.h> | ||
23 | #endif | ||
24 | #include <mailutils/mailutils.h> | ||
25 | #include <xalloc.h> | ||
26 | #include <fnmatch.h> | ||
27 | #define obstack_chunk_alloc malloc | ||
28 | #define obstack_chunk_free free | ||
29 | #include <obstack.h> | ||
30 | |||
31 | struct mimetypes_string | ||
32 | { | ||
33 | char *ptr; | ||
34 | size_t len; | ||
35 | }; | ||
36 | |||
37 | int mimetypes_yylex (void); | ||
38 | int mimetypes_yyerror (char *s); | ||
39 | |||
40 | int mimetypes_open (const char *name); | ||
41 | void mimetypes_close (void); | ||
42 | int mimetypes_parse (const char *name); | ||
43 | void mimetypes_gram_debug (int level); | ||
44 | void mimetypes_lex_debug (int level); | ||
45 | void mimetypes_lex_init (void); | ||
46 | void reset_lex (void); | ||
47 | void *mimetypes_malloc (size_t size); | ||
48 | |||
49 | struct mimetypes_string mimetypes_append_string2 (struct mimetypes_string *s1, | ||
50 | char c, | ||
51 | struct mimetypes_string *s2); | ||
52 | struct mimetypes_string *mimetypes_string_dup (struct mimetypes_string *s); | ||
53 | |||
54 | const char *get_file_type (void); | ||
55 | |||
56 | extern char *mimeview_file; | ||
57 | extern FILE *mimeview_fp; | ||
58 | extern int debug_level; | ||
59 | |||
60 | #define DEBUG(l,f) if (debug_level > (l)) printf f |
-
Please register or sign in to post a comment