From 3327a23a49e532c068972a0b2d64021361540f7b Mon Sep 17 00:00:00 2001 From: Sergey Poznyakoff Date: Tue, 26 Oct 2010 13:00:52 +0300 Subject: 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): 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. --- configure.ac | 1 + doc/texinfo/url.texi | 2 +- imap4d/imap4d.c | 9 +- include/mailutils/auth.h | 4 +- include/mailutils/cpp/url.h | 2 +- include/mailutils/stream.h | 6 +- include/mailutils/sys/url.h | 6 +- include/mailutils/url.h | 52 +- include/mailutils/util.h | 3 +- libmailutils/Makefile.am | 5 +- libmailutils/base/Makefile.am | 1 - libmailutils/base/registrar.c | 4 +- libmailutils/base/url.c | 1254 --------------------------------------- libmailutils/base/wicket.c | 20 +- libmailutils/mailbox/folder.c | 4 +- libmailutils/mailbox/mailbox.c | 8 +- libmailutils/mailer/mailer.c | 4 +- libmailutils/mime/mimehdr.c | 8 +- libmailutils/stream/tcp.c | 11 +- libmailutils/string/Makefile.am | 3 +- libmailutils/string/xdecode.c | 73 +++ libmailutils/tests/url-parse.c | 9 +- libmailutils/tests/wicket.c | 7 +- libmailutils/url/Makefile.am | 45 ++ libmailutils/url/accessor.h | 143 +++++ libmailutils/url/copy.c | 145 +++++ libmailutils/url/create.c | 525 ++++++++++++++++ libmailutils/url/decode.c | 118 ++++ libmailutils/url/destroy.c | 74 +++ libmailutils/url/dup.c | 56 ++ libmailutils/url/expand.c | 216 +++++++ libmailutils/url/flag.c | 40 ++ libmailutils/url/get-auth.c | 3 + libmailutils/url/get-host.c | 2 + libmailutils/url/get-param.c | 131 ++++ libmailutils/url/get-path.c | 2 + libmailutils/url/get-portstr.c | 2 + libmailutils/url/get-query.c | 72 +++ libmailutils/url/get-scheme.c | 2 + libmailutils/url/get-secret.c | 44 ++ libmailutils/url/get-user.c | 2 + libmailutils/url/match.c | 102 ++++ libmailutils/url/port.c | 53 ++ libmailutils/url/scheme.c | 55 ++ libmailutils/url/uplevel.c | 71 +++ libmailutils/url/urlstr.c | 31 + libmu_cpp/url.cc | 10 +- libproto/imap/folder.c | 6 +- libproto/maildir/folder.c | 2 +- libproto/mailer/prog.c | 2 +- libproto/mailer/remote.c | 6 +- libproto/mailer/sendmail.c | 6 +- libproto/mailer/smtp.c | 4 +- libproto/mailer/smtp_auth.c | 9 - libproto/mbox/folder.c | 2 +- libproto/mh/folder.c | 2 +- libproto/nntp/folder.c | 4 +- libproto/pop/folder.c | 4 +- libproto/pop/mbox.c | 2 +- maidag/deliver.c | 15 - mu/wicket.c | 34 +- python/libmu_py/url.c | 8 +- 62 files changed, 2126 insertions(+), 1420 deletions(-) delete mode 100644 libmailutils/base/url.c create mode 100644 libmailutils/string/xdecode.c create mode 100644 libmailutils/url/Makefile.am create mode 100644 libmailutils/url/accessor.h create mode 100644 libmailutils/url/copy.c create mode 100644 libmailutils/url/create.c create mode 100644 libmailutils/url/decode.c create mode 100644 libmailutils/url/destroy.c create mode 100644 libmailutils/url/dup.c create mode 100644 libmailutils/url/expand.c create mode 100644 libmailutils/url/flag.c create mode 100644 libmailutils/url/get-auth.c create mode 100644 libmailutils/url/get-host.c create mode 100644 libmailutils/url/get-param.c create mode 100644 libmailutils/url/get-path.c create mode 100644 libmailutils/url/get-portstr.c create mode 100644 libmailutils/url/get-query.c create mode 100644 libmailutils/url/get-scheme.c create mode 100644 libmailutils/url/get-secret.c create mode 100644 libmailutils/url/get-user.c create mode 100644 libmailutils/url/match.c create mode 100644 libmailutils/url/port.c create mode 100644 libmailutils/url/scheme.c create mode 100644 libmailutils/url/uplevel.c create mode 100644 libmailutils/url/urlstr.c diff --git a/configure.ac b/configure.ac index 27ff3f64a..690171bcf 100644 --- a/configure.ac +++ b/configure.ac @@ -1387,6 +1387,7 @@ AC_CONFIG_FILES([ libmailutils/server/Makefile libmailutils/string/Makefile libmailutils/stream/Makefile + libmailutils/url/Makefile libmailutils/Makefile messages/Makefile mh/Makefile diff --git a/doc/texinfo/url.texi b/doc/texinfo/url.texi index 267a89f7a..139973131 100644 --- a/doc/texinfo/url.texi +++ b/doc/texinfo/url.texi @@ -186,7 +186,7 @@ for any particular scheme. @deftypefun int mu_url_get_host (const mu_url_t, char *, size_t, size_t *) @end deftypefun -@deftypefun int mu_url_get_port (const mu_url_t, long *) +@deftypefun int mu_url_get_port (const mu_url_t, unsigned *) @end deftypefun @deftypefun int mu_url_get_path (const mu_url_t, char *, size_t, size_t *) diff --git a/imap4d/imap4d.c b/imap4d/imap4d.c index c80af2b7e..cbadb83d7 100644 --- a/imap4d/imap4d.c +++ b/imap4d/imap4d.c @@ -172,7 +172,7 @@ parse_preauth_scheme (mu_debug_t debug, const char *scheme, mu_url_t url) else if (strcmp (scheme, "ident") == 0) { struct servent *sp; - long n; + unsigned n; if (url && mu_url_get_port (url, &n) == 0) ident_port = (short) n; else if ((sp = getservbyname ("auth", "tcp"))) @@ -219,13 +219,6 @@ cb_preauth (mu_debug_t debug, void *data, mu_config_value_t *val) mu_diag_funcall (MU_DIAG_ERROR, "mu_url_create", val->v.string, rc); return 1; } - rc = mu_url_parse (url); - if (rc) - { - mu_cfg_format_error (debug, MU_DEBUG_ERROR, - "%s: %s", val->v.string, mu_strerror (rc)); - return 1; - } rc = mu_url_aget_scheme (url, &scheme); if (rc) diff --git a/include/mailutils/auth.h b/include/mailutils/auth.h index b3b7be357..3433b6173 100644 --- a/include/mailutils/auth.h +++ b/include/mailutils/auth.h @@ -78,8 +78,10 @@ int mu_file_wicket_create (mu_wicket_t *pwicket, const char *filename); struct mu_debug_locus; int mu_wicket_stream_match_url (mu_stream_t stream, struct mu_debug_locus *loc, - mu_url_t url, mu_url_t *pticket_url); + mu_url_t url, int parse_flags, + mu_url_t *pticket_url); int mu_wicket_file_match_url (const char *name, mu_url_t url, + int parse_flags, mu_url_t *pticket_url); diff --git a/include/mailutils/cpp/url.h b/include/mailutils/cpp/url.h index dd7d06578..b3b71387f 100644 --- a/include/mailutils/cpp/url.h +++ b/include/mailutils/cpp/url.h @@ -42,7 +42,7 @@ class Url ~Url (); void parse (); - long get_port (); + unsigned get_port (); std::string get_scheme (); std::string get_user (); std::string get_auth (); diff --git a/include/mailutils/stream.h b/include/mailutils/stream.h index d951f3425..bb141860f 100644 --- a/include/mailutils/stream.h +++ b/include/mailutils/stream.h @@ -176,14 +176,14 @@ int mu_streamref_create_abridged (mu_stream_t *pref, mu_stream_t str, int mu_streamref_create (mu_stream_t *pref, mu_stream_t str); int mu_tcp_stream_create_with_source_ip (mu_stream_t *stream, - const char *host, int port, + const char *host, unsigned port, unsigned long source_ip, int flags); int mu_tcp_stream_create_with_source_host (mu_stream_t *stream, - const char *host, int port, + const char *host, unsigned port, const char *source_host, int flags); -int mu_tcp_stream_create (mu_stream_t *stream, const char *host, int port, +int mu_tcp_stream_create (mu_stream_t *stream, const char *host, unsigned port, int flags); /* Transcript output levels */ diff --git a/include/mailutils/sys/url.h b/include/mailutils/sys/url.h index f782bb0c8..8e8019714 100644 --- a/include/mailutils/sys/url.h +++ b/include/mailutils/sys/url.h @@ -35,7 +35,8 @@ struct _mu_url mu_secret_t secret; char *auth; char *host; - long port; + short port; + char *portstr; char *path; char **fvpairs; int fvcount; @@ -53,7 +54,8 @@ struct _mu_url int (*_get_secret) (const mu_url_t, mu_secret_t *); int (*_get_auth) (const mu_url_t, char *, size_t, size_t *); int (*_get_host) (const mu_url_t, char *, size_t, size_t *); - int (*_get_port) (const mu_url_t, long *); + int (*_get_port) (const mu_url_t, unsigned *); + int (*_get_portstr)(const mu_url_t, char *, size_t, size_t *); int (*_get_path) (const mu_url_t, char *, size_t, size_t *); int (*_get_query) (const mu_url_t, char *, size_t, size_t *); int (*_uplevel) (const mu_url_t, mu_url_t *); diff --git a/include/mailutils/url.h b/include/mailutils/url.h index b8745bbe9..dc4801dd2 100644 --- a/include/mailutils/url.h +++ b/include/mailutils/url.h @@ -25,14 +25,15 @@ extern "C" { #endif -#define MU_URL_USER 0x0001 /* Has a user part */ -#define MU_URL_SECRET 0x0002 /* Has a secret (password) part */ -#define MU_URL_AUTH 0x0004 /* Has auth part */ -#define MU_URL_HOST 0x0008 /* Has host part */ -#define MU_URL_PORT 0x0010 /* Has port part */ -#define MU_URL_PATH 0x0020 /* Has path */ -#define MU_URL_PARAM 0x0040 /* Has parameters */ -#define MU_URL_QUERY 0x0080 /* Has query */ +#define MU_URL_SCHEME 0x0001 +#define MU_URL_USER 0x0002 /* Has a user part */ +#define MU_URL_SECRET 0x0004 /* Has a secret (password) part */ +#define MU_URL_AUTH 0x0008 /* Has auth part */ +#define MU_URL_HOST 0x0010 /* Has host part */ +#define MU_URL_PORT 0x0020 /* Has port part */ +#define MU_URL_PATH 0x0040 /* Has path */ +#define MU_URL_PARAM 0x0080 /* Has parameters */ +#define MU_URL_QUERY 0x0100 /* Has query */ #define MU_URL_CRED (MU_URL_USER | MU_URL_SECRET | MU_URL_AUTH) /* Has some of authentication credentials */ @@ -45,6 +46,28 @@ extern "C" { MU_URL_PARAM | \ MU_URL_QUERY) + /* Parser flags */ +#define MU_URL_PARSE_HEXCODE 0x0001 /* Decode % notations (RFC 1738, + section 2.2) */ +#define MU_URL_PARSE_HIDEPASS 0x0002 /* Hide password in the URL */ +#define MU_URL_PARSE_PORTSRV 0x0004 /* Use getservbyname to determine + port number */ +#define MU_URL_PARSE_PORTWC 0x0008 /* Allow wildcard (*) as a port + number (for tickets) */ +#define MU_URL_PARSE_PIPE 0x0010 /* Translate "| ..." to + "prog://..." */ +#define MU_URL_PARSE_SLASH 0x0020 /* Translate "/..." to + "file:///..." */ + +#define MU_URL_PARSE_DEFAULT \ + (MU_URL_PARSE_HEXCODE|MU_URL_PARSE_HIDEPASS|MU_URL_PARSE_PORTSRV|\ + MU_URL_PARSE_PIPE|MU_URL_PARSE_SLASH) +#define MU_URL_PARSE_ALL (MU_URL_PARSE_DEFAULT|MU_URL_PARSE_PORTWC) + +int mu_url_create_hint (mu_url_t *purl, const char *str, int flags, + mu_url_t hint); +int mu_url_copy_hints (mu_url_t url, mu_url_t hint); + int mu_url_create (mu_url_t *, const char *name); int mu_url_dup (mu_url_t old_url, mu_url_t *new_url); int mu_url_uplevel (mu_url_t url, mu_url_t *upurl); @@ -53,7 +76,6 @@ int mu_url_get_flags (mu_url_t, int *); int mu_url_has_flag (mu_url_t, int); void mu_url_destroy (mu_url_t *); -int mu_url_parse (mu_url_t); int mu_url_sget_scheme (const mu_url_t, const char **); int mu_url_aget_scheme (const mu_url_t, char **); @@ -80,7 +102,11 @@ int mu_url_get_path (const mu_url_t, char *, size_t, size_t *); int mu_url_sget_query (const mu_url_t url, size_t *qc, char ***qv); int mu_url_aget_query (const mu_url_t url, size_t *qc, char ***qv); -int mu_url_get_port (const mu_url_t, long *); +int mu_url_sget_portstr (const mu_url_t, const char **); +int mu_url_aget_portstr (const mu_url_t, char **); +int mu_url_get_portstr (const mu_url_t, char *, size_t, size_t *); + +int mu_url_get_port (const mu_url_t, unsigned *); int mu_url_sget_fvpairs (const mu_url_t url, size_t *fvc, char ***fvp); int mu_url_aget_fvpairs (const mu_url_t url, size_t *pfvc, char ***pfvp); @@ -101,11 +127,9 @@ int mu_url_is_same_path (mu_url_t, mu_url_t); int mu_url_is_same_host (mu_url_t, mu_url_t); int mu_url_is_same_port (mu_url_t, mu_url_t); -char *mu_url_decode_len (const char *s, size_t len); -char *mu_url_decode (const char *s); - int mu_url_matches_ticket (mu_url_t ticket, mu_url_t url, int *wcn); -int mu_url_init (mu_url_t url, int port, const char *scheme); + +int mu_url_decode (mu_url_t url); #ifdef __cplusplus } diff --git a/include/mailutils/util.h b/include/mailutils/util.h index 3af373cc6..9d3fff40c 100644 --- a/include/mailutils/util.h +++ b/include/mailutils/util.h @@ -42,7 +42,8 @@ int mu_unre_set_regex (const char *str, int caseflag, char **errp); int mu_unre_subject (const char *subject, const char **new_subject); int mu_is_proto (const char *p); int mu_mh_delim (const char *str); - +void mu_str_url_decode_inline (char *str); +int mu_str_url_decode (char **ptr, const char *s); /* ----------------------- */ /* Date & time functions */ 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 @@ # . 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 - . */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include -#include -#include -#include -#ifdef HAVE_STRINGS_H -# include -#endif - -#include -#include -#include -#include -#include -#include -#include - -#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: - : - or - :;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 **fvp; - int status = mu_url_sget_fvpairs (url, &fvc, &fvp); - - if (status) - return status; - - if (fvc) - { - size_t i; - - for (i = 0; i < fvc; i++) - { - const char *p; - char *q; - - for (p = param, q = fvp[i]; *p && *q && *p == *q; p++, q++) - ; - if (*p == 0) - { - if (*q == 0) - { - if (val) - *val = q; - return 0; - } - else if (*q == '=') - { - if (val) - *val = q + 1; - return 0; - } - } - } - } - - return MU_ERR_NOENT; -} - -int -mu_url_aget_fvpairs (const mu_url_t url, size_t *pfvc, char ***pfvp) -{ - size_t fvc, i; - char **fvp; - char **fvcopy; - - int rc = mu_url_sget_fvpairs (url, &fvc, &fvp); - if (rc) - return rc; - - fvcopy = calloc (fvc + 1, sizeof (fvcopy[0])); - if (!fvcopy) - return errno; - for (i = 0; i < fvc; i++) - { - if (!(fvcopy[i] = strdup (fvp[i]))) - { - mu_argcv_free (i, fvcopy); - return errno; - } - } - fvcopy[i] = NULL; - *pfvc = fvc; - *pfvp = fvcopy; - return 0; -} - -int -mu_url_aget_param (const mu_url_t url, const char *param, char **val) -{ - const char *s; - int status = mu_url_sget_param (url, param, &s); - - if (status == 0) - { - *val = strdup (s); - if (!*val) - status = ENOMEM; - } - return status; -} - -int -mu_url_get_port (const mu_url_t url, long *pport) -{ - if (url == NULL) - return EINVAL; - if (url->_get_port) - return url->_get_port (url, pport); - *pport = url->port; - return 0; -} - -const char * -mu_url_to_string (const mu_url_t url) -{ - if (url == NULL || url->name == NULL) - return ""; - return url->name; -} - -int -mu_url_set_scheme (mu_url_t url, const char *scheme) -{ - char *p; - if (!url || !scheme) - return EINVAL; - p = realloc (url->scheme, strlen (scheme) + 1); - if (!p) - return ENOMEM; - strcpy (url->scheme, scheme); - return 0; -} - -int -mu_url_is_scheme (mu_url_t url, const char *scheme) -{ - if (url && scheme && url->scheme - && mu_c_strcasecmp (url->scheme, scheme) == 0) - return 1; - - return 0; -} - -int -mu_url_is_same_port (mu_url_t url1, mu_url_t url2) -{ - long p1 = 0, p2 = 0; - - mu_url_get_port (url1, &p1); - mu_url_get_port (url2, &p2); - return (p1 == p2); -} - -/* From RFC 1738, section 2.2 */ -char * -mu_url_decode_len (const char *s, size_t len) -{ - char *d; - const char *eos = s + len; - int i; - - d = malloc (len + 1); - if (!d) - return NULL; - - for (i = 0; s < eos; i++) - { - if (*s != '%') - { - d[i] = *s; - s++; - } - else - { - unsigned long ul = 0; - - s++; - - /* don't check return value, it's correctly coded, or it's not, - in which case we just skip the garbage, this is a decoder, - not an AI project */ - - mu_hexstr2ul (&ul, s, 2); - - s += 2; - - d[i] = (char) ul; - } - } - - d[i] = 0; - - return d; -} - -char * -mu_url_decode (const char *s) -{ - return mu_url_decode_len (s, strlen (s)); -} - -#define is_wildcard(s) ((s)[0] == '*' && s[1] == 0) - -#define WEIGHT_SCHEME 3 -#define WEIGHT_USER 4 -#define WEIGHT_HOST 2 -#define WEIGHT_PORT 1 - -int -mu_url_matches_ticket (mu_url_t ticket, mu_url_t url, int *pwc) -{ - int wcnt = 0; - - if (is_wildcard (ticket->scheme)) - wcnt += WEIGHT_SCHEME; - else if (mu_c_strcasecmp (ticket->scheme, url->scheme)) - return 0; - - if (ticket->flags & MU_URL_HOST) - { - if (is_wildcard (ticket->host)) - wcnt += WEIGHT_HOST; - else if (url->flags & MU_URL_HOST) - { - if (mu_c_strcasecmp (ticket->host, url->host)) - /* FIXME: Compare IP addresses */ - return 0; - } - else - return 0; - } - else - wcnt += WEIGHT_HOST; - - if (ticket->flags & MU_URL_PORT) - { - /* FIXME: No way to put a wildcard in the ticket file */ - if (url->port & MU_URL_PORT) - { - if (ticket->port != url->port) - return 0; - else - wcnt += WEIGHT_PORT; - } - } - else - wcnt += WEIGHT_PORT; - - if (ticket->flags & MU_URL_USER) - { - if (is_wildcard (ticket->user)) - wcnt += WEIGHT_USER; - - /* If ticket has a user or pass, but url doesn't, that's OK, we were - looking for this info. But if url does have a user/pass, it - must match the ticket. */ - else if (url->flags & MU_URL_USER) - { - if (strcmp (ticket->user, url->user)) - return 0; - } - } - else - wcnt += WEIGHT_USER; - - /* Guess it matches. */ - if (pwc) - *pwc = wcnt; - return 1; -} - -int -mu_url_init (mu_url_t url, int port, const char *scheme) -{ - int status = 0; - - url->_destroy = NULL; - - status = mu_url_parse (url); - if (status) - return status; - - if (!mu_url_is_scheme (url, scheme)) - return EINVAL; - - if (url->port == 0) - url->port = port; - - return status; -} - -/* Default mailbox path generator */ -static char * -_url_path_default (const char *spooldir, const char *user, int unused) -{ - return mu_make_file_name (spooldir, user); -} - -/* Hashed indexing */ -static char * -_url_path_hashed (const char *spooldir, const char *user, int param) -{ - int i; - int ulen = strlen (user); - char *mbox; - unsigned hash; - - if (param > ulen) - param = ulen; - for (i = 0, hash = 0; i < param; i++) - hash += user[i]; - - mbox = malloc (ulen + strlen (spooldir) + 5); - sprintf (mbox, "%s/%02X/%s", spooldir, hash % 256, user); - return mbox; -} - -static int transtab[] = { - 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', - 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', - 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', - 'y', 'z', 'a', 'b', 'c', 'd', 'e', 'f', - 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', - 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', - 'w', 'x', 'y', 'z', 'a', 'b', 'c', 'd', - 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', - 'm', 'a', 'b', 'c', 'd', 'e', 'f', 'g', - 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', - 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', - 'x', 'y', 'z', 'b', 'c', 'd', 'e', 'f', - 'g', 'a', 'b', 'c', 'd', 'e', 'f', 'g', - 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', - 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', - 'x', 'y', 'z', 'b', 'c', 'd', 'e', 'f', - 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', - 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', - 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', - 'z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', - 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', - 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', - 'x', 'y', 'z', 'a', 'b', 'c', 'd', 'e', - 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', - 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', - 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', - 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', - 'y', 'z', 'b', 'c', 'd', 'e', 'f', 'g', - 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', - 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', - 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', - 'y', 'z', 'b', 'c', 'd', 'e', 'f', 'g' -}; - -/* Forward Indexing */ -static char * -_url_path_index (const char *spooldir, const char *iuser, int index_depth) -{ - const unsigned char* user = (const unsigned char*) iuser; - int i, ulen = strlen (iuser); - char *mbox, *p; - - if (ulen == 0) - return NULL; - - mbox = malloc (ulen + strlen (spooldir) + 2*index_depth + 2); - strcpy (mbox, spooldir); - p = mbox + strlen (mbox); - for (i = 0; i < index_depth && i < ulen; i++) - { - *p++ = '/'; - *p++ = transtab[ user[i] ]; - } - for (; i < index_depth; i++) - { - *p++ = '/'; - *p++ = transtab[ user[ulen-1] ]; - } - *p++ = '/'; - strcpy (p, iuser); - return mbox; -} - -/* Reverse Indexing */ -static char * -_url_path_rev_index (const char *spooldir, const char *iuser, int index_depth) -{ - const unsigned char* user = (const unsigned char*) iuser; - int i, ulen = strlen (iuser); - char *mbox, *p; - - if (ulen == 0) - return NULL; - - mbox = malloc (ulen + strlen (spooldir) + 2*index_depth + 1); - strcpy (mbox, spooldir); - p = mbox + strlen (mbox); - for (i = 0; i < index_depth && i < ulen; i++) - { - *p++ = '/'; - *p++ = transtab[ user[ulen - i - 1] ]; - } - for (; i < index_depth; i++) - { - *p++ = '/'; - *p++ = transtab[ user[0] ]; - } - *p++ = '/'; - strcpy (p, iuser); - return mbox; -} - -static int -rmselector (const char *p, void *data MU_ARG_UNUSED) -{ - return strncmp (p, "type=", 5) == 0 - || strncmp (p, "user=", 5) == 0 - || strncmp (p, "param=", 6) == 0; -} - -int -mu_url_expand_path (mu_url_t url) -{ - size_t i; - char *user = NULL; - int param = 0; - char *p; - char *(*fun) (const char *, const char *, int) = _url_path_default; - - if (url->fvcount == 0) - return 0; - - for (i = 0; i < url->fvcount; i++) - { - p = url->fvpairs[i]; - if (strncmp (p, "type=", 5) == 0) - { - char *type = p + 5; - - if (strcmp (type, "hash") == 0) - fun = _url_path_hashed; - else if (strcmp (type, "index") == 0) - fun = _url_path_index; - else if (strcmp (type, "rev-index") == 0) - fun = _url_path_rev_index; - else - return MU_ERR_NOENT; - } - else if (strncmp (p, "user=", 5) == 0) - { - user = p + 5; - } - else if (strncmp (p, "param=", 6) == 0) - { - param = strtoul (p + 6, NULL, 0); - } - } - - if (user) - { - char *p = fun (url->path, user, param); - if (p) - { - free (url->path); - url->path = p; - } - mu_argcv_remove (&url->fvcount, &url->fvpairs, rmselector, NULL); - } - else - return MU_ERR_NOENT; - - return 0; -} - -int -mu_url_get_flags (mu_url_t url, int *pf) -{ - if (!url || !pf) - return EINVAL; - *pf = url->flags; - return 0; -} - -int -mu_url_has_flag (mu_url_t url, int flags) -{ - if (!url) - return 0; - return url->flags & flags; -} - diff --git a/libmailutils/base/wicket.c b/libmailutils/base/wicket.c index 3e808c0ea..afdb87512 100644 --- a/libmailutils/base/wicket.c +++ b/libmailutils/base/wicket.c @@ -180,7 +180,9 @@ file_ticket_get_cred (mu_ticket_t ticket, mu_url_t url, const char *challenge, if (!ft->tickurl) { - int rc = mu_wicket_file_match_url (ft->filename, url, &ft->tickurl); + int rc = mu_wicket_file_match_url (ft->filename, url, + MU_URL_PARSE_ALL, + &ft->tickurl); if (rc) return rc; } @@ -245,7 +247,8 @@ _file_wicket_get_ticket (mu_wicket_t wicket, void *data, int mu_wicket_stream_match_url (mu_stream_t stream, struct mu_debug_locus *loc, - mu_url_t url, mu_url_t *pticket_url) + mu_url_t url, int parse_flags, + mu_url_t *pticket_url) { int rc; mu_url_t u = NULL; @@ -270,20 +273,13 @@ mu_wicket_stream_match_url (mu_stream_t stream, struct mu_debug_locus *loc, if (*p == 0 || *p == '#') continue; - if ((err = mu_url_create (&u, p)) != 0) + if ((err = mu_url_create_hint (&u, p, parse_flags, NULL)) != 0) { /* Skip erroneous entry */ mu_error (_("%s:%u: cannot create URL: %s"), loc->file, loc->line, mu_strerror (err)); continue; } - if ((err = mu_url_parse (u)) != 0) - { - mu_error (_("%s:%u: cannot parse URL: %s"), - loc->file, loc->line, mu_strerror (err)); - mu_url_destroy (&u); - continue; - } if (!mu_url_has_flag (u, MU_URL_USER|MU_URL_SECRET)) { @@ -326,6 +322,7 @@ mu_wicket_stream_match_url (mu_stream_t stream, struct mu_debug_locus *loc, int mu_wicket_file_match_url (const char *name, mu_url_t url, + int parse_flags, mu_url_t *pticket_url) { mu_stream_t stream; @@ -337,7 +334,8 @@ mu_wicket_file_match_url (const char *name, mu_url_t url, return rc; loc.file = name; loc.line = 0; - rc = mu_wicket_stream_match_url (stream, &loc, url, pticket_url); + rc = mu_wicket_stream_match_url (stream, &loc, url, parse_flags, + pticket_url); mu_stream_close (stream); mu_stream_destroy (&stream); return rc; diff --git a/libmailutils/mailbox/folder.c b/libmailutils/mailbox/folder.c index f6e75c03d..fe918230e 100644 --- a/libmailutils/mailbox/folder.c +++ b/libmailutils/mailbox/folder.c @@ -157,9 +157,7 @@ mu_folder_create (mu_folder_t *pfolder, const char *name) rc = mu_url_create (&url, name); if (rc) return rc; - rc = mu_url_parse (url); - if (rc == 0) - rc = mu_folder_create_from_record (pfolder, url, NULL); + rc = mu_folder_create_from_record (pfolder, url, NULL); if (rc) mu_url_destroy (&url); return rc; diff --git a/libmailutils/mailbox/mailbox.c b/libmailutils/mailbox/mailbox.c index d95ce2d96..0677e88ff 100644 --- a/libmailutils/mailbox/mailbox.c +++ b/libmailutils/mailbox/mailbox.c @@ -185,9 +185,7 @@ _create_mailbox (mu_mailbox_t *pmbox, const char *name) status = mu_url_create (&url, name); if (status) return status; - status = mu_url_parse (url); - if (status == 0) - status = _create_mailbox0 (pmbox, url, name); + status = _create_mailbox0 (pmbox, url, name); if (status) mu_url_destroy (&url); return status; @@ -224,9 +222,7 @@ mu_mailbox_create_from_record (mu_mailbox_t *pmbox, mu_record_t record, rc = mu_url_create (&url, name); if (rc) return rc; - rc = mu_url_parse (url); - if (rc == 0) - rc = _mailbox_create_from_record (pmbox, record, url, name); + rc = _mailbox_create_from_record (pmbox, record, url, name); if (rc) mu_url_destroy (&url); return rc; diff --git a/libmailutils/mailer/mailer.c b/libmailutils/mailer/mailer.c index 59559ebe8..01fb6d31e 100644 --- a/libmailutils/mailer/mailer.c +++ b/libmailutils/mailer/mailer.c @@ -168,9 +168,7 @@ mu_mailer_create (mu_mailer_t * pmailer, const char *name) status = mu_url_create (&url, name); if (status) return status; - status = mu_url_parse (url); - if (status == 0) - status = mu_mailer_create_from_url (pmailer, url); + status = mu_mailer_create_from_url (pmailer, url); if (status) mu_url_destroy (&url); return status; diff --git a/libmailutils/mime/mimehdr.c b/libmailutils/mime/mimehdr.c index 7bc801b2c..863566c25 100644 --- a/libmailutils/mime/mimehdr.c +++ b/libmailutils/mime/mimehdr.c @@ -29,8 +29,6 @@ #include #include #include -#include /* FIXME: for mu_url_decode, which should - be renamed! */ #include #include #include @@ -480,9 +478,9 @@ mu_mimehdr_decode_param (const char *value, int flags, } else { - decoded = mu_url_decode (value); - if (!decoded) - return ENOMEM; + rc = mu_str_url_decode (&decoded, value); + if (rc) + return rc; if ((flags & MU_MIMEHDR_CSINFO) && (lang = strchr (decoded, '\'')) diff --git a/libmailutils/stream/tcp.c b/libmailutils/stream/tcp.c index b53511a94..c719be81f 100644 --- a/libmailutils/stream/tcp.c +++ b/libmailutils/stream/tcp.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -52,7 +53,7 @@ struct _tcp_instance struct _mu_stream stream; int fd; char *host; - int port; + unsigned short port; int state; unsigned long address; unsigned long source_addr; @@ -304,7 +305,7 @@ _create_tcp_stream (int flags) int mu_tcp_stream_create_with_source_ip (mu_stream_t *pstream, - const char *host, int port, + const char *host, unsigned port, unsigned long source_ip, int flags) { @@ -315,7 +316,7 @@ mu_tcp_stream_create_with_source_ip (mu_stream_t *pstream, if (host == NULL) return MU_ERR_TCP_NO_HOST; - if (port < 1) + if (port > USHRT_MAX) return MU_ERR_TCP_NO_PORT; tcp = _create_tcp_stream (flags | MU_STREAM_RDWR); @@ -341,7 +342,7 @@ mu_tcp_stream_create_with_source_ip (mu_stream_t *pstream, int mu_tcp_stream_create_with_source_host (mu_stream_t *stream, - const char *host, int port, + const char *host, unsigned port, const char *source_host, int flags) { @@ -354,7 +355,7 @@ mu_tcp_stream_create_with_source_host (mu_stream_t *stream, } int -mu_tcp_stream_create (mu_stream_t *stream, const char *host, int port, +mu_tcp_stream_create (mu_stream_t *stream, const char *host, unsigned port, int flags) { return mu_tcp_stream_create_with_source_ip (stream, host, port, diff --git a/libmailutils/string/Makefile.am b/libmailutils/string/Makefile.am index 3f11adef4..485df4a67 100644 --- a/libmailutils/string/Makefile.am +++ b/libmailutils/string/Makefile.am @@ -34,6 +34,7 @@ libstring_la_SOURCES = \ asprintf.c\ muctype.c\ vasnprintf.c\ - mkfilename.c + mkfilename.c\ + xdecode.c INCLUDES = @MU_LIB_COMMON_INCLUDES@ -I/libmailutils diff --git a/libmailutils/string/xdecode.c b/libmailutils/string/xdecode.c new file mode 100644 index 000000000..e802bf67c --- /dev/null +++ b/libmailutils/string/xdecode.c @@ -0,0 +1,73 @@ +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 1999, 2000, 2001, 2002, 2003, 2005, 2006, 2007, 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 + . */ + +#if HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + +/* From RFC 1738, section 2.2 */ +void +mu_str_url_decode_inline (char *s) +{ + char *d; + + d = strchr (s, '%'); + if (!d) + return; + + for (s = d; *s; ) + { + if (*s != '%') + { + *d++ = *s++; + } + else + { + unsigned long ul = 0; + + s++; + + /* don't check return value, it's correctly coded, or it's not, + in which case we just skip the garbage, this is a decoder, + not an AI project */ + + mu_hexstr2ul (&ul, s, 2); + + s += 2; + + *d++ = (char) ul; + } + } + + *d = 0; +} + +int +mu_str_url_decode (char **ptr, const char *s) +{ + char *d = strdup (s); + if (!d) + return ENOMEM; + mu_str_url_decode_inline (d); + *ptr = d; + return 0; +} diff --git a/libmailutils/tests/url-parse.c b/libmailutils/tests/url-parse.c index 92fd4f166..c87753c05 100644 --- a/libmailutils/tests/url-parse.c +++ b/libmailutils/tests/url-parse.c @@ -77,7 +77,7 @@ int main () { char str[1024]; - long port = 0; + unsigned port = 0; mu_url_t u = NULL; while (fgets (str, sizeof (str), stdin) != NULL) @@ -95,11 +95,6 @@ main () str, rc, mu_strerror (rc)); exit (1); } - if ((rc = mu_url_parse (u)) != 0) - { - fprintf (stderr, "%s\n", mu_errname (rc)); - continue; - } GET_AND_PRINT (scheme, u, buf, rc); GET_AND_PRINT (user, u, buf, rc); @@ -127,7 +122,7 @@ main () mu_error ("cannot get %s: %s", "port", mu_strerror (rc)); exit (1); } - printf ("port %ld\n", port); + printf ("port %hu\n", port); GET_AND_PRINT (path, u, buf, rc); print_fvpairs (u); diff --git a/libmailutils/tests/wicket.c b/libmailutils/tests/wicket.c index b6215cbf9..57857dafc 100644 --- a/libmailutils/tests/wicket.c +++ b/libmailutils/tests/wicket.c @@ -38,15 +38,10 @@ match_string (const char *str) str, rc, mu_strerror (rc)); return; } - if ((rc = mu_url_parse (u)) != 0) - { - fprintf (stderr, "%s\n", mu_errname (rc)); - return; - } MU_ASSERT (mu_stream_seek (stream, 0, MU_SEEK_SET, NULL)); loc.file = name; loc.line = 0; - rc = mu_wicket_stream_match_url (stream, &loc, u, &url); + rc = mu_wicket_stream_match_url (stream, &loc, u, MU_URL_PARSE_ALL, &url); switch (rc) { case 0: 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 +# . + +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 + . */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#ifdef HAVE_STRINGS_H +# include +#endif + +#include +#include +#include +#include +#include + +/* 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 + . */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#ifdef HAVE_STRINGS_H +# include +#endif + +#include +#include +#include +#include +#include + +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 (