diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2005-03-12 19:18:55 +0000 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2005-03-12 19:18:55 +0000 |
commit | 4e6c7e6e3f5a8906c5229390b45c2c9b3aa090df (patch) | |
tree | 9b175f494e057e444cf732dfda58c196b5cd56b8 /lib | |
parent | 060730686c03584575b5497a3b765ab963b2e690 (diff) | |
download | mailutils-4e6c7e6e3f5a8906c5229390b45c2c9b3aa090df.tar.gz mailutils-4e6c7e6e3f5a8906c5229390b45c2c9b3aa090df.tar.bz2 |
Routines for displaying MIME messages.
Diffstat (limited to 'lib')
-rw-r--r-- | lib/mailcap.c | 660 |
1 files changed, 660 insertions, 0 deletions
diff --git a/lib/mailcap.c b/lib/mailcap.c new file mode 100644 index 000000000..8e0d65f97 --- /dev/null +++ b/lib/mailcap.c | |||
@@ -0,0 +1,660 @@ | |||
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 | #include <mailutils/mailutils.h> | ||
22 | #include <xalloc.h> | ||
23 | #include <fnmatch.h> | ||
24 | #define obstack_chunk_alloc malloc | ||
25 | #define obstack_chunk_free free | ||
26 | #include <obstack.h> | ||
27 | #include <sys/wait.h> | ||
28 | |||
29 | /* Default mailcap path, the $HOME/.mailcap: entry is prepended to it */ | ||
30 | #define DEFAULT_MAILCAP \ | ||
31 | "/usr/local/etc/mailcap:"\ | ||
32 | "/usr/etc/mailcap:"\ | ||
33 | "/etc/mailcap:"\ | ||
34 | "/etc/mail/mailcap:"\ | ||
35 | "/usr/public/lib/mailcap" | ||
36 | |||
37 | #define FLAGS_DRY_RUN 0x0001 | ||
38 | #define FLAGS_INTERACTIVE 0x0002 | ||
39 | |||
40 | struct mime_context | ||
41 | { | ||
42 | stream_t input; | ||
43 | header_t hdr; | ||
44 | char *content_type_buffer; | ||
45 | char *content_type; | ||
46 | list_t values; | ||
47 | char *temp_file; | ||
48 | int unlink_temp_file; | ||
49 | |||
50 | char *no_ask_str; | ||
51 | list_t no_ask_types; | ||
52 | int debug_level; | ||
53 | int flags; | ||
54 | }; | ||
55 | |||
56 | #define DEBUG(c,l,f) if ((c)->debug_level > (l)) printf f | ||
57 | |||
58 | static void | ||
59 | mime_context_fill (struct mime_context *ctx, const char *file, | ||
60 | stream_t input, header_t hdr, const char *no_ask, | ||
61 | int interactive, int dry_run, int debug_level) | ||
62 | { | ||
63 | char *p, *sp; | ||
64 | |||
65 | memset (ctx, 0, sizeof *ctx); | ||
66 | ctx->input = input; | ||
67 | ctx->hdr = hdr; | ||
68 | header_aget_value (hdr, MU_HEADER_CONTENT_TYPE, &ctx->content_type_buffer); | ||
69 | ctx->content_type = strtok_r (ctx->content_type_buffer, ";", &sp); | ||
70 | ctx->temp_file = file ? strdup (file) : NULL; | ||
71 | ctx->unlink_temp_file = 0; | ||
72 | |||
73 | if (interactive) | ||
74 | ctx->flags |= FLAGS_INTERACTIVE; | ||
75 | if (dry_run) | ||
76 | ctx->flags |= FLAGS_DRY_RUN; | ||
77 | ctx->debug_level = debug_level; | ||
78 | |||
79 | list_create (&ctx->values); | ||
80 | while ((p = strtok_r (NULL, ";", &sp))) | ||
81 | list_append (ctx->values, p); | ||
82 | |||
83 | if (no_ask) | ||
84 | { | ||
85 | ctx->no_ask_str = xstrdup (no_ask); | ||
86 | list_create (&ctx->no_ask_types); | ||
87 | for (p = strtok_r (ctx->no_ask_str, ",", &sp); p; | ||
88 | p = strtok_r (NULL, ",", &sp)) | ||
89 | list_append (ctx->no_ask_types, p); | ||
90 | } | ||
91 | } | ||
92 | |||
93 | static void | ||
94 | mime_context_release (struct mime_context *ctx) | ||
95 | { | ||
96 | free (ctx->content_type_buffer); | ||
97 | if (ctx->unlink_temp_file) | ||
98 | unlink (ctx->temp_file); | ||
99 | free (ctx->temp_file); | ||
100 | list_destroy (&ctx->values); | ||
101 | free (ctx->no_ask_str); | ||
102 | list_destroy (&ctx->no_ask_types); | ||
103 | } | ||
104 | |||
105 | static int | ||
106 | mime_context_do_not_ask (struct mime_context *ctx) | ||
107 | { | ||
108 | int rc = 0; | ||
109 | |||
110 | if (ctx->no_ask_types) | ||
111 | { | ||
112 | iterator_t itr; | ||
113 | list_get_iterator (ctx->no_ask_types, &itr); | ||
114 | for (iterator_first (itr); !rc && !iterator_is_done (itr); | ||
115 | iterator_next (itr)) | ||
116 | { | ||
117 | char *p; | ||
118 | iterator_current (itr, (void**)&p); | ||
119 | rc = fnmatch (p, ctx->content_type, FNM_CASEFOLD) == 0; | ||
120 | } | ||
121 | iterator_destroy (&itr); | ||
122 | } | ||
123 | return rc; | ||
124 | } | ||
125 | |||
126 | int | ||
127 | dry_run_p (struct mime_context *ctx) | ||
128 | { | ||
129 | return ctx->flags & FLAGS_DRY_RUN; | ||
130 | } | ||
131 | |||
132 | int | ||
133 | interactive_p (struct mime_context *ctx) | ||
134 | { | ||
135 | return ctx->flags & FLAGS_INTERACTIVE; | ||
136 | } | ||
137 | |||
138 | static void | ||
139 | mime_context_get_content_type (struct mime_context *ctx, char **ptr) | ||
140 | { | ||
141 | *ptr = ctx->content_type; | ||
142 | } | ||
143 | |||
144 | static void | ||
145 | mime_context_get_input (struct mime_context *ctx, stream_t *pinput) | ||
146 | { | ||
147 | *pinput = ctx->input; | ||
148 | } | ||
149 | |||
150 | static void | ||
151 | mime_context_get_content_type_value (struct mime_context *ctx, | ||
152 | char *name, size_t len, | ||
153 | char **ptr, size_t *plen) | ||
154 | { | ||
155 | iterator_t itr = NULL; | ||
156 | |||
157 | list_get_iterator (ctx->values, &itr); | ||
158 | for (iterator_first (itr); !iterator_is_done (itr); iterator_next (itr)) | ||
159 | { | ||
160 | char *item, *p; | ||
161 | |||
162 | iterator_current (itr, (void**) &item); | ||
163 | p = strchr (item, '='); | ||
164 | if (p - item == len && strncasecmp (item, name, len) == 0) | ||
165 | { | ||
166 | *ptr = ++p; | ||
167 | *plen = strlen (*ptr); | ||
168 | if (**ptr == '"') | ||
169 | { | ||
170 | ++*ptr; | ||
171 | *plen -= 2; | ||
172 | } | ||
173 | break; | ||
174 | } | ||
175 | } | ||
176 | iterator_destroy (&itr); | ||
177 | } | ||
178 | |||
179 | static void | ||
180 | mime_context_write_input (struct mime_context *ctx, int fd) | ||
181 | { | ||
182 | stream_t input; | ||
183 | char buf[512]; | ||
184 | size_t n; | ||
185 | int status; | ||
186 | |||
187 | mime_context_get_input (ctx, &input); | ||
188 | stream_seek (input, 0, SEEK_SET); | ||
189 | while ((status = stream_sequential_read (input, buf, sizeof buf, &n)) == 0 | ||
190 | && n) | ||
191 | write (fd, buf, n); | ||
192 | } | ||
193 | |||
194 | static int | ||
195 | mime_context_get_temp_file (struct mime_context *ctx, char **ptr) | ||
196 | { | ||
197 | if (!ctx->temp_file) | ||
198 | { | ||
199 | int fd = mu_tempfile (NULL, &ctx->temp_file); | ||
200 | if (fd == -1) | ||
201 | return -1; | ||
202 | mime_context_write_input (ctx, fd); | ||
203 | close (fd); | ||
204 | ctx->unlink_temp_file = 1; | ||
205 | } | ||
206 | *ptr = ctx->temp_file; | ||
207 | return 0; | ||
208 | } | ||
209 | |||
210 | |||
211 | static struct obstack expand_stack; | ||
212 | |||
213 | static int | ||
214 | expand_string (struct mime_context *ct, char **pstr) | ||
215 | { | ||
216 | char *p, *s; | ||
217 | int rc = 0; | ||
218 | |||
219 | for (p = *pstr; *p; ) | ||
220 | { | ||
221 | switch (p[0]) | ||
222 | { | ||
223 | case '%': | ||
224 | switch (p[1]) | ||
225 | { | ||
226 | case 's': | ||
227 | mime_context_get_temp_file (ct, &s); | ||
228 | obstack_grow (&expand_stack, s, strlen (s)); | ||
229 | rc = 1; | ||
230 | p += 2; | ||
231 | break; | ||
232 | |||
233 | case 't': | ||
234 | mime_context_get_content_type (ct, &s); | ||
235 | obstack_grow (&expand_stack, s, strlen (s)); | ||
236 | p += 2; | ||
237 | break; | ||
238 | |||
239 | case '{': | ||
240 | { | ||
241 | size_t n; | ||
242 | char *q = ++p; | ||