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