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