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