NeoMutt  2019-12-07-60-g0cfa53
Teaching an old dog new tricks
DOXYGEN
url.c File Reference

Parse and identify different URL schemes. More...

#include "config.h"
#include <ctype.h>
#include <string.h>
#include "mutt/mutt.h"
#include "url.h"
#include "mime.h"
+ Include dependency graph for url.c:

Go to the source code of this file.

Functions

static int parse_query_string (struct UrlQueryList *list, char *src)
 Parse a URL query string. More...
 
int url_pct_decode (char *s)
 Decode a percent-encoded string. More...
 
enum UrlScheme url_check_scheme (const char *s)
 Check the protocol of a URL. More...
 
struct Urlurl_parse (const char *src)
 Fill in Url. More...
 
void url_free (struct Url **u)
 Free the contents of a URL. More...
 
void url_pct_encode (char *buf, size_t buflen, const char *src)
 Percent-encode a string. More...
 
int url_tobuffer (struct Url *u, struct Buffer *buf, int flags)
 Output the URL string for a given Url object. More...
 
int url_tostring (struct Url *u, char *dest, size_t len, int flags)
 Output the URL string for a given Url object. More...
 

Variables

static const struct Mapping UrlMap []
 Constants for URL protocols. More...
 

Detailed Description

Parse and identify different URL schemes.

Authors
  • Thomas Roessler

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.

Definition in file url.c.

Function Documentation

◆ parse_query_string()

static int parse_query_string ( struct UrlQueryList *  list,
char *  src 
)
static

Parse a URL query string.

Parameters
listList to store the results
srcString to parse
Return values
0Success
-1Error

Definition at line 53 of file url.c.

54 {
55  struct UrlQuery *qs = NULL;
56  char *k = NULL, *v = NULL;
57 
58  while (src && *src)
59  {
60  qs = mutt_mem_calloc(1, sizeof(struct UrlQuery));
61  k = strchr(src, '&');
62  if (k)
63  *k = '\0';
64 
65  v = strchr(src, '=');
66  if (v)
67  {
68  *v = '\0';
69  qs->value = v + 1;
70  if (url_pct_decode(qs->value) < 0)
71  {
72  FREE(&qs);
73  return -1;
74  }
75  }
76  qs->name = src;
77  if (url_pct_decode(qs->name) < 0)
78  {
79  FREE(&qs);
80  return -1;
81  }
82  STAILQ_INSERT_TAIL(list, qs, entries);
83 
84  if (!k)
85  break;
86  src = k + 1;
87  }
88  return 0;
89 }
char * name
Query name.
Definition: url.h:57
int url_pct_decode(char *s)
Decode a percent-encoded string.
Definition: url.c:100
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
Parsed Query String.
Definition: url.h:55
#define STAILQ_INSERT_TAIL(head, elm, field)
Definition: queue.h:386
char * value
Query value.
Definition: url.h:58
#define FREE(x)
Definition: memory.h:40
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ url_pct_decode()

int url_pct_decode ( char *  s)

Decode a percent-encoded string.

Parameters
sString to decode
Return values
0Success
-1Error

e.g. turn "hello%20world" into "hello world" The string is decoded in-place.

Definition at line 100 of file url.c.

101 {
102  if (!s)
103  return -1;
104 
105  char *d = NULL;
106 
107  for (d = s; *s; s++)
108  {
109  if (*s == '%')
110  {
111  if ((s[1] != '\0') && (s[2] != '\0') && isxdigit((unsigned char) s[1]) &&
112  isxdigit((unsigned char) s[2]) && (hexval(s[1]) >= 0) && (hexval(s[2]) >= 0))
113  {
114  *d++ = (hexval(s[1]) << 4) | (hexval(s[2]));
115  s += 2;
116  }
117  else
118  return -1;
119  }
120  else
121  *d++ = *s;
122  }
123  *d = '\0';
124  return 0;
125 }
#define hexval(ch)
Definition: mime.h:75
+ Here is the caller graph for this function:

◆ url_check_scheme()

enum UrlScheme url_check_scheme ( const char *  s)

Check the protocol of a URL.

Parameters
sString to check
Return values
numUrl type, e.g. U_IMAPS

Definition at line 132 of file url.c.

133 {
134  char sbuf[256];
135  char *t = NULL;
136  int i;
137 
138  if (!s || !(t = strchr(s, ':')))
139  return U_UNKNOWN;
140  if ((size_t)(t - s) >= (sizeof(sbuf) - 1))
141  return U_UNKNOWN;
142 
143  mutt_str_strfcpy(sbuf, s, t - s + 1);
144  mutt_str_strlower(sbuf);
145 
146  i = mutt_map_get_value(sbuf, UrlMap);
147  if (i == -1)
148  return U_UNKNOWN;
149 
150  return (enum UrlScheme) i;
151 }
Url wasn&#39;t recognised.
Definition: url.h:34
char * mutt_str_strlower(char *s)
convert all characters in the string to lowercase
Definition: string.c:509
UrlScheme
All recognised Url types.
Definition: url.h:32
size_t mutt_str_strfcpy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:750
static const struct Mapping UrlMap[]
Constants for URL protocols.
Definition: url.c:39
int mutt_map_get_value(const char *name, const struct Mapping *map)
Lookup the constant for a string.
Definition: mapping.c:61
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ url_parse()

struct Url* url_parse ( const char *  src)

Fill in Url.

Parameters
srcString to parse
Return values
ptrPointer to the parsed URL
NULLString is invalid

To free Url, caller must call url_free()

Definition at line 161 of file url.c.

162 {
163  if (!src || !*src)
164  return NULL;
165 
166  enum UrlScheme scheme = url_check_scheme(src);
167  if (scheme == U_UNKNOWN)
168  return NULL;
169 
170  char *p = NULL;
171  size_t srcsize = strlen(src) + 1;
172  struct Url *u = mutt_mem_calloc(1, sizeof(struct Url) + srcsize);
173 
174  u->scheme = scheme;
175  u->user = NULL;
176  u->pass = NULL;
177  u->host = NULL;
178  u->port = 0;
179  u->path = NULL;
181  u->src = (char *) u + sizeof(struct Url);
182  mutt_str_strfcpy(u->src, src, srcsize);
183 
184  char *it = u->src;
185 
186  it = strchr(it, ':') + 1;
187 
188  if (strncmp(it, "//", 2) != 0)
189  {
190  u->path = it;
191  if (url_pct_decode(u->path) < 0)
192  {
193  url_free(&u);
194  }
195  return u;
196  }
197 
198  it += 2;
199 
200  /* We have the length of the string, so let's be fancier than strrchr */
201  for (char *q = u->src + srcsize - 1; q >= it; --q)
202  {
203  if (*q == '?')
204  {
205  *q = '\0';
206  if (parse_query_string(&u->query_strings, q + 1) < 0)
207  {
208  goto err;
209  }
210  break;
211  }
212  }
213 
214  u->path = strchr(it, '/');
215  if (u->path)
216  {
217  *u->path++ = '\0';
218  if (url_pct_decode(u->path) < 0)
219  goto err;
220  }
221 
222  char *at = strrchr(it, '@');
223  if (at)
224  {
225  *at = '\0';
226  p = strchr(it, ':');
227  if (p)
228  {
229  *p = '\0';
230  u->pass = p + 1;
231  if (url_pct_decode(u->pass) < 0)
232  goto err;
233  }
234  u->user = it;
235  if (url_pct_decode(u->user) < 0)
236  goto err;
237  it = at + 1;
238  }
239 
240  /* IPv6 literal address. It may contain colons, so set p to start the port
241  * scan after it. */
242  if ((*it == '[') && (p = strchr(it, ']')))
243  {
244  it++;
245  *p++ = '\0';
246  }
247  else
248  p = it;
249 
250  p = strchr(p, ':');
251  if (p)
252  {
253  int num;
254  *p++ = '\0';
255  if ((mutt_str_atoi(p, &num) < 0) || (num < 0) || (num > 0xffff))
256  goto err;
257  u->port = (unsigned short) num;
258  }
259  else
260  u->port = 0;
261 
262  if (mutt_str_strlen(it) != 0)
263  {
264  u->host = it;
265  if (url_pct_decode(u->host) < 0)
266  goto err;
267  }
268  else if (u->path)
269  {
270  /* No host are provided, we restore the / because this is absolute path */
271  u->path = it;
272  *it++ = '/';
273  }
274 
275  return u;
276 
277 err:
278  url_free(&u);
279  return NULL;
280 }
int url_pct_decode(char *s)
Decode a percent-encoded string.
Definition: url.c:100
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
int mutt_str_atoi(const char *str, int *dst)
Convert ASCII string to an integer.
Definition: string.c:262
char * pass
Password.
Definition: url.h:70
A parsed URL proto://user:password@host:port/path?a=1&b=2
Definition: url.h:66
enum UrlScheme scheme
Scheme, e.g. U_SMTPS.
Definition: url.h:68
Url wasn&#39;t recognised.
Definition: url.h:34
size_t mutt_str_strlen(const char *a)
Calculate the length of a string, safely.
Definition: string.c:666
enum UrlScheme url_check_scheme(const char *s)
Check the protocol of a URL.
Definition: url.c:132
#define STAILQ_INIT(head)
Definition: queue.h:369
UrlScheme
All recognised Url types.
Definition: url.h:32
struct UrlQueryList query_strings
List of query strings.
Definition: url.h:74
char * user
Username.
Definition: url.h:69
size_t mutt_str_strfcpy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:750
char * host
Host.
Definition: url.h:71
static int parse_query_string(struct UrlQueryList *list, char *src)
Parse a URL query string.
Definition: url.c:53
char * path
Path.
Definition: url.h:73
unsigned short port
Port.
Definition: url.h:72
void url_free(struct Url **u)
Free the contents of a URL.
Definition: url.c:288
char * src
Raw URL string.
Definition: url.h:75
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ url_free()

void url_free ( struct Url **  u)

Free the contents of a URL.

Parameters
[out]uUrl to empty
Note
The Url itself is not freed

Definition at line 288 of file url.c.

289 {
290  if (!u || !*u)
291  return;
292 
293  struct UrlQuery *np = STAILQ_FIRST(&(*u)->query_strings);
294  struct UrlQuery *next = NULL;
295  while (np)
296  {
297  next = STAILQ_NEXT(np, entries);
298  /* NOTE(sileht): We don't free members, they will be freed when
299  * the src char* passed to url_parse() is freed */
300  FREE(&np);
301  np = next;
302  }
303  STAILQ_INIT(&(*u)->query_strings);
304  FREE(u);
305 }
Parsed Query String.
Definition: url.h:55
#define STAILQ_INIT(head)
Definition: queue.h:369
#define STAILQ_NEXT(elm, field)
Definition: queue.h:397
#define FREE(x)
Definition: memory.h:40
#define STAILQ_FIRST(head)
Definition: queue.h:347
+ Here is the caller graph for this function:

◆ url_pct_encode()

void url_pct_encode ( char *  buf,
size_t  buflen,
const char *  src 
)

Percent-encode a string.

Parameters
bufBuffer for the result
buflenLength of buffer
srcString to encode

e.g. turn "hello world" into "hello%20world"

Definition at line 315 of file url.c.

316 {
317  static const char *hex = "0123456789ABCDEF";
318 
319  if (!buf)
320  return;
321 
322  *buf = '\0';
323  buflen--;
324  while (src && *src && (buflen != 0))
325  {
326  if (strchr("/:&%", *src))
327  {
328  if (buflen < 3)
329  break;
330 
331  *buf++ = '%';
332  *buf++ = hex[(*src >> 4) & 0xf];
333  *buf++ = hex[*src & 0xf];
334  src++;
335  buflen -= 3;
336  continue;
337  }
338  *buf++ = *src++;
339  buflen--;
340  }
341  *buf = '\0';
342 }
+ Here is the caller graph for this function:

◆ url_tobuffer()

int url_tobuffer ( struct Url u,
struct Buffer buf,
int  flags 
)

Output the URL string for a given Url object.

Parameters
uUrl to turn into a string
bufBuffer for the result
flagsFlags, e.g. U_PATH
Return values
0Success
-1Error

Definition at line 352 of file url.c.

353 {
354  if (!u || !buf)
355  return -1;
356  if (u->scheme == U_UNKNOWN)
357  return -1;
358 
360 
361  if (u->host)
362  {
363  if (!(flags & U_PATH))
364  mutt_buffer_addstr(buf, "//");
365 
366  if (u->user && (u->user[0] || !(flags & U_PATH)))
367  {
368  char str[256];
369  url_pct_encode(str, sizeof(str), u->user);
370  mutt_buffer_add_printf(buf, "%s@", str);
371  }
372 
373  if (strchr(u->host, ':'))
374  mutt_buffer_add_printf(buf, "[%s]", u->host);
375  else
376  mutt_buffer_add_printf(buf, "%s", u->host);
377 
378  if (u->port)
379  mutt_buffer_add_printf(buf, ":%hu/", u->port);
380  else
381  mutt_buffer_addstr(buf, "/");
382  }
383 
384  if (u->path)
385  mutt_buffer_addstr(buf, u->path);
386 
387  return 0;
388 }
enum UrlScheme scheme
Scheme, e.g. U_SMTPS.
Definition: url.h:68
Url wasn&#39;t recognised.
Definition: url.h:34
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:160
const char * mutt_map_get_name(int val, const struct Mapping *map)
Lookup a string for a constant.
Definition: mapping.c:42
int mutt_buffer_add_printf(struct Buffer *buf, const char *fmt,...)
Format a string appending a Buffer.
Definition: buffer.c:203
size_t mutt_buffer_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:225
void url_pct_encode(char *buf, size_t buflen, const char *src)
Percent-encode a string.
Definition: url.c:315
char * user
Username.
Definition: url.h:69
char * host
Host.
Definition: url.h:71
char * path
Path.
Definition: url.h:73
unsigned short port
Port.
Definition: url.h:72
static const struct Mapping UrlMap[]
Constants for URL protocols.
Definition: url.c:39
#define U_PATH
Definition: url.h:48
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ url_tostring()

int url_tostring ( struct Url u,
char *  dest,
size_t  len,
int  flags 
)

Output the URL string for a given Url object.

Parameters
uUrl to turn into a string
destBuffer for the result
lenLength of buffer
flagsFlags, e.g. U_PATH
Return values
0Success
-1Error

Definition at line 399 of file url.c.

400 {
401  if (!u || !dest)
402  return -1;
403 
404  struct Buffer *dest_buf = mutt_buffer_pool_get();
405 
406  int retval = url_tobuffer(u, dest_buf, flags);
407  if (retval == 0)
408  mutt_str_strfcpy(dest, mutt_b2s(dest_buf), len);
409 
410  mutt_buffer_pool_release(&dest_buf);
411 
412  return retval;
413 }
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
String manipulation buffer.
Definition: buffer.h:33
int url_tobuffer(struct Url *u, struct Buffer *buf, int flags)
Output the URL string for a given Url object.
Definition: url.c:352
#define mutt_b2s(buf)
Definition: buffer.h:41
size_t mutt_str_strfcpy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:750
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

Variable Documentation

◆ UrlMap

const struct Mapping UrlMap[]
static
Initial value:
= {
{ "file", U_FILE }, { "imap", U_IMAP }, { "imaps", U_IMAPS },
{ "pop", U_POP }, { "pops", U_POPS }, { "news", U_NNTP },
{ "snews", U_NNTPS }, { "mailto", U_MAILTO }, { "notmuch", U_NOTMUCH },
{ "smtp", U_SMTP }, { "smtps", U_SMTPS }, { NULL, U_UNKNOWN },
}
Url is notmuch://.
Definition: url.h:45
Url is imaps://.
Definition: url.h:39
Url wasn&#39;t recognised.
Definition: url.h:34
Url is imap://.
Definition: url.h:38
Url is nntps://.
Definition: url.h:41
Url is smtps://.
Definition: url.h:43
Url is pop://.
Definition: url.h:36
Url is nntp://.
Definition: url.h:40
Url is smtp://.
Definition: url.h:42
Url is mailto://.
Definition: url.h:44
Url is file://.
Definition: url.h:35
Url is pops://.
Definition: url.h:37

Constants for URL protocols.

Definition at line 39 of file url.c.