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