summaryrefslogtreecommitdiff
path: root/libmailutils
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2010-10-26 13:00:52 +0300
committerSergey Poznyakoff <gray@gnu.org.ua>2010-10-26 13:36:28 +0300
commit3327a23a49e532c068972a0b2d64021361540f7b (patch)
treeb2d6508005ac8343a54638142c4f8234f7202441 /libmailutils
parent6203ae65f53758a4b893e6e176be7c153a31bef0 (diff)
downloadmailutils-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')
-rw-r--r--libmailutils/Makefile.am5
-rw-r--r--libmailutils/base/Makefile.am1
-rw-r--r--libmailutils/base/registrar.c4
-rw-r--r--libmailutils/base/url.c1254
-rw-r--r--libmailutils/base/wicket.c20
-rw-r--r--libmailutils/mailbox/folder.c4
-rw-r--r--libmailutils/mailbox/mailbox.c8
-rw-r--r--libmailutils/mailer/mailer.c4
-rw-r--r--libmailutils/mime/mimehdr.c8
-rw-r--r--libmailutils/stream/tcp.c11
-rw-r--r--libmailutils/string/Makefile.am3
-rw-r--r--libmailutils/string/xdecode.c73
-rw-r--r--libmailutils/tests/url-parse.c9
-rw-r--r--libmailutils/tests/wicket.c7
-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
37 files changed, 2038 insertions, 1307 deletions
diff --git a/libmailutils/Makefile.am b/libmailutils/Makefile.am
index f13085f32..454962bd3 100644
--- a/libmailutils/Makefile.am
+++ b/libmailutils/Makefile.am
@@ -17,7 +17,7 @@
# <http://www.gnu.org/licenses/>.
SUBDIRS = auth base address cfg diag filter mailbox mailer mime\
- server string stream . tests
+ server string stream url . tests
lib_LTLIBRARIES = libmailutils.la
@@ -36,7 +36,8 @@ libmailutils_la_LIBADD = \
mime/libmime.la\
server/libserver.la\
string/libstring.la\
- stream/libstream.la
+ stream/libstream.la\
+ url/liburl.la
libmailutils_la_LDFLAGS = -version-info @VI_CURRENT@:@VI_REVISION@:@VI_AGE@
diff --git a/libmailutils/base/Makefile.am b/libmailutils/base/Makefile.am
index 196344bb7..c51c947be 100644
--- a/libmailutils/base/Makefile.am
+++ b/libmailutils/base/Makefile.am
@@ -61,7 +61,6 @@ libbase_la_SOURCES = \
tempfile.c\
ticket.c\
tilde.c\
- url.c\
usremail.c\
vartab.c\
version.c\
diff --git a/libmailutils/base/registrar.c b/libmailutils/base/registrar.c
index da43bff5e..fc31b90b9 100644
--- a/libmailutils/base/registrar.c
+++ b/libmailutils/base/registrar.c
@@ -220,9 +220,7 @@ mu_registrar_lookup (const char *name, int flags,
rc = mu_url_create (&url, name);
if (rc)
return rc;
- rc = mu_url_parse (url);
- if (rc == 0)
- rc = mu_registrar_lookup_url (url, flags, precord, pflags);
+ rc = mu_registrar_lookup_url (url, flags, precord, pflags);
mu_url_destroy (&url);
return rc;
}
diff --git a/libmailutils/base/url.c b/libmailutils/base/url.c
deleted file mode 100644
index 96345f056..000000000
--- a/libmailutils/base/url.c
+++ /dev/null
@@ -1,1254 +0,0 @@
-/* GNU Mailutils -- a suite of utilities for electronic mail
- Copyright (C) 1999, 2000, 2001, 2007, 2008, 2009, 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 <mailutils/util.h>
-#include <mailutils/errno.h>
-#include <mailutils/argcv.h>
-#include <mailutils/secret.h>
-#include <mailutils/cctype.h>
-#include <mailutils/cstr.h>
-#include <mailutils/sys/url.h>
-
-#define AC2(a,b) a ## b
-#define AC4(a,b,c,d) a ## b ## c ## d
-
-static int url_parse0 (mu_url_t, char *, size_t *poff, int *decode);
-
-static int
-parse_query (const char *query,
- char *delim,
- int *pargc, char ***pargv, const char **pend)
-{
- size_t count, i;
- char **v;
- const char *p;
-
- for (p = query, count = 0; ; count++)
- {
- size_t len = strcspn (p, delim);
- p += len;
- if (!*p || *p == delim[1])
- break;
- p++;
- }
-
- if (pend)
- *pend = p;
- if (p == query)
- return 0;
- count++;
-
- v = calloc (count + 1, sizeof (v[0]));
- for (i = 0, p = query; i < count; i++)
- {
- size_t len = strcspn (p, delim);
- v[i] = mu_url_decode_len (p, len);
- if (v[i] == NULL)
- {
- mu_argcv_free (i, v);
- return 1;
- }
- p += len + 1;
- }
- v[i] = NULL;
-
- *pargc = count;
- *pargv = v;
- return 0;
-}
-
-int
-mu_url_create (mu_url_t *purl, const char *name)
-{
- mu_url_t url = calloc (1, sizeof (*url));
- if (url == NULL)
- return ENOMEM;
-
- url->name = strdup (name);
- if (url->name == NULL)
- {
- free (url);
- return ENOMEM;
- }
- *purl = url;
- 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
-mu_url_copy0 (mu_url_t old_url, mu_url_t new_url)
-{
- const char *str;
- size_t argc;
- char **argv;
- int rc;
- mu_secret_t sec;
-
-#define URLCOPY(what) \
- do \
- { \
- rc = AC2(mu_url_sget_,what) (old_url, &str); \
- if (rc == 0) \
- { \
- if ((new_url->what = strdup (str)) == NULL) \
- return ENOMEM; \
- } \
- else if (rc != MU_ERR_NOENT) \
- return rc; \
- } \
- while (0);
-
- URLCOPY (scheme);
- URLCOPY (user);
-
- rc = mu_url_get_secret (old_url, &sec);
- if (rc == MU_ERR_NOENT)
- new_url->secret = NULL;
- else if (rc)
- return rc;
- else
- {
- rc = mu_secret_dup (sec, &new_url->secret);
- if (rc)
- return rc;
- }
-
- URLCOPY (auth);
- URLCOPY (host);
- new_url->port = old_url->port;
- URLCOPY (path);
-
- rc = mu_url_sget_fvpairs (old_url, &argc, &argv);
- if (rc == 0 && argc)
- {
- if ((new_url->fvpairs = argcv_copy (argc, argv)) == NULL)
- return ENOMEM;
- new_url->fvcount = argc;
- }
-
- rc = mu_url_sget_query (old_url, &argc, &argv);
- if (rc == 0 && argc)
- {
- if ((new_url->qargv = argcv_copy (argc, argv)) == NULL)
- return ENOMEM;
- new_url->qargc = argc;
- }
- new_url->flags = old_url->flags;
- return 0;
-#undef URLCOPY
-}
-
-int
-mu_url_dup (mu_url_t old_url, mu_url_t *new_url)
-{
- mu_url_t url;
- int rc = mu_url_create (&url, mu_url_to_string (old_url));
-
- if (rc)
- return rc;
-
- rc = mu_url_copy0 (old_url, url);
- if (rc == 0)
- *new_url = url;
- else
- mu_url_destroy (&url);
- return rc;
-}
-
-int
-mu_url_uplevel (mu_url_t url, mu_url_t *upurl)
-{
- int rc;
- char *p;
- mu_url_t new_url;
-
- if (url->_uplevel)
- return url->_uplevel (url, upurl);
-
- if (!url->path)
- return MU_ERR_NOENT;
- p = strrchr (url->path, '/');
-
- rc = mu_url_dup (url, &new_url);
- if (rc == 0)
- {
- if (!p || p == url->path)
- {
- free (new_url->path);
- new_url->path = NULL;
- }
- else
- {
- size_t size = p - url->path;
- new_url->path = realloc (new_url->path, size + 1);
- if (!new_url->path)
- {
- mu_url_destroy (&new_url);
- return ENOMEM;
- }
- memcpy (new_url->path, url->path, size);
- new_url->path[size] = 0;
- }
- *upurl = new_url;
- }
- return rc;
-}
-
-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;
- }
-}
-
-int
-mu_url_parse (mu_url_t url)
-{
- int err = 0;
- char *n = NULL;
- struct _mu_url u;
- size_t pstart;
- mu_secret_t newsec;
- int want_decode;
-
- if (!url || !url->name)
- return EINVAL;
-
- memset (&u, 0, sizeof u);
- /* can't have been parsed already */
- if (url->flags)
- return EINVAL;
-
- n = strdup (url->name);
-
- if (!n)
- return ENOMEM;
-
- err = url_parse0 (&u, n, &pstart, &want_decode);
-
- if (!err)
- {
- if (u.secret)
- {
- /* Obfuscate the password */
-#define PASS_REPL "***"
-#define PASS_REPL_LEN (sizeof (PASS_REPL) - 1)
- size_t plen = mu_secret_length (u.secret);
- size_t nlen = strlen (url->name);
- size_t len = nlen - plen + PASS_REPL_LEN + 1;
- char *newname;
-
- memset (url->name + pstart, 0, plen);
- if (len > nlen + 1)
- {
- newname = realloc (url->name, len);
- if (!newname)
- goto CLEANUP;
- url->name = newname;
- }
- else
- newname = url->name;
- memmove (newname + pstart + PASS_REPL_LEN, newname + pstart + plen,
- nlen - (pstart + plen) + 1);
- memcpy (newname + pstart, PASS_REPL, PASS_REPL_LEN);
- }
-
- /* Dup the strings we found. We wouldn't have to do this
- if we did a single alloc of the source url name, and
- kept it around. It's also a good time to do hex decoding,
- though.
- */
-
-#define UALLOC(X,f) \
- if (u.X && u.X[0]) \
- { \
- url->X = want_decode ? mu_url_decode (u.X) : strdup (u.X); \
- if (!url->X) \
- { \
- err = ENOMEM; \
- goto CLEANUP; \
- } \
- url->flags |= f; \
- } \
- else \
- { \
- /* Set zero-length strings to NULL. */ \
- url->X = NULL; \
- }
-
- UALLOC (scheme, 0);
- UALLOC (user, MU_URL_USER);
-
- if (u.secret)
- {
- char *pass = mu_url_decode (mu_secret_password (u.secret));
- err = mu_secret_create (&newsec, pass, strlen (pass));
- memset (pass, 0, strlen (pass));
- mu_secret_destroy (&u.secret);
- if (err)
- goto CLEANUP;
-
- url->secret = newsec;
- url->flags |= MU_URL_SECRET;
- }
-
- UALLOC (auth, MU_URL_AUTH);
- UALLOC (host, MU_URL_HOST);
- UALLOC (path, MU_URL_PATH);
-
-#undef UALLOC
- url->fvcount = u.fvcount;
- url->fvpairs = u.fvpairs;
- if (u.fvcount)
- url->flags |= MU_URL_PARAM;
-
- url->qargc = u.qargc;
- url->qargv = u.qargv;
- if (u.qargc)
- url->flags |= MU_URL_QUERY;
-
- url->port = u.port;
- if (u.port)
- url->flags |= MU_URL_PORT;
- }
-
-CLEANUP:
- memset (n, 0, strlen (n));
- free (n);
-
- if (err)
- {
-#define UFREE(X) if (X) { free(X); X = 0; }
-
- UFREE (url->scheme);
- UFREE (url->user);
- mu_secret_destroy (&u.secret);
- UFREE (url->auth);
- UFREE (url->host);
- UFREE (url->path);
- mu_argcv_free (url->fvcount, url->fvpairs);
- mu_argcv_free (url->qargc, url->qargv);
-#undef UFREE
- }
-
- return err;
-}
-
-/*
-
-Syntax, condensed from RFC 1738, and extended with the ;auth=
-of RFC 2384 (for POP) and RFC 2192 (for IMAP):
-
-url =
- scheme ":" [ "//"
-
- [ user [ ( ":" password ) | ( ";auth=" auth ) ] "@" ]
-
- host [ ":" port ]
-
- [ ( "/" urlpath ) | ( "?" query ) ] ]
-
-All hell will break loose in this parser if the user/pass/auth
-portion is missing, and the urlpath has any @ or : characters
-in it. A imap mailbox, say, named after the email address of
-the person the mail is from:
-
- imap://imap.uniserve.com/alain@qnx.com
-
-Is this required to be % quoted, though? I hope so!
-
-*/
-
-static int
-url_parse0 (mu_url_t u, char *name, size_t *poff, int *decode)
-{
- char *start = name;
- char *p; /* pointer into name */
-
- /* reject the obvious */
- if (name == NULL)
- return EINVAL;
-
- if (name[0] == '/')
- {
- u->scheme = "file";
- *decode = 0;
- }
- else if (name[0] == '|')
- {
- int rc;
- u->scheme = "prog";
- *decode = 0;
- rc = mu_argcv_get (name + 1, NULL, NULL, &u->qargc, &u->qargv);
- if (rc == 0)
- {
- u->path = strdup (u->qargv[0]);
- if (!u->path)
- rc = ENOMEM;
- }
- return rc;
- }
- else
- {
- *decode = 1;
- /* Parse out the SCHEME. */
- p = strchr (name, ':');
- if (p == NULL)
- return MU_ERR_PARSE;
-
- *p++ = 0;
-
- u->scheme = name;
-
- /* RFC 1738, section 2.1, lower the scheme case */
- for (; name < p; name++)
- *name = mu_tolower (*name);
-
- name = p;
- }
-
- /* Check for nothing following the scheme. */
- if (!*name)
- return 0;
-
- if (strncmp (name, "//", 2) == 0)
- {
- name += 2;
-
- if (name[0] == '/')
- {
- u->path = name;
- p = u->path + strcspn (u->path, ";?");
- }
- else
- {
- /* Split into LHS and RHS of the '@', and then parse each side. */
- u->host = strchr (name, '@');
- if (u->host == NULL)
- u->host = name;
- else
- {
- char *pass = NULL;
-
- /* Parse the LHS into an identification/authentication pair. */
- *u->host++ = 0;
-
- u->user = name;
-
- /* Try to split the user into a:
- <user>:<password>
- or
- <user>:<password>;AUTH=<auth>
- */
-
- for (; *name; name++)
- {
- if (*name == ':')
- {
- *name++ = 0;
- pass = name;
- *poff = pass - start;
- }
- else if (*name == ';')
- {
- /* Make sure it's the auth token. */
- if (mu_c_strncasecmp (name + 1, "auth=", 5) == 0)
- {
- *name++ = 0;
- name += 5;
- u->auth = name;
- break;
- }
- }
- }
-
- if (pass)
- {
- if (mu_secret_create (&u->secret, pass, strlen (pass)))
- return ENOMEM;
- else
- /* Obfuscate password */
- memset (pass, 0, strlen (pass));
- }
- }
-
- /* Parse the host and port from the RHS. */
- p = strchr (u->host, ':');
- if (p)
- {
- *p++ = 0;
- u->port = strtol (p, &p, 10);
-
- /* Check for garbage after the port: we should be on the start
- of a path, a query, or at the end of the string. */
- if (*p && strcspn (p, "/?") != 0)
- return MU_ERR_PARSE;
- }
- else
- p = u->host + strcspn (u->host, ";/?");
- }
- }
- else
- {
- u->path = name;
- p = u->path + strcspn (u->path, ";?");
- }
-
- /* Either way, if we're not at a nul, we're at a path or query. */
- if (u->path == NULL && *p == '/')
- {
- /* found a path */
- *p++ = 0;
- u->path = p;
- p = u->path + strcspn (u->path, ";?");
- }
-
- if (*p == ';')
- {
- *p++ = 0;
- if (parse_query (p, ";?", &u->fvcount, &u->fvpairs, (const char **)&p))
- return ENOMEM;
- }
-
- if (*p == '?')
- {
- /* found a query */
- *p++ = 0;
- if (parse_query (p, "&", &u->qargc, &u->qargv, NULL))
- return ENOMEM;
- }
-
- return 0;
-}
-
-
-/* General accessors: */
-#define ACCESSOR(action,field) AC4(mu_url_,action,_,field)
-
-#define DECL_SGET(field) \
-int \
-ACCESSOR(sget,field) (mu_url_t url, char const **sptr) \
-{ \
- if (url == NULL) \
- return EINVAL; \
- if (!url->field) \
- { \
- if (url->AC2(_get_,field)) \
- { \
- size_t n; \
- char *buf; \
- \
- int status = url->AC2(_get_,field) (url, NULL, 0, &n); \
- if (status) \
- return status; \
- \
- buf = malloc (n + 1); \
- if (!buf) \
- return ENOMEM; \
- \
- status = url->AC2(_get_,field) (url, buf, n + 1, NULL); \
- if (status) \
- return status; \
- \
- if (buf[0]) \
- { \
- url->field = mu_url_decode (buf); \
- free (buf); \
- } \
- else \
- url->field = buf; \
- if (!url->field) \
- return ENOMEM; \
- } \
- else \
- return MU_ERR_NOENT; \
- } \
- *sptr = url->field; \
- return 0; \
-}
-
-#define DECL_GET(field) \
-int \
-ACCESSOR(get,field) (mu_url_t url, char *buf, size_t len, size_t *n) \
-{ \
- size_t i; \
- const char *str; \
- int status = ACCESSOR(sget, field) (url, &str); \
- \
- if (status) \
- return status; \
- \
- i = mu_cpystr (buf, str, len); \
- if (n) \
- *n = i; \
- return 0; \
-}
-
-#define DECL_AGET(field) \
-int \
-ACCESSOR(aget, field) (mu_url_t url, char **buf) \
-{ \
- const char *str; \
- int status = ACCESSOR(sget, field) (url, &str); \
- \
- if (status) \
- return status; \
- \
- if (str) \
- { \
- *buf = strdup (str); \
- if (!*buf) \
- status = ENOMEM; \
- } \
- else \
- *buf = NULL; \
- return status; \
-}
-
-#define DECL_CMP(field) \
-int \
-ACCESSOR(is_same,field) (mu_url_t url1, mu_url_t url2) \
-{ \
- const char *s1, *s2; \
- int status1, status2; \
- \
- status1 = ACCESSOR(sget, field) (url1, &s1); \
- if (status1 && status1 != MU_ERR_NOENT) \
- return 0; \
- status2 = ACCESSOR(sget, field) (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; \
-}
-
-#define DECL_ACCESSORS(field) \
-DECL_SGET(field) \
-DECL_GET(field) \
-DECL_AGET(field) \
-DECL_CMP(field)
-
-
-/* Declare particular accessors */
-DECL_ACCESSORS (scheme)
-DECL_ACCESSORS (user)
-DECL_ACCESSORS (auth)
-DECL_ACCESSORS (host)
-DECL_ACCESSORS (path)
-
-int
-mu_url_get_secret (const mu_url_t url, mu_secret_t *psecret)
-{
- if (url->_get_secret)
- return url->_get_secret (url, psecret);
- if (url->secret == NULL)
- return MU_ERR_NOENT;
- mu_secret_ref (url->secret);
- *psecret = url->secret;
- return 0;
-}
-
-int
-mu_url_sget_query (const mu_url_t url, size_t *qc, char ***qv)
-{
- if (url == NULL)
- return EINVAL;
- /* See FIXME below */
- *qc = url->qargc;
- *qv = url->qargv;
- return 0;
-}
-
-int
-mu_url_aget_query (const mu_url_t url, size_t *qc, char ***qv)
-{
- size_t qargc, i;
- char **qargv;
- char **qcopy;
-
- int rc = mu_url_sget_fvpairs (url, &qargc, &qargv);
- if (rc)
- return rc;
-
- qcopy = calloc (qargc + 1, sizeof (qcopy[0]));
- if (!qcopy)
- return errno;
- for (i = 0; i < qargc; i++)
- {
- if (!(qcopy[i] = strdup (qargv[i])))
- {
- mu_argcv_free (i, qcopy);
- return errno;
- }
- }
- qcopy[i] = NULL;
- *qc = qargc;
- *qv = qcopy;
- return 0;
-}
-
-/* field-value pairs accessors */
-int
-mu_url_sget_fvpairs (const mu_url_t url, size_t *fvc, char ***fvp)
-{
- if (url == NULL)
- return EINVAL;
- /* FIXME: no _get_fvpairs method, but the method stuff needs to be rewritten
- anyway */
- *fvc = url->fvcount;
- *fvp = url->fvpairs;
- return 0;
-}
-
-int
-mu_url_sget_param (const mu_url_t url, const char *param, const char **val)
-{
- size_t fvc;
- char **fv