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 | |
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')
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 |