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