small reorg.
[apps/madmutt.git] / lib-mime / mime.c
1 /*
2  *  This program is free software; you can redistribute it and/or modify
3  *  it under the terms of the GNU General Public License as published by
4  *  the Free Software Foundation; either version 2 of the License, or (at
5  *  your option) any later version.
6  *
7  *  This program is distributed in the hope that it will be useful, but
8  *  WITHOUT ANY WARRANTY; without even the implied warranty of
9  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
10  *  General Public License for more details.
11  *
12  *  You should have received a copy of the GNU General Public License
13  *  along with this program; if not, write to the Free Software
14  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
15  *  MA 02110-1301, USA.
16  *
17  *  Copyright © 2006 Pierre Habouzit
18  */
19 /*
20  * Copyright notice from original mutt:
21  * Copyright (C) 1996-2000 Michael R. Elkins <me@mutt.org>
22  * Copyright (C) 1999-2000 Thomas Roessler <roessler@does-not-exist.org>
23  */
24
25 #include <lib-lib/lib-lib.h>
26
27 #include "mime.h"
28
29 #define BOUNDARYLEN 16
30
31 const char MimeSpecials[] = "@.,;:<>[]\\\"()?/= \t";
32
33 const char *BodyTypes[] = {
34     "x-unknown",
35     "audio",
36     "application",
37     "image",
38     "message",
39     "model",
40     "multipart",
41     "text",
42     "video",
43 };
44
45 const char *BodyEncodings[] = {
46     "x-unknown",
47     "7bit",
48     "8bit",
49     "quoted-printable",
50     "base64",
51     "binary",
52     "x-uuencoded",
53 };
54
55 /****************************************************************************/
56 /* rfc822 header parameters                                                 */
57 /****************************************************************************/
58
59 char *parameter_getval(parameter_t *parm, const char *s)
60 {
61     while (parm) {
62         if (!ascii_strcasecmp(parm->attribute, s))
63             return parm->value;
64         parm = parm->next;
65     }
66     return NULL;
67 }
68
69 void parameter_setval(parameter_t **p, const char *attribute, const char *value)
70 {
71     while (*p) {
72         if (!ascii_strcasecmp(attribute, (*p)->attribute)) {
73             if (value) {
74                 m_strreplace(&(*p)->value, value);
75             } else {
76                 parameter_t *q = parameter_list_pop(p);
77                 parameter_delete(&q);
78             }
79             return;
80         }
81         p = &(*p)->next;
82     }
83
84     if (value) {
85         (*p) = parameter_new();
86         (*p)->attribute = m_strdup(attribute);
87         (*p)->value = m_strdup(value);
88     }
89 }
90
91 void parameter_delval(parameter_t **p, const char *attribute)
92 {
93     while (*p) {
94         if (!ascii_strcasecmp(attribute, (*p)->attribute)) {
95             parameter_t *q = parameter_list_pop(p);
96             parameter_delete(&q);
97             return;
98         }
99
100         p = &(*p)->next;
101     }
102 }
103
104 int parameter_equal(const parameter_t *p1, const parameter_t *p2)
105 {
106     while (p1 && p2) {
107         if (m_strcmp(p1->attribute, p2->attribute)
108         ||  m_strcmp(p1->value, p2->value))
109             return 0;
110
111         p1 = p1->next;
112         p2 = p2->next;
113     }
114
115     if (p1 || p2)
116         return 0;
117
118     return 1;
119 }
120
121 void parameter_set_boundary(parameter_t **parm)
122 {
123     char rs[BOUNDARYLEN + 1];
124     int i;
125
126     for (i = 0; i < BOUNDARYLEN; i++) {
127         rs[i] = __m_b64chars[lrand48() % sizeof(__m_b64chars)];
128     }
129     rs[BOUNDARYLEN] = '\0';
130
131     parameter_setval(parm, "boundary", rs);
132 }
133
134
135 /****************************************************************************/
136 /* XXX                                                                      */
137 /****************************************************************************/
138
139 void envelope_wipe(ENVELOPE *p)
140 {
141     address_list_wipe(&p->return_path);
142     address_list_wipe(&p->from);
143     address_list_wipe(&p->to);
144     address_list_wipe(&p->cc);
145     address_list_wipe(&p->bcc);
146     address_list_wipe(&p->sender);
147     address_list_wipe(&p->reply_to);
148     address_list_wipe(&p->mail_followup_to);
149
150     p_delete(&p->list_post);
151     p_delete(&p->subject);
152     /* real_subj is just an offset to subject and shouldn't be freed */
153     p_delete(&p->message_id);
154     p_delete(&p->supersedes);
155     p_delete(&p->date);
156     p_delete(&p->x_label);
157     p_delete(&p->organization);
158 #ifdef USE_NNTP
159     p_delete(&p->newsgroups);
160     p_delete(&p->xref);
161     p_delete(&p->followup_to);
162     p_delete(&p->x_comment_to);
163 #endif
164
165     mutt_buffer_free (&p->spam);
166     string_list_wipe(&p->references);
167     string_list_wipe(&p->in_reply_to);
168     string_list_wipe(&p->userhdrs);
169 }
170
171 void body_wipe(BODY *b)
172 {
173     if (b->parameter)
174         parameter_list_wipe(&b->parameter);
175
176     if (b->unlink && b->filename) {
177         unlink (b->filename);
178     }
179
180     p_delete(&b->filename);
181     p_delete(&b->content);
182     p_delete(&b->xtype);
183     p_delete(&b->subtype);
184     p_delete(&b->description);
185     p_delete(&b->form_name);
186
187     if (b->hdr) {
188         /* Don't free twice (b->hdr->content = b->parts) */
189         b->hdr->content = NULL;
190         header_delete(&b->hdr);
191     }
192
193     if (b->parts)
194         body_list_wipe(&b->parts);
195 }
196
197 void header_wipe(HEADER *h)
198 {
199     envelope_delete(&h->env);
200     body_list_wipe(&h->content);
201     p_delete(&h->maildir_flags);
202     p_delete(&h->tree);
203     p_delete(&h->path);
204     string_list_wipe(&h->chain);
205     p_delete(&h->data);
206 }
207
208
209 /****************************************************************************/
210 /* misc functions                                                           */
211 /****************************************************************************/
212
213 int mutt_is_message_type(BODY *b)
214 {
215     int tok;
216
217     if (b->type != TYPEMESSAGE)
218         return 0;
219
220     tok = mime_which_token(b->subtype, -1);
221     return tok == MIME_RFC822 || tok == MIME_NEWS;
222 }
223
224 int mutt_is_text_part(BODY * b)
225 {
226     char *s = b->subtype;
227
228     if (mutt_is_application_pgp(b))
229         return 0;
230
231     switch (b->type) {
232       case TYPETEXT:
233         return 1;
234
235       case TYPEMESSAGE:
236         return mime_which_token(s, -1) == MIME_DELIVERY_STATUS;
237
238       case TYPEAPPLICATION:
239         return mime_which_token(s, -1) == MIME_PGP_KEYS;
240
241       default:
242         return 0;
243     }
244 }
245
246 #include "mutt.h"
247
248 int url_parse_mailto(ENVELOPE *e, char **body, const char *src)
249 {
250     char *t;
251     char *tmp;
252     char *headers;
253     char *tag, *value;
254     char scratch[HUGE_STRING];
255
256     int taglen;
257
258     string_list_t **last = &e->userhdrs;
259
260     if (!(t = strchr (src, ':')))
261         return -1;
262
263     if ((tmp = m_strdup(t + 1)) == NULL)
264         return -1;
265
266     if ((headers = strchr (tmp, '?')))
267         *headers++ = '\0';
268
269     url_decode(tmp);
270     e->to = rfc822_parse_adrlist(e->to, tmp);
271
272     tag = headers ? strtok (headers, "&") : NULL;
273
274     for (; tag; tag = strtok(NULL, "&")) {
275         if ((value = strchr (tag, '=')))
276             *value++ = '\0';
277         if (!value || !*value)
278             continue;
279
280         url_decode (tag);
281         url_decode (value);
282
283         if (mime_which_token(tag, -1) == MIME_BODY) {
284             if (body)
285                 m_strreplace(body, value);
286         } else {
287 #define SAFEPFX (option(OPTSTRICTMAILTO) ? "" : "X-Mailto-")
288             taglen = m_strlen(tag) + strlen(SAFEPFX);
289             /* mutt_parse_rfc822_line makes some assumptions */
290             snprintf(scratch, sizeof(scratch), "%s%s: %s", SAFEPFX, tag, value);
291 #undef SAVEPFX
292             scratch[taglen] = '\0';
293             value = vskipspaces(&scratch[taglen + 1]);
294             last  = mutt_parse_rfc822_line (e, NULL, scratch, value, 0, 0, last);
295             /* if $strict_mailto is set, force editing headers to let
296              * users have a look at what we got */
297             if (!option (OPTSTRICTMAILTO)) {
298                 set_option (OPTXMAILTO);
299                 set_option (OPTEDITHDRS);
300             }
301         }
302     }
303
304     p_delete(&tmp);
305     return 0;
306 }