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