summaryrefslogtreecommitdiff
path: root/libmailutils/url
diff options
context:
space:
mode:
Diffstat (limited to 'libmailutils/url')
-rw-r--r--libmailutils/url/Makefile.am45
-rw-r--r--libmailutils/url/accessor.h143
-rw-r--r--libmailutils/url/copy.c145
-rw-r--r--libmailutils/url/create.c525
-rw-r--r--libmailutils/url/decode.c118
-rw-r--r--libmailutils/url/destroy.c74
-rw-r--r--libmailutils/url/dup.c56
-rw-r--r--libmailutils/url/expand.c216
-rw-r--r--libmailutils/url/flag.c40
-rw-r--r--libmailutils/url/get-auth.c3
-rw-r--r--libmailutils/url/get-host.c2
-rw-r--r--libmailutils/url/get-param.c131
-rw-r--r--libmailutils/url/get-path.c2
-rw-r--r--libmailutils/url/get-portstr.c2
-rw-r--r--libmailutils/url/get-query.c72
-rw-r--r--libmailutils/url/get-scheme.c2
-rw-r--r--libmailutils/url/get-secret.c44
-rw-r--r--libmailutils/url/get-user.c2
-rw-r--r--libmailutils/url/match.c102
-rw-r--r--libmailutils/url/port.c53
-rw-r--r--libmailutils/url/scheme.c55
-rw-r--r--libmailutils/url/uplevel.c71
-rw-r--r--libmailutils/url/urlstr.c31
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)
+ return rc;
+ mu_secret_destroy (&url->secret);
+ url->secret = newsec;
+ return 0;
+}
+
+static struct decode_tab decode_tab[] = {
+ { MU_URL_SCHEME, _url_dec_str, mu_offsetof (struct _mu_url, scheme) },
+ { MU_URL_USER, _url_dec_str, mu_offsetof (struct _mu_url, user) },
+ { MU_URL_SECRET, _url_dec_secret },
+ { MU_URL_AUTH, _url_dec_str, mu_offsetof (struct _mu_url, auth) },
+ { MU_URL_HOST, _url_dec_str, mu_offsetof (struct _mu_url, host) },
+ { MU_URL_PATH, _url_dec_str, mu_offsetof (struct _mu_url, path) },
+ { MU_URL_PARAM, _url_dec_param, 0 },
+ { MU_URL_QUERY, _url_dec_query, 0 }
+};
+
+int
+mu_url_decode (mu_url_t url)
+{
+ int i;
+
+ if (!url)
+ return EINVAL;
+ for (i = 0; i < MU_ARRAY_SIZE (decode_tab); i++)
+ {
+ if (url->flags & decode_tab[i].mask)
+ {
+ int rc = decode_tab[i].fun (url, decode_tab[i].off);
+ if (rc)
+ return rc;
+ }
+ }
+ return 0;
+}
+
diff --git a/libmailutils/url/destroy.c b/libmailutils/url/destroy.c
new file mode 100644
index 000000000..a46dc3150
--- /dev/null
+++ b/libmailutils/url/destroy.c
@@ -0,0 +1,74 @@
+/* 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/argcv.h>
+#include <mailutils/secret.h>
+#include <mailutils/errno.h>
+#include <mailutils/sys/url.h>
+
+void
+mu_url_destroy (mu_url_t * purl)
+{
+ if (purl && *purl)
+ {
+ mu_url_t url = (*purl);
+
+ if (url->_destroy)
+ url->_destroy (url);
+
+ if (url->name)
+ free (url->name);
+
+ if (url->scheme)
+ free (url->scheme);
+
+ if (url->user)
+ free (url->user);
+
+ mu_secret_destroy (&url->secret);
+
+ if (url->auth)
+ free (url->auth);
+
+ if (url->host)
+ free (url->host);
+
+ if (url->path)
+ free (url->path);
+
+ if (url->fvcount)
+ mu_argcv_free (url->fvcount, url->fvpairs);
+
+ mu_argcv_free (url->qargc, url->qargv);
+
+ free (url);
+
+ *purl = NULL;
+ }
+}
diff --git a/libmailutils/url/dup.c b/libmailutils/url/dup.c
new file mode 100644
index 000000000..d9a738341
--- /dev/null
+++ b/libmailutils/url/dup.c
@@ -0,0 +1,56 @@