diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2010-10-26 13:00:52 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2010-10-26 13:36:28 +0300 |
commit | 3327a23a49e532c068972a0b2d64021361540f7b (patch) | |
tree | b2d6508005ac8343a54638142c4f8234f7202441 /libmailutils/url | |
parent | 6203ae65f53758a4b893e6e176be7c153a31bef0 (diff) | |
download | mailutils-3327a23a49e532c068972a0b2d64021361540f7b.tar.gz mailutils-3327a23a49e532c068972a0b2d64021361540f7b.tar.bz2 |
Rewrite URL support.
The purpose is to make it modular and flexible. URLs are
parsed out as they are created. Missing URL parts can be
supplied via a "URL hint" at creation time (similar to
the approach used in creating mu_address_t). Ports
can be specified either as numbers or as service names.
Original port string representation can be retrieved from
the URL, as well as its numeric value.
* libmailutils/url/accessor.h: New file.
* libmailutils/url/copy.c: New file.
* libmailutils/url/create.c: New file.
* libmailutils/url/decode.c: New file.
* libmailutils/url/destroy.c: New file.
* libmailutils/url/dup.c: New file.
* libmailutils/url/expand.c: New file.
* libmailutils/url/flag.c: New file.
* libmailutils/url/get-auth.c: New file.
* libmailutils/url/get-host.c: New file.
* libmailutils/url/get-param.c: New file.
* libmailutils/url/get-path.c: New file.
* libmailutils/url/get-portstr.c: New file.
* libmailutils/url/get-query.c: New file.
* libmailutils/url/get-scheme.c: New file.
* libmailutils/url/get-secret.c: New file.
* libmailutils/url/get-user.c: New file.
* libmailutils/url/match.c: New file.
* libmailutils/url/port.c: New file.
* libmailutils/url/scheme.c: New file.
* libmailutils/url/uplevel.c: New file.
* libmailutils/url/urlstr.c: New file.
* configure.ac (AC_CONFIG_FILES): Add libmailutils/url/Makefile
* libmailutils/Makefile.am (SUBDIRS): Add url.
(libmailutils_la_LIBADD): Link with liburl.
* libmailutils/base/Makefile.am (libbase_la_SOURCES): Remove url.c
* libmailutils/base/url.c: Remove.
* libmailutils/string/Makefile.am (libstring_la_SOURCES): Add xdecode.c
* libmailutils/string/xdecode.c: New file.
* include/mailutils/sys/url.h (_mu_url): Change type to short.
<_get_port>: Change second argument to unsigned.
<_get_portstr>: New method.
* include/mailutils/url.h (MU_URL_SCHEME): New flag.
(MU_URL_PARSE_HEXCODE, MU_URL_PARSE_HIDEPASS)
(MU_URL_PARSE_PORTSRV, MU_URL_PARSE_PORTWC)
(MU_URL_PARSE_PIPE, MU_URL_PARSE_SLASH): New flags.
(mu_url_create_hint, mu_url_copy_hints): New prototypes.
(mu_url_parse): Remove.
(mu_url_get_port): Change second argument to unsigned.
(mu_url_decode_len,mu_url_decode): Remove.
(mu_url_decode): New proto.
(mu_url_sget_portstr, mu_url_aget_portstr)
(mu_url_get_portstr): New protos.
* include/mailutils/util.h (mu_str_url_decode)
(mu_str_url_decode_inline): New protos.
* libproto/pop/mbox.c (pop_open): Port is unsigned.
* libproto/imap/folder.c: Use MU_URL_SCHEME in url_may_have.
* libproto/maildir/folder.c: Likewise.
* libproto/mailer/prog.c: Likewise.
* libproto/mailer/remote.c: Likewise.
* libproto/mailer/sendmail.c: Likewise.
* libproto/mailer/smtp.c: Likewise.
* libproto/mbox/folder.c: Likewise.
* libproto/mh/folder.c: Likewise.
* libproto/nntp/folder.c: Likewise.
* libproto/pop/folder.c: Likewise.
* imap4d/imap4d.c: Remove calls to mu_url_parse.
* libmailutils/base/registrar.c: Likewise.
* libmailutils/base/wicket.c: Likewise.
* libmailutils/mailbox/folder.c: Likewise.
* libmailutils/mailbox/mailbox.c: Likewise.
* libmailutils/mailer/mailer.c: Likewise.
* libmailutils/tests/url-parse.c: Likewise.
* libmailutils/tests/wicket.c: Likewise.
* libproto/mailer/smtp_auth.c: Likewise.
* maidag/deliver.c: Likewise.
* mu/wicket.c: Likewise.
* libmailutils/mime/mimehdr.c (mu_mimehdr_decode_param): Use
mu_str_url_decode, instead of mu_url_decode.
* libmailutils/stream/tcp.c (_tcp_instance)<port>: Change type
to unsigned short. All uses updated.
(mu_tcp_stream_create_with_source_ip)
(mu_tcp_stream_create_with_source_host)
(mu_tcp_stream_create): Port is unsigned.
* include/mailutils/stream.h (mu_tcp_stream_create_with_source_ip)
(mu_tcp_stream_create_with_source_host)
(mu_tcp_stream_create): Port is unsigned.
* include/mailutils/cpp/url.h (get_port): Return unsigned.
* libmu_cpp/url.cc (get_port): Return unsigned.
(parse): Empty function. Schedule for removal.
* python/libmu_py/url.c (api_url_parse): Empty function.
Schedule for removal.
(api_url_get_port): Port is unsigned.
* libmailutils/base/wicket.c (mu_wicket_file_match_url)
(mu_wicket_file_match_url): New parameter: parse_flags.
* mu/wicket.c (wicket_match): Use parse_flags to control
whether or not to show the plaintext password.
* doc/texinfo/url.texi: Update.
Diffstat (limited to 'libmailutils/url')
-rw-r--r-- | libmailutils/url/Makefile.am | 45 | ||||
-rw-r--r-- | libmailutils/url/accessor.h | 143 | ||||
-rw-r--r-- | libmailutils/url/copy.c | 145 | ||||
-rw-r--r-- | libmailutils/url/create.c | 525 | ||||
-rw-r--r-- | libmailutils/url/decode.c | 118 | ||||
-rw-r--r-- | libmailutils/url/destroy.c | 74 | ||||
-rw-r--r-- | libmailutils/url/dup.c | 56 | ||||
-rw-r--r-- | libmailutils/url/expand.c | 216 | ||||
-rw-r--r-- | libmailutils/url/flag.c | 40 | ||||
-rw-r--r-- | libmailutils/url/get-auth.c | 3 | ||||
-rw-r--r-- | libmailutils/url/get-host.c | 2 | ||||
-rw-r--r-- | libmailutils/url/get-param.c | 131 | ||||
-rw-r--r-- | libmailutils/url/get-path.c | 2 | ||||
-rw-r--r-- | libmailutils/url/get-portstr.c | 2 | ||||
-rw-r--r-- | libmailutils/url/get-query.c | 72 | ||||
-rw-r--r-- | libmailutils/url/get-scheme.c | 2 | ||||
-rw-r--r-- | libmailutils/url/get-secret.c | 44 | ||||
-rw-r--r-- | libmailutils/url/get-user.c | 2 | ||||
-rw-r--r-- | libmailutils/url/match.c | 102 | ||||
-rw-r--r-- | libmailutils/url/port.c | 53 | ||||
-rw-r--r-- | libmailutils/url/scheme.c | 55 | ||||
-rw-r--r-- | libmailutils/url/uplevel.c | 71 | ||||
-rw-r--r-- | libmailutils/url/urlstr.c | 31 |
23 files changed, 1934 insertions, 0 deletions
diff --git a/libmailutils/url/Makefile.am b/libmailutils/url/Makefile.am new file mode 100644 index 000000000..51e3e6483 --- /dev/null +++ b/libmailutils/url/Makefile.am @@ -0,0 +1,45 @@ +# GNU Mailutils -- a suite of utilities for electronic mail +# Copyright (C) 2010 Free Software Foundation, Inc. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 3 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General +# Public License along with this library. If not, see +# <http://www.gnu.org/licenses/>. + +noinst_LTLIBRARIES = liburl.la + +liburl_la_SOURCES = \ + accessor.h\ + copy.c\ + create.c\ + decode.c\ + destroy.c\ + dup.c\ + expand.c\ + flag.c\ + get-auth.c\ + get-host.c\ + get-param.c\ + get-path.c\ + get-portstr.c\ + get-query.c\ + get-scheme.c\ + get-secret.c\ + get-user.c\ + match.c\ + port.c\ + scheme.c\ + uplevel.c\ + urlstr.c + +INCLUDES = @MU_LIB_COMMON_INCLUDES@ -I/libmailutils + diff --git a/libmailutils/url/accessor.h b/libmailutils/url/accessor.h new file mode 100644 index 000000000..de3871152 --- /dev/null +++ b/libmailutils/url/accessor.h @@ -0,0 +1,143 @@ +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 2010 Free Software Foundation, Inc. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library. If not, see + <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#ifdef HAVE_STRINGS_H +# include <strings.h> +#endif + +#include <mailutils/types.h> +#include <mailutils/errno.h> +#include <mailutils/util.h> +#include <mailutils/cstr.h> +#include <mailutils/sys/url.h> + +/* General accessors: */ +#define AC2(a,b) a ## b +#define METHOD(pfx,part) AC2(pfx,part) +#define AC4(a,b,c,d) a ## b ## c ## d +#define ACCESSOR(action,field) AC4(mu_url_,action,_,field) + +/* Define a `static get' accessor */ +int +ACCESSOR(sget,URL_PART) (mu_url_t url, char const **sptr) +{ + if (url == NULL) + return EINVAL; + if (!url->URL_PART) + { + if (url->METHOD(_get_,URL_PART)) + { + size_t n; + char *buf; + + int status = url->METHOD(_get_,URL_PART) (url, NULL, 0, &n); + if (status) + return status; + + buf = malloc (n + 1); + if (!buf) + return ENOMEM; + + status = url->METHOD(_get_,URL_PART) (url, buf, n + 1, NULL); + if (status) + return status; + + if (buf[0]) + { + /* FIXME */ + status = mu_str_url_decode (&url->URL_PART, buf); + if (status) + { + free (buf); + return status; + } + } + else + url->URL_PART = buf; + if (!url->URL_PART) + return ENOMEM; + } + else + return MU_ERR_NOENT; + } + *sptr = url->URL_PART; + return 0; +} + +/* Define a `get' accessor */ +int +ACCESSOR(get,URL_PART) (mu_url_t url, char *buf, size_t len, size_t *n) +{ + size_t i; + const char *str; + int status = ACCESSOR(sget, URL_PART) (url, &str); + + if (status) + return status; + + i = mu_cpystr (buf, str, len); + if (n) + *n = i; + return 0; +} + +/* Define an `allocated get' accessor */ +int +ACCESSOR(aget, URL_PART) (mu_url_t url, char **buf) +{ + const char *str; + int status = ACCESSOR(sget, URL_PART) (url, &str); + + if (status) + return status; + + if (str) + { + *buf = strdup (str); + if (!*buf) + status = ENOMEM; + } + else + *buf = NULL; + return status; +} + +/* Define a comparator */ +int +ACCESSOR(is_same,URL_PART) (mu_url_t url1, mu_url_t url2) +{ + const char *s1, *s2; + int status1, status2; + + status1 = ACCESSOR(sget, URL_PART) (url1, &s1); + if (status1 && status1 != MU_ERR_NOENT) + return 0; + status2 = ACCESSOR(sget, URL_PART) (url2, &s2); + if (status2 && status2 != MU_ERR_NOENT) + return 0; + + if (status1 || status2) + return status1 == status2; /* Both fields are missing */ + return mu_c_strcasecmp (s1, s2) == 0; +} diff --git a/libmailutils/url/copy.c b/libmailutils/url/copy.c new file mode 100644 index 000000000..7190b4212 --- /dev/null +++ b/libmailutils/url/copy.c @@ -0,0 +1,145 @@ +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 2010 Free Software Foundation, Inc. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library. If not, see + <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <errno.h> +#include <string.h> +#ifdef HAVE_STRINGS_H +# include <strings.h> +#endif + +#include <mailutils/types.h> +#include <mailutils/argcv.h> +#include <mailutils/secret.h> +#include <mailutils/util.h> +#include <mailutils/sys/url.h> + +struct copy_tab +{ + int mask; + int (*fun) (mu_url_t, mu_url_t, size_t); + size_t off; +}; + +static int +_url_copy_str (mu_url_t dest_url, mu_url_t src_url, size_t off) +{ + char **dest = (char**) ((char*) dest_url + off); + char *src = *(char**) ((char*) src_url + off); + char *p = strdup (src); + if (!p) + return ENOMEM; + *dest = p; + return 0; +} + +static int +_url_copy_secret (mu_url_t dest, mu_url_t src, size_t off) +{ + return mu_secret_dup (src->secret, &dest->secret); +} + +static int +_url_copy_port (mu_url_t dest, mu_url_t src, size_t off) +{ + if (src->portstr) + { + dest->portstr = strdup (src->portstr); + if (!dest->portstr) + return ENOMEM; + } + dest->port = src->port; + return 0; +} + +static char ** +argcv_copy (size_t argc, char **argv) +{ + size_t i; + char **nv = calloc (argc + 1, sizeof (nv[0])); + if (!nv) + return NULL; + for (i = 0; i < argc; i++) + if ((nv[i] = strdup (argv[i])) == NULL) + { + mu_argcv_free (i, nv); + free (nv); + return NULL; + } + return nv; +} + +static int +_url_copy_param (mu_url_t dest, mu_url_t src, size_t off) +{ + if ((dest->fvpairs = argcv_copy (src->fvcount, src->fvpairs)) == NULL) + return ENOMEM; + dest->fvcount = src->fvcount; + return 0; +} + +static int +_url_copy_query (mu_url_t dest, mu_url_t src, size_t off) +{ + if ((dest->qargv = argcv_copy (src->qargc, src->qargv)) == NULL) + return ENOMEM; + dest->qargc = src->qargc; + return 0; +} + +static struct copy_tab copy_tab[] = { + { MU_URL_SCHEME, _url_copy_str, mu_offsetof (struct _mu_url, scheme) }, + { MU_URL_USER, _url_copy_str, mu_offsetof (struct _mu_url, user) }, + { MU_URL_SECRET, _url_copy_secret, 0 }, + { MU_URL_AUTH, _url_copy_str, mu_offsetof (struct _mu_url, auth) }, + { MU_URL_HOST, _url_copy_str, mu_offsetof (struct _mu_url, host) }, + { MU_URL_PORT, _url_copy_port, 0 }, + { MU_URL_PATH, _url_copy_str, mu_offsetof (struct _mu_url, path) }, + { MU_URL_PARAM, _url_copy_param, 0 }, + { MU_URL_QUERY, _url_copy_query, 0 } +}; + +int +mu_url_copy_hints (mu_url_t url, mu_url_t hint) +{ + int i; + + if (!url) + return EINVAL; + if (!hint) + return 0; + for (i = 0; i < MU_ARRAY_SIZE (copy_tab); i++) + { + if (!(url->flags & copy_tab[i].mask) && + (hint->flags & copy_tab[i].mask)) + { + int rc = copy_tab[i].fun (url, hint, copy_tab[i].off); + if (rc) + return rc; + url->flags |= copy_tab[i].mask; + } + } + return 0; +} + + + + + diff --git a/libmailutils/url/create.c b/libmailutils/url/create.c new file mode 100644 index 000000000..674a52469 --- /dev/null +++ b/libmailutils/url/create.c @@ -0,0 +1,525 @@ +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 2010 Free Software Foundation, Inc. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library. If not, see + <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <ctype.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#ifdef HAVE_STRINGS_H +# include <strings.h> +#endif +#include <netdb.h> +#include <arpa/inet.h> +#include <limits.h> + +#include <mailutils/util.h> +#include <mailutils/errno.h> +#include <mailutils/argcv.h> +#include <mailutils/secret.h> +#include <mailutils/cstr.h> +#include <mailutils/sys/url.h> + +struct mu_url_ctx +{ + int flags; + const char *input; + const char *cur; + mu_url_t url; + + size_t passoff; + + char *tokbuf; + size_t toksize; + size_t toklen; +}; + +static int +getkn (struct mu_url_ctx *ctx, char *delim) +{ + size_t n; + + if (*ctx->cur == 0) + return -1; + n = strcspn (ctx->cur, delim); + if (n > ctx->toksize) + { + char *p = realloc (ctx->tokbuf, n + 1); + if (!p) + return ENOENT; + ctx->toksize = n + 1; + ctx->tokbuf = p; + } + memcpy (ctx->tokbuf, ctx->cur, n); + ctx->tokbuf[n] = 0; + ctx->toklen = n; + ctx->cur += n; + return 0; +} + +#define INIT_ARRAY_SIZE 16 + +static int +expand_array (size_t *pwc, char ***pwv, int incr) +{ + size_t wc = *pwc; + char **wv = *pwv; + + if (!wv) + { + wv = calloc (INIT_ARRAY_SIZE, sizeof (wv[0])); + wc = INIT_ARRAY_SIZE; + } + else + { + if (incr) + wc += incr; + else + { + size_t newsize = wc * 2; + if (newsize < wc) + return ENOMEM; + wc = newsize; + } + wv = realloc (wv, sizeof (wv[0]) * wc); + } + if (!wv) + return ENOMEM; + *pwv = wv; + *pwc = wc; + return 0; +} + +static int +parse_param (struct mu_url_ctx *ctx, char *delim, int *pargc, char ***pargv) +{ + int rc; + size_t wc = 0, wn = 0; + char **wv = NULL; + + while ((rc = getkn (ctx, delim)) == 0) + { + if (wn == wc) + { + rc = expand_array (&wc, &wv, 0); + if (rc) + break; + } + wv[wn] = strdup (ctx->tokbuf); + if (!wv[wn]) + { + rc = ENOMEM; + break; + } + wn++; + if (*ctx->cur != delim[0]) + break; + ctx->cur++; + } + + if (rc == 0) + { + if (wn == wc) + { + rc = expand_array (&wc, &wv, 1); + if (rc) + { + mu_argcv_free (wc, wv); + return ENOMEM; + } + wv[wn] = NULL; + } + + *pargv = realloc (wv, sizeof (wv[0]) * (wn + 1)); + *pargc = wn; + } + else + mu_argcv_free (wc, wv); + + return rc; +} + +static int +_mu_url_ctx_parse_query (struct mu_url_ctx *ctx) +{ + int rc; + + ctx->cur++; + rc = parse_param (ctx, "&", &ctx->url->qargc, &ctx->url->qargv); + if (rc == 0 && ctx->url->qargc) + ctx->url->flags |= MU_URL_QUERY; + return rc; +} + +static int +_mu_url_ctx_parse_param (struct mu_url_ctx *ctx) +{ + int rc; + + ctx->cur++; + rc = parse_param (ctx, ";?", &ctx->url->fvcount, &ctx->url->fvpairs); + if (rc) + return rc; + if (ctx->url->fvcount) + ctx->url->flags |= MU_URL_PARAM; + if (*ctx->cur == '?') + return _mu_url_ctx_parse_query (ctx); + return 0; +} + +static int +str_assign (char **ptr, const char *str) +{ + *ptr = strdup (str); + if (!*ptr) + return ENOMEM; + return 0; +} + +static int +_mu_url_ctx_parse_path (struct mu_url_ctx *ctx) +{ + int rc; + mu_url_t url = ctx->url; + + rc = getkn (ctx, ";?"); + if (rc) + return rc; + rc = str_assign (&url->path, ctx->tokbuf); + if (rc == 0) + url->flags |= MU_URL_PATH; + if (*ctx->cur == ';') + return _mu_url_ctx_parse_param (ctx); + if (*ctx->cur == '?') + return _mu_url_ctx_parse_query (ctx); + return 0; +} + +static int +_mu_url_ctx_parse_host (struct mu_url_ctx *ctx, int has_host) +{ + int rc; + mu_url_t url = ctx->url; + + rc = getkn (ctx, ":/;?"); + if (rc) + return rc; + + if (ctx->toklen) + { + rc = str_assign (&url->host, ctx->tokbuf); + if (rc) + return rc; + url->flags |= MU_URL_HOST; + has_host = 1; + } + + if (*ctx->cur == ':') + { + ctx->cur++; + has_host = 1; + + rc = getkn (ctx, "/;?"); + if (rc) + return rc; + + rc = str_assign (&url->portstr, ctx->tokbuf); + if (rc) + return rc; + url->flags |= MU_URL_PORT; + } + + if (*ctx->cur == '/') + { + if (has_host) + ctx->cur++; + return _mu_url_ctx_parse_path (ctx); + } + + if (*ctx->cur == ';') + return _mu_url_ctx_parse_param (ctx); + + if (*ctx->cur == '?') + return _mu_url_ctx_parse_query (ctx); + return 0; +} + +static int +_mu_url_ctx_parse_cred (struct mu_url_ctx *ctx) +{ + int rc, has_cred; + mu_url_t url = ctx->url; + const char *save = ctx->cur; + + rc = getkn (ctx, "@"); + if (rc) + return rc; + has_cred = *ctx->cur == '@'; + /* restore the pointer */ + ctx->cur = save; + if (has_cred) + { + /* Try to split the user into a: + <user>:<password> + or + <user>:<password>;AUTH=<auth> + */ + rc = getkn (ctx, ":;@"); + if (rc) + return rc; + + if (ctx->toklen) + { + rc = str_assign (&url->user, ctx->tokbuf); + if (rc) + return rc; + url->flags |= MU_URL_USER; + } + + if (*ctx->cur == ':') + { + ctx->cur++; + ctx->passoff = ctx->cur - ctx->input; + + rc = getkn (ctx, ";@"); + if (rc) + return rc; + + if (ctx->toklen) + { + if (mu_secret_create (&url->secret, ctx->tokbuf, ctx->toklen)) + return ENOMEM; + else + /* Clear password */ + memset (ctx->tokbuf, 0, ctx->toklen); + url->flags |= MU_URL_SECRET; + } + } + if (*ctx->cur == ';') + { + ctx->cur++; + + rc = getkn (ctx, "@"); + if (rc) + return rc; + + /* Make sure it's the auth token. */ + if (mu_c_strncasecmp (ctx->tokbuf, "auth=", 5) == 0) + { + rc = str_assign (&url->auth, ctx->tokbuf + 5); + if (rc) + return rc; + url->flags |= MU_URL_AUTH; + } + } + + /* Skip @ sign */ + ctx->cur++; + } + return _mu_url_ctx_parse_host (ctx, has_cred); +} + +int +_mu_url_ctx_parse (struct mu_url_ctx *ctx) +{ + int rc; + mu_url_t url = ctx->url; + + /* Parse the scheme part */ + rc = getkn (ctx, ":/"); + if (rc) + return rc; + if (*ctx->cur == ':') + { + rc = str_assign (&url->scheme, ctx->tokbuf); + if (rc) + return rc; + url->flags |= MU_URL_SCHEME; + ctx->cur++; + } + + if (*ctx->cur == 0) + return 0; + + if (ctx->cur[0] == '/' && ctx->cur[1] == '/') + { + ctx->cur += 2; + return _mu_url_ctx_parse_cred (ctx); + } + + return _mu_url_ctx_parse_path (ctx); +} + +static int +_mu_url_create_internal (struct mu_url_ctx *ctx, mu_url_t hint) +{ + int rc; + mu_url_t url = ctx->url; + + if ((ctx->flags & MU_URL_PARSE_PIPE) && ctx->input[0] == '|') + { + rc = str_assign (&url->scheme, "prog"); + if (rc) + return rc; + url->flags |= MU_URL_SCHEME; + ctx->flags &= ~MU_URL_PARSE_HEXCODE; + rc = mu_argcv_get (ctx->input + 1, NULL, NULL, &url->qargc, &url->qargv); + if (rc == 0) + { + url->flags |= MU_URL_QUERY; + rc = str_assign (&url->path, url->qargv[0]); + if (rc == 0) + url->flags |= MU_URL_PATH; + } + } + else if ((ctx->flags & MU_URL_PARSE_SLASH) && ctx->input[0] == '/') + { + rc = str_assign (&url->scheme, "file"); + if (rc) + return rc; + url->flags |= MU_URL_SCHEME; + ctx->flags &= ~MU_URL_PARSE_HEXCODE; + rc = str_assign (&url->path, ctx->input); + if (rc == 0) + url->flags |= MU_URL_PATH; + } + else + rc = _mu_url_ctx_parse (ctx); + + if (rc) + return rc; + + if (hint) + { + /* Fill in missing values */ + rc = mu_url_copy_hints (url, hint); + if (rc) + return rc; + } + + if (!(url->flags & MU_URL_SCHEME)) + return MU_ERR_URL_MISS_PARTS; + + /* RFC 1738, section 2.1, lower the scheme case */ + mu_strlower (url->scheme); + + if ((url->flags & MU_URL_PORT) && url->port == 0) + { + /* Convert port string to number */ + unsigned long n; + char *p; + + n = strtoul (url->portstr, &p, 10); + if (*p) + { + if (ctx->flags & MU_URL_PARSE_PORTSRV) + { + /* FIXME: Another proto? */ + struct servent *sp = getservbyname (url->portstr, "tcp"); + if (!sp) + return MU_ERR_TCP_NO_PORT; //FIXME: Error code? + url->port = ntohs (sp->s_port); + } + else + return MU_ERR_TCP_NO_PORT; + } + else if (n > USHRT_MAX) + return ERANGE; + else + url->port = n; + } + + if (ctx->flags & MU_URL_PARSE_HEXCODE) + { + /* Decode the %XX notations */ + rc = mu_url_decode (url); + if (rc) + return rc; + } + + if ((url->flags & MU_URL_SECRET) && + (ctx->flags & MU_URL_PARSE_HIDEPASS)) + { + /* Obfuscate the password */ +#define PASS_REPL "***" +#define PASS_REPL_LEN (sizeof (PASS_REPL) - 1) + size_t plen = mu_secret_length (url->secret); + size_t nlen = strlen (url->name); + size_t len = nlen - plen + PASS_REPL_LEN + 1; + char *newname; + + memset (url->name + ctx->passoff, 0, plen); + if (len > nlen + 1) + { + newname = realloc (url->name, len); + if (!newname) + return rc; + url->name = newname; + } + else + newname = url->name; + memmove (newname + ctx->passoff + PASS_REPL_LEN, + newname + ctx->passoff + plen, + nlen - (ctx->passoff + plen) + 1); + memcpy (newname + ctx->passoff, PASS_REPL, PASS_REPL_LEN); + } + + return 0; +} + +int +mu_url_create_hint (mu_url_t *purl, const char *str, int flags, + mu_url_t hint) +{ + int rc; + struct mu_url_ctx ctx; + mu_url_t url = calloc (1, sizeof (*url)); + if (url == NULL) + return ENOMEM; + url->name = strdup (str); + if (!url->name) + { + free (url); + return ENOMEM; + } + memset (&ctx, 0, sizeof (ctx)); + ctx.flags = flags; + ctx.input = str; + ctx.cur = ctx.input; + ctx.url = url; + rc = _mu_url_create_internal (&ctx, hint); + free (ctx.tokbuf); + if (rc) + mu_url_destroy (&url); + else + *purl = url; + return rc; +} + +int +mu_url_create (mu_url_t *purl, const char *str) +{ + return mu_url_create_hint (purl, str, + MU_URL_PARSE_HEXCODE | + MU_URL_PARSE_HIDEPASS | + MU_URL_PARSE_PORTSRV | + MU_URL_PARSE_PIPE | + MU_URL_PARSE_SLASH, NULL); +} diff --git a/libmailutils/url/decode.c b/libmailutils/url/decode.c new file mode 100644 index 000000000..9aca0e217 --- /dev/null +++ b/libmailutils/url/decode.c @@ -0,0 +1,118 @@ +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 2010 Free Software Foundation, Inc. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library. If not, see + <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#ifdef HAVE_STRINGS_H +# include <strings.h> +#endif + +#include <mailutils/types.h> +#include <mailutils/util.h> +#include <mailutils/secret.h> +#include <mailutils/sys/url.h> + +struct decode_tab +{ + int mask; + int (*fun) (mu_url_t, size_t); + size_t off; +}; + +static int +_url_dec_str (mu_url_t url, size_t off) +{ + char **pptr = (char**) ((char*) url + off); + mu_str_url_decode_inline (*pptr); + return 0; +} + +static int +_url_dec_param (mu_url_t url, size_t off) +{ + int i; + + for (i = 0; i < url->fvcount; i++) + mu_str_url_decode_inline (url->fvpairs[i]); + return 0; +} + +static int +_url_dec_query (mu_url_t url, size_t off) +{ + int i; + + for (i = 0; i < url->qargc; i++) + mu_str_url_decode_inline (url->qargv[i]); + return 0; +} + +static int +_url_dec_secret (mu_url_t url, size_t off) +{ + char *pass; + mu_secret_t newsec; + int rc; + + rc = mu_str_url_decode (&pass, mu_secret_password (url->secret)); + if (rc) + return rc; + rc = mu_secret_create (&newsec, pass, strlen (pass)); + memset (pass, 0, strlen (pass)); + free (pass); + if (rc) + re |