9abea0b29fbb2c1ac5dd32663e00041ab8655512
[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_text_part(BODY * b)
214 {
215     char *s = b->subtype;
216
217     if (mutt_is_application_pgp(b))
218         return 0;
219
220     switch (b->type) {
221       case TYPETEXT:
222         return 1;
223
224       case TYPEMESSAGE:
225         return mime_which_token(s, -1) == MIME_DELIVERY_STATUS;
226
227       case TYPEAPPLICATION:
228         return mime_which_token(s, -1) == MIME_PGP_KEYS;
229
230       default:
231         return 0;
232     }
233 }
234
235 #include "mutt.h"
236
237 int url_parse_mailto(ENVELOPE *e, char **body, const char *src)
238 {
239     char *t;
240     char *tmp;
241     char *headers;
242     char *tag, *value;
243     char scratch[HUGE_STRING];
244
245     int taglen;
246
247     string_list_t **last = &e->userhdrs;
248
249     if (!(t = strchr (src, ':')))
250         return -1;
251
252     if ((tmp = m_strdup(t + 1)) == NULL)
253         return -1;
254
255     if ((headers = strchr (tmp, '?')))
256         *headers++ = '\0';
257
258     url_decode(tmp);
259     e->to = rfc822_parse_adrlist(e->to, tmp);
260
261     tag = headers ? strtok (headers, "&") : NULL;
262
263     for (; tag; tag = strtok(NULL, "&")) {
264         if ((value = strchr (tag, '=')))
265             *value++ = '\0';
266         if (!value || !*value)
267             continue;
268
269         url_decode (tag);
270         url_decode (value);
271
272         if (mime_which_token(tag, -1) == MIME_BODY) {
273             if (body)
274                 m_strreplace(body, value);
275         } else {
276 #define SAFEPFX (option(OPTSTRICTMAILTO) ? "" : "X-Mailto-")
277             taglen = m_strlen(tag) + strlen(SAFEPFX);
278             /* mutt_parse_rfc822_line makes some assumptions */
279             snprintf(scratch, sizeof(scratch), "%s%s: %s", SAFEPFX, tag, value);
280 #undef SAVEPFX
281             scratch[taglen] = '\0';
282             value = vskipspaces(&scratch[taglen + 1]);
283             last  = mutt_parse_rfc822_line (e, NULL, scratch, value, 0, 0, last);
284             /* if $strict_mailto is set, force editing headers to let
285              * users have a look at what we got */
286             if (!option (OPTSTRICTMAILTO)) {
287                 set_option (OPTXMAILTO);
288                 set_option (OPTEDITHDRS);
289             }
290         }
291     }
292
293     p_delete(&tmp);
294     return 0;
295 }