ctors/dtors for BODY's
[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 #include <lib-lib/ascii.h>
21 #include <lib-lib/url.h>
22
23 #include "mime.h"
24
25 #include "mutt.h"
26
27 #define BOUNDARYLEN 16
28
29 const char MimeSpecials[] = "@.,;:<>[]\\\"()?/= \t";
30
31 const char *BodyTypes[] = {
32     "x-unknown",
33     "audio",
34     "application",
35     "image",
36     "message",
37     "model",
38     "multipart",
39     "text",
40     "video",
41 };
42
43 const char *BodyEncodings[] = {
44     "x-unknown",
45     "7bit",
46     "8bit",
47     "quoted-printable",
48     "base64",
49     "binary",
50     "x-uuencoded",
51 };
52
53 /****************************************************************************/
54 /* rfc822 header parameters                                                 */
55 /****************************************************************************/
56
57 char *parameter_getval(parameter_t *parm, const char *s)
58 {
59     while (parm) {
60         if (!ascii_strcasecmp(parm->attribute, s))
61             return parm->value;
62         parm = parm->next;
63     }
64     return NULL;
65 }
66
67 void parameter_setval(parameter_t **p, const char *attribute, const char *value)
68 {
69     while (*p) {
70         if (!ascii_strcasecmp(attribute, (*p)->attribute)) {
71             if (value) {
72                 m_strreplace(&(*p)->value, value);
73             } else {
74                 parameter_t *q = parameter_list_pop(p);
75                 parameter_delete(&q);
76             }
77             return;
78         }
79         p = &(*p)->next;
80     }
81
82     if (value) {
83         (*p) = parameter_new();
84         (*p)->attribute = m_strdup(attribute);
85         (*p)->value = m_strdup(value);
86     }
87 }
88
89 void parameter_delval(parameter_t **p, const char *attribute)
90 {
91     while (*p) {
92         if (!ascii_strcasecmp(attribute, (*p)->attribute)) {
93             parameter_t *q = parameter_list_pop(p);
94             parameter_delete(&q);
95             return;
96         }
97
98         p = &(*p)->next;
99     }
100 }
101
102 int parameter_equal(const parameter_t *p1, const parameter_t *p2)
103 {
104     while (p1 && p2) {
105         if (m_strcmp(p1->attribute, p2->attribute)
106         ||  m_strcmp(p1->value, p2->value))
107             return 0;
108
109         p1 = p1->next;
110         p2 = p2->next;
111     }
112
113     if (p1 || p2)
114         return 0;
115
116     return 1;
117 }
118
119 void parameter_set_boundary(parameter_t **parm)
120 {
121     char rs[BOUNDARYLEN + 1];
122     int i;
123
124     for (i = 0; i < BOUNDARYLEN; i++) {
125         rs[i] = __m_b64chars[lrand48() % sizeof(__m_b64chars)];
126     }
127     rs[BOUNDARYLEN] = '\0';
128
129     parameter_setval(parm, "boundary", rs);
130 }
131
132
133 /****************************************************************************/
134 /* XXX                                                                      */
135 /****************************************************************************/
136
137 void rfc1524_entry_wipe(rfc1524_entry *p)
138 {
139     p_delete(&p->command);
140     p_delete(&p->testcommand);
141     p_delete(&p->composecommand);
142     p_delete(&p->composetypecommand);
143     p_delete(&p->editcommand);
144     p_delete(&p->printcommand);
145     p_delete(&p->nametemplate);
146     p_delete(&p->convert);
147 }
148
149 void envelope_wipe(ENVELOPE *p)
150 {
151     address_list_wipe(&p->return_path);
152     address_list_wipe(&p->from);
153     address_list_wipe(&p->to);
154     address_list_wipe(&p->cc);
155     address_list_wipe(&p->bcc);
156     address_list_wipe(&p->sender);
157     address_list_wipe(&p->reply_to);
158     address_list_wipe(&p->mail_followup_to);
159
160     p_delete(&p->list_post);
161     p_delete(&p->subject);
162     /* real_subj is just an offset to subject and shouldn't be freed */
163     p_delete(&p->message_id);
164     p_delete(&p->supersedes);
165     p_delete(&p->date);
166     p_delete(&p->x_label);
167     p_delete(&p->organization);
168 #ifdef USE_NNTP
169     p_delete(&p->newsgroups);
170     p_delete(&p->xref);
171     p_delete(&p->followup_to);
172     p_delete(&p->x_comment_to);
173 #endif
174
175     mutt_buffer_free (&p->spam);
176     string_list_wipe(&p->references);
177     string_list_wipe(&p->in_reply_to);
178     string_list_wipe(&p->userhdrs);
179 }
180
181 void body_wipe(BODY *b)
182 {
183     if (b->parameter)
184         parameter_list_wipe(&b->parameter);
185
186     if (b->unlink && b->filename) {
187         unlink (b->filename);
188     }
189
190     p_delete(&b->filename);
191     p_delete(&b->content);
192     p_delete(&b->xtype);
193     p_delete(&b->subtype);
194     p_delete(&b->description);
195     p_delete(&b->form_name);
196
197     if (b->hdr) {
198         /* Don't free twice (b->hdr->content = b->parts) */
199         b->hdr->content = NULL;
200         header_delete(&b->hdr);
201     }
202
203     if (b->parts)
204         body_list_wipe(&b->parts);
205 }
206
207 void header_wipe(HEADER *h)
208 {
209     envelope_delete(&h->env);
210     body_list_wipe(&h->content);
211     p_delete(&h->maildir_flags);
212     p_delete(&h->tree);
213     p_delete(&h->path);
214 #ifdef MIXMASTER
215     string_list_wipe(&h->chain);
216 #endif
217     p_delete(&h->data);
218 }
219
220 int url_parse_mailto(ENVELOPE *e, char **body, const char *src)
221 {
222     char *t;
223     char *tmp;
224     char *headers;
225     char *tag, *value;
226     char scratch[HUGE_STRING];
227
228     int taglen;
229
230     string_list_t **last = &e->userhdrs;
231
232     if (!(t = strchr (src, ':')))
233         return -1;
234
235     if ((tmp = m_strdup(t + 1)) == NULL)
236         return -1;
237
238     if ((headers = strchr (tmp, '?')))
239         *headers++ = '\0';
240
241     url_decode(tmp);
242     e->to = rfc822_parse_adrlist (e->to, tmp);
243
244     tag = headers ? strtok (headers, "&") : NULL;
245
246     for (; tag; tag = strtok (NULL, "&")) {
247         if ((value = strchr (tag, '=')))
248             *value++ = '\0';
249         if (!value || !*value)
250             continue;
251
252         url_decode (tag);
253         url_decode (value);
254
255         if (!ascii_strcasecmp (tag, "body")) {
256             if (body)
257                 m_strreplace(body, value);
258         }
259         else {
260 #define SAFEPFX (option (OPTSTRICTMAILTO) ? "" : "X-Mailto-")
261             taglen = m_strlen(tag) + m_strlen(SAFEPFX);
262             /* mutt_parse_rfc822_line makes some assumptions */
263             snprintf (scratch, sizeof (scratch), "%s%s: %s", SAFEPFX, tag, value);
264 #undef SAVEPFX
265             scratch[taglen] = '\0';
266             value = vskipspaces(&scratch[taglen + 1]);
267             last = mutt_parse_rfc822_line (e, NULL, scratch, value, 0, 0, last);
268             /* if $strict_mailto is set, force editing headers to let
269              * users have a look at what we got */
270             if (!option (OPTSTRICTMAILTO)) {
271                 set_option (OPTXMAILTO);
272                 set_option (OPTEDITHDRS);
273             }
274         }
275     }
276
277     p_delete(&tmp);
278     return 0;
279 }