44463cb134c89367bc7bf892572b2d1d9b023d8f
[apps/madmutt.git] / url.c
1 /*
2  * Copyright (C) 2000 Thomas Roessler <roessler@does-not-exist.org>
3  * 
4  *     This program 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 of the License, or
7  *     (at your option) any later version.
8  * 
9  *     This program 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 this program; if not, write to the Free Software
16  *     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
17  */
18
19 /*
20  * A simple URL parser.
21  */
22
23 #if HAVE_CONFIG_H
24 # include "config.h"
25 #endif
26
27 #include "mutt.h"
28 #include "mapping.h"
29 #include "url.h"
30
31 #include "mime.h"
32
33 #include <ctype.h>
34
35 static struct mapping_t UrlMap[] = {
36   {"file", U_FILE},
37   {"imap", U_IMAP},
38   {"imaps", U_IMAPS},
39   {"pop", U_POP},
40   {"pops", U_POPS},
41   {"nntp", U_NNTP},
42   {"nntps", U_NNTPS},
43   {"snews", U_NNTPS},
44   {"mailto", U_MAILTO},
45   {NULL, U_UNKNOWN}
46 };
47
48
49 static void url_pct_decode (char *s)
50 {
51   char *d;
52
53   if (!s)
54     return;
55
56   for (d = s; *s; s++) {
57     if (*s == '%' && s[1] && s[2] &&
58         isxdigit ((unsigned char) s[1]) &&
59         isxdigit ((unsigned char) s[2]) &&
60         hexval (s[1]) >= 0 && hexval (s[2]) >= 0) {
61       *d++ = (hexval (s[1]) << 4) | (hexval (s[2]));
62       s += 2;
63     }
64     else
65       *d++ = *s;
66   }
67   *d = '\0';
68 }
69
70 url_scheme_t url_check_scheme (const char *s)
71 {
72   char sbuf[STRING];
73   char *t;
74   int i;
75
76   if (!s || !(t = strchr (s, ':')))
77     return U_UNKNOWN;
78   if ((t - s) + 1 >= sizeof (sbuf))
79     return U_UNKNOWN;
80
81   strfcpy (sbuf, s, t - s + 1);
82   for (t = sbuf; *t; t++)
83     *t = ascii_tolower (*t);
84
85   if ((i = mutt_getvaluebyname (sbuf, UrlMap)) == -1)
86     return U_UNKNOWN;
87   else
88     return (url_scheme_t) i;
89 }
90
91 int url_parse_file (char *d, const char *src, size_t dl)
92 {
93   if (ascii_strncasecmp (src, "file:", 5))
94     return -1;
95   else if (!ascii_strncasecmp (src, "file://", 7))      /* we don't support remote files */
96     return -1;
97   else
98     strfcpy (d, src + 5, dl);
99
100   url_pct_decode (d);
101   return 0;
102 }
103
104 /* ciss_parse_userhost: fill in components of ciss with info from src. Note
105  *   these are pointers into src, which is altered with '\0's. Port of 0
106  *   means no port given. */
107 static char *ciss_parse_userhost (ciss_url_t * ciss, char *src)
108 {
109   char *t;
110   char *p;
111   char *path;
112
113   ciss->user = NULL;
114   ciss->pass = NULL;
115   ciss->host = NULL;
116   ciss->port = 0;
117
118   if (strncmp (src, "//", 2))
119     return src;
120
121   src += 2;
122
123   if ((path = strchr (src, '/')))
124     *path++ = '\0';
125
126   if ((t = strrchr (src, '@'))) {
127     *t = '\0';
128     if ((p = strchr (src, ':'))) {
129       *p = '\0';
130       ciss->pass = p + 1;
131       url_pct_decode (ciss->pass);
132     }
133     ciss->user = src;
134     url_pct_decode (ciss->user);
135     t++;
136   }
137   else
138     t = src;
139
140   if ((p = strchr (t, ':'))) {
141     *p++ = '\0';
142     ciss->port = atoi (p);
143   }
144   else
145     ciss->port = 0;
146
147   ciss->host = t;
148   url_pct_decode (ciss->host);
149   return path;
150 }
151
152 /* url_parse_ciss: Fill in ciss_url_t. char* elements are pointers into src,
153  *   which is modified by this call (duplicate it first if you need to). */
154 int url_parse_ciss (ciss_url_t * ciss, char *src)
155 {
156   char *tmp;
157
158   if ((ciss->scheme = url_check_scheme (src)) == U_UNKNOWN)
159     return -1;
160
161   tmp = strchr (src, ':') + 1;
162
163   ciss->path = ciss_parse_userhost (ciss, tmp);
164   url_pct_decode (ciss->path);
165
166   return 0;
167 }
168
169 /* url_ciss_tostring: output the URL string for a given CISS object. */
170
171 int url_ciss_tostring (ciss_url_t * ciss, char *dest, size_t len, int flags)
172 {
173   long l;
174
175   if (ciss->scheme == U_UNKNOWN)
176     return -1;
177
178   snprintf (dest, len, "%s:", mutt_getnamebyvalue (ciss->scheme, UrlMap));
179
180   if (ciss->host) {
181     safe_strcat (dest, len, "//");
182     len -= (l = strlen (dest));
183     dest += l;
184
185     if (ciss->user) {
186       if (flags & U_DECODE_PASSWD && ciss->pass)
187         snprintf (dest, len, "%s:%s@", ciss->user, ciss->pass);
188       else
189         snprintf (dest, len, "%s@", ciss->user);
190
191       len -= (l = strlen (dest));
192       dest += l;
193     }
194
195     if (ciss->port)
196       snprintf (dest, len, "%s:%hu/", ciss->host, ciss->port);
197     else
198       snprintf (dest, len, "%s/", ciss->host);
199   }
200
201   if (ciss->path)
202     safe_strcat (dest, len, ciss->path);
203
204   return 0;
205 }
206
207 int url_parse_mailto (ENVELOPE * e, char **body, const char *src)
208 {
209   char *t;
210   char *tmp;
211   char *headers;
212   char *tag, *value;
213   char scratch[HUGE_STRING];
214
215   int taglen;
216
217   LIST *last = NULL;
218
219   if (!(t = strchr (src, ':')))
220     return -1;
221
222   if ((tmp = safe_strdup (t + 1)) == NULL)
223     return -1;
224
225   if ((headers = strchr (tmp, '?')))
226     *headers++ = '\0';
227
228   url_pct_decode (tmp);
229   e->to = rfc822_parse_adrlist (e->to, tmp);
230
231   tag = headers ? strtok (headers, "&") : NULL;
232
233   for (; tag; tag = strtok (NULL, "&")) {
234     if ((value = strchr (tag, '=')))
235       *value++ = '\0';
236     if (!value || !*value)
237       continue;
238
239     url_pct_decode (tag);
240     url_pct_decode (value);
241
242     if (!ascii_strcasecmp (tag, "body")) {
243       if (body)
244         mutt_str_replace (body, value);
245     }
246     else {
247       taglen = strlen (tag);
248       /* mutt_parse_rfc822_line makes some assumptions */
249       snprintf (scratch, sizeof (scratch), "%s: %s", tag, value);
250       scratch[taglen] = '\0';
251       value = &scratch[taglen + 1];
252       SKIPWS (value);
253       mutt_parse_rfc822_line (e, NULL, scratch, value, 1, 0, 0, &last);
254     }
255   }
256
257   FREE (&tmp);
258   return 0;
259 }