From 36868ac9ddc6b4e521913858b04ace62d8edfa5a Mon Sep 17 00:00:00 2001 From: Sergey Poznyakoff Date: Fri, 28 Dec 2007 15:27:43 +0000 Subject: Additional mailbox URL parameters `type', `user' and `param' can appear in any local URLs. * TODO, NEWS: Update. * examples/url-parse.c: Print field/value pairs. * include/mailutils/argcv.h (MU_ARGCV_RETURN_DELIMS): New macro. (mu_argcv_get_np): New function. (mu_argcv_remove): New function. * include/mailutils/mutil.h (mu_scheme_autodetect_p): Change prototype. * include/mailutils/registrar.h (mu_registrar_lookup_url): New function. (struct _mu_record._is_scheme): Change signature. * include/mailutils/url.h (mu_url_sget_fvpairs) (mu_url_aget_fvpairs): New functions. (mu_url_expand_path): New function. * libproto/imap/folder.c (folder_imap_list): Fix signature. * libproto/nntp/folder.c (nntp_folder_list): Fix signature. * libproto/include/amd.h (amd_url_init): Remove. * libproto/include/registrar0.h: Fix scheme defines. * libproto/include/url0.h (struct _mu_url.fvpairs,fvcount): New members. * libproto/maildir/folder.c (_maildir_is_scheme): Change signature. (_maildir_url_init): Remove (_maildir_record): Remove url_init. * libproto/mbox/folder.c (_path_record): Remove url_init. (_mbox_record): Use mu_url_expand_path as url_init. (_path_is_scheme): Change signature. * libproto/mh/folder.c (_mh_is_scheme): Change signature. (_mh_url_init): Remove. (_mh_record): Use mu_url_expand_path as url_init. * libproto/mbox/Makefile.am (libmu_mbox_la_SOURCES): Remove url.c * libproto/mbox/url.c: Remove. * mail/mail.h, mail/util.c (util_url_to_string): New function. * mail/quit.c, mail/summary.c: Use util_url_to_string where appropriate. * mailbox/amd.c (amd_url_destroy, amd_url_init): Remove. * mailbox/argcv.c (mu_argcv_get_np): New function. (argcv_scan): Change signature. All callers updated. (argcv_get_n): Rewrite using argcv_get_np. (mu_argcv_remove): New function. * mailbox/file_stream.c (struct _prog_stream.argc): Fix data type. * mailbox/folder.c (mu_folder_create_from_record): URL initializer is optional. * mailbox/gdebug.c (mu_global_debug_from_string): Fix datatype of argc. * mailbox/mailbox.c (mailbox_folder_create): Rewrite. (_create_mailbox): Split off _create_mailbox0 function. Make URL initializer optional. * mailbox/mutil.c (mu_scheme_autodetect_p): Rewrite. * mailbox/registrar.c (mu_registrar_lookup_url): New function. (mu_registrar_lookup): Rewrite using mu_registrar_lookup_url. (mu_record_is_scheme,mu_record_set_is_scheme): Change signature. * mailbox/url.c (mu_url_destroy): Destroy fvpairs. (url_parse0): Use scheme "file" for URLs beginning with a /. Parse parameters. (mu_url_sget_fvpairs, mu_url_aget_fvpairs): New functions. (mu_url_expand_path): New function. * mailbox/testsuite/Urls: Update. * pop3d/bulletin.c (set_bulletin_db,set_bulletin_source): Allocate string storage. (read_bulletin_db): Return 0 if no record was found. (get_last_delivered_num): Return error code. (deliver_pending_bulletins): Rewrite. * pop3d/capa.c (pop3d_capa): Bugfix. --- ChangeLog | 74 ++++++++ NEWS | 33 +++- TODO | 4 +- examples/url-parse.c | 17 ++ include/mailutils/argcv.h | 8 + include/mailutils/mutil.h | 2 +- include/mailutils/registrar.h | 8 +- include/mailutils/url.h | 10 +- lib/.cvsignore | 2 + libproto/imap/folder.c | 5 +- libproto/include/amd.h | 1 - libproto/include/registrar0.h | 22 +-- libproto/include/url0.h | 3 +- libproto/maildir/folder.c | 28 +-- libproto/mbox/Makefile.am | 3 +- libproto/mbox/folder.c | 22 ++- libproto/mbox/url.c | 301 ------------------------------ libproto/mh/folder.c | 26 +-- libproto/nntp/folder.c | 4 +- m4/.cvsignore | 1 + mail/mail.h | 2 + mail/quit.c | 6 +- mail/summary.c | 2 +- mail/util.c | 15 ++ mailbox/amd.c | 46 ----- mailbox/argcv.c | 178 +++++++++++++----- mailbox/file_stream.c | 2 +- mailbox/folder.c | 25 ++- mailbox/gdebug.c | 2 +- mailbox/mailbox.c | 74 ++++++-- mailbox/mutil.c | 17 +- mailbox/registrar.c | 36 +++- mailbox/testsuite/Urls | 37 ++++ mailbox/url.c | 419 +++++++++++++++++++++++++++++++++--------- pop3d/bulletin.c | 29 +-- pop3d/capa.c | 2 +- 36 files changed, 850 insertions(+), 616 deletions(-) delete mode 100644 libproto/mbox/url.c diff --git a/ChangeLog b/ChangeLog index d113738e8..8fc4359bd 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,77 @@ +2007-12-28 Sergey Poznyakoff + + Additional mailbox URL parameters `type', `user' and `param' can + appear in any local URLs. + + * TODO, NEWS: Update. + + * examples/url-parse.c: Print field/value pairs. + * include/mailutils/argcv.h (MU_ARGCV_RETURN_DELIMS): New macro. + (mu_argcv_get_np): New function. + (mu_argcv_remove): New function. + * include/mailutils/mutil.h (mu_scheme_autodetect_p): Change + prototype. + * include/mailutils/registrar.h (mu_registrar_lookup_url): New + function. + (struct _mu_record._is_scheme): Change signature. + * include/mailutils/url.h (mu_url_sget_fvpairs) + (mu_url_aget_fvpairs): New functions. + (mu_url_expand_path): New function. + + * libproto/imap/folder.c (folder_imap_list): Fix signature. + * libproto/nntp/folder.c (nntp_folder_list): Fix signature. + * libproto/include/amd.h (amd_url_init): Remove. + * libproto/include/registrar0.h: Fix scheme defines. + * libproto/include/url0.h (struct _mu_url.fvpairs,fvcount): New + members. + * libproto/maildir/folder.c (_maildir_is_scheme): Change + signature. + (_maildir_url_init): Remove + (_maildir_record): Remove url_init. + * libproto/mbox/folder.c (_path_record): Remove url_init. + (_mbox_record): Use mu_url_expand_path as url_init. + (_path_is_scheme): Change signature. + * libproto/mh/folder.c (_mh_is_scheme): Change signature. + (_mh_url_init): Remove. + (_mh_record): Use mu_url_expand_path as url_init. + * libproto/mbox/Makefile.am (libmu_mbox_la_SOURCES): Remove url.c + * libproto/mbox/url.c: Remove. + + * mail/mail.h, mail/util.c (util_url_to_string): New function. + * mail/quit.c, mail/summary.c: Use util_url_to_string where + appropriate. + * mailbox/amd.c (amd_url_destroy, amd_url_init): Remove. + * mailbox/argcv.c (mu_argcv_get_np): New function. + (argcv_scan): Change signature. All callers updated. + (argcv_get_n): Rewrite using argcv_get_np. + (mu_argcv_remove): New function. + + * mailbox/file_stream.c (struct _prog_stream.argc): Fix data type. + * mailbox/folder.c (mu_folder_create_from_record): URL initializer + is optional. + * mailbox/gdebug.c (mu_global_debug_from_string): Fix datatype of + argc. + * mailbox/mailbox.c (mailbox_folder_create): Rewrite. + (_create_mailbox): Split off _create_mailbox0 function. + Make URL initializer optional. + * mailbox/mutil.c (mu_scheme_autodetect_p): Rewrite. + * mailbox/registrar.c (mu_registrar_lookup_url): New function. + (mu_registrar_lookup): Rewrite using mu_registrar_lookup_url. + (mu_record_is_scheme,mu_record_set_is_scheme): Change signature. + * mailbox/url.c (mu_url_destroy): Destroy fvpairs. + (url_parse0): Use scheme "file" for URLs beginning with a /. + Parse parameters. + (mu_url_sget_fvpairs, mu_url_aget_fvpairs): New functions. + (mu_url_expand_path): New function. + * mailbox/testsuite/Urls: Update. + + * pop3d/bulletin.c (set_bulletin_db,set_bulletin_source): Allocate + string storage. + (read_bulletin_db): Return 0 if no record was found. + (get_last_delivered_num): Return error code. + (deliver_pending_bulletins): Rewrite. + * pop3d/capa.c (pop3d_capa): Bugfix. + 2007-12-21 Sergey Poznyakoff * examples/lsf.c: Use mu_folder_enumerate + callback function, for diff --git a/NEWS b/NEWS index 1730f164c..634f30bad 100644 --- a/NEWS +++ b/NEWS @@ -1,4 +1,4 @@ -GNU mailutils NEWS -- history of user-visible changes. 2007-12-19 +GNU mailutils NEWS -- history of user-visible changes. 2007-12-28 Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. See the end of file for copying conditions. @@ -26,6 +26,11 @@ The programs using configuration file facility also understand the output the detailed description of configuration file statements that affect the given program. +** URL parameters. + +Additional mailbox URL parameters `type', `user' and `param' can +appear in any local URLs. + ** New utility `maidag' Maidag is a MAIl Delivery AGent. It is a general-purpose MDA able to @@ -185,6 +190,9 @@ extern int mu_url_aget_path (const mu_url_t, char **); extern int mu_url_sget_query (const mu_url_t, const char **); extern int mu_url_aget_query (const mu_url_t, char **); +int mu_url_sget_fvpairs (const mu_url_t, size_t *, char ***); +int mu_url_aget_fvpairs (const mu_url_t, size_t *, char ***); + ** ACL A set of functions implements general-purpose access control lists. @@ -227,6 +235,29 @@ that can be done over them is mu_mailbox_append_message. E.g., appending to the URL `remote+smtp://127.0.0.1:24' is equivalent to sending a message using mailer `smtp://127.0.0.1:24'. +** New argcv functions. + +- int mu_argcv_get_np (const char *command, int len, + const char *delim, const char *cmnt, + int flags, + int *pargc, char ***pargv, char **endp); + +This function is an alternative entry point to +mu_argcv_get/mu_argcv_get_n functions. The resulting argv will contain +non-whitespace delimiters only if flags contains the bit +MU_ARGCV_RETURN_DELIMS. + +- void mu_argcv_remove (int *pargc, char ***pargv, + int (*sel) (const char *, void *), void *); + +Removes from pargc/pargv all elements for which the sel function +returns true. + +** New registry functions. + +- int mu_registrar_lookup_url (mu_url_t url, int flags, + mu_record_t *precord, int *pflags); + ** Fixed parsing of URLs similar to file:///a/b. It is parsed as an absolute file name `/a/b'. diff --git a/TODO b/TODO index 01b987335..c229b7141 100644 --- a/TODO +++ b/TODO @@ -1,7 +1,9 @@ -GNU mailutils TODO list. 2007-12-07 +GNU mailutils TODO list. 2007-12-28 Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. +* Fix folder_imap_list in libproto/imap/folder.c + * Documentation * Review the code and use mu_vartab_* and mu_kwd_* functions where diff --git a/examples/url-parse.c b/examples/url-parse.c index 2d10adecc..cc3e037a1 100644 --- a/examples/url-parse.c +++ b/examples/url-parse.c @@ -39,6 +39,22 @@ } \ printf ("\t" #field " <%s>\n", buf) +static void +print_fvpairs (mu_url_t url) +{ + size_t fvc, i; + char **fvp; + int rc = mu_url_sget_fvpairs (url, &fvc, &fvp); + if (rc) + { + mu_error ("cannot get F/V pairs: %s", mu_strerror (rc)); + exit (1); + } + if (fvc == 0) + return; + for (i = 0; i < fvc; i++) + printf ("\tparam[%d] <%s>\n", i, fvp[i]); +} int main () @@ -84,6 +100,7 @@ main () printf ("\tport %ld\n", port); GET_AND_PRINT (path, u, buf, rc); + print_fvpairs (u); GET_AND_PRINT (query, u, buf, rc); mu_url_destroy (&u); diff --git a/include/mailutils/argcv.h b/include/mailutils/argcv.h index a880f05c3..bbae929f9 100644 --- a/include/mailutils/argcv.h +++ b/include/mailutils/argcv.h @@ -28,12 +28,18 @@ extern "C" { #endif +#define MU_ARGCV_RETURN_DELIMS 0x01 + extern int mu_argcv_get (const char *command, const char *delim, const char* cmnt, int *argc, char ***argv); extern int mu_argcv_get_n (const char *command, int len, const char *delim, const char *cmnt, int *argc, char ***argv); +extern int mu_argcv_get_np (const char *command, int len, + const char *delim, const char *cmnt, + int flags, + int *pargc, char ***pargv, char **endp); extern int mu_argcv_string (int argc, char **argv, char **string); extern int mu_argcv_free (int argc, char **argv); @@ -42,6 +48,8 @@ extern int mu_argcv_quote_char (int c); extern size_t mu_argcv_quoted_length (const char *str, int *quote); extern void mu_argcv_unquote_copy (char *dst, const char *src, size_t n); extern void mu_argcv_quote_copy (char *dst, const char *src); +extern void mu_argcv_remove (int *pargc, char ***pargv, + int (*sel) (const char *, void *), void *); #ifdef __cplusplus } diff --git a/include/mailutils/mutil.h b/include/mailutils/mutil.h index 6802de8cf..16765aee0 100644 --- a/include/mailutils/mutil.h +++ b/include/mailutils/mutil.h @@ -128,7 +128,7 @@ extern int mu_unre_subject (const char *subject, const char **new_subject); extern char *mu_charset_lookup (char *lang, char *terr); extern int mu_true_answer_p (const char *p); -extern int mu_scheme_autodetect_p (const char *scheme, const char **path); +extern int mu_scheme_autodetect_p (mu_url_t); struct timeval; diff --git a/include/mailutils/registrar.h b/include/mailutils/registrar.h index 03836b85e..ecc904d32 100644 --- a/include/mailutils/registrar.h +++ b/include/mailutils/registrar.h @@ -38,7 +38,7 @@ struct _mu_record void *data; /* back pointer. */ /* Stub functions to override. The default is to return the fields. */ - int (*_is_scheme) (mu_record_t, const char *, int); + int (*_is_scheme) (mu_record_t, mu_url_t, int); int (*_get_url) (mu_record_t, int (*(*_mu_url)) (mu_url_t)); int (*_get_mailbox) (mu_record_t, int (*(*_mu_mailbox)) (mu_mailbox_t)); int (*_get_mailer) (mu_record_t, int (*(*_mu_mailer)) (mu_mailer_t)); @@ -51,14 +51,16 @@ extern int mu_registrar_get_list (mu_list_t *) __attribute__ ((deprecated)); extern int mu_registrar_lookup (const char *name, int flags, mu_record_t *precord, int *pflags); +extern int mu_registrar_lookup_url (mu_url_t url, int flags, + mu_record_t *precord, int *pflags); extern int mu_registrar_record (mu_record_t); extern int mu_unregistrar_record (mu_record_t); /* Scheme. */ -extern int mu_record_is_scheme (mu_record_t, const char *, int flags); +extern int mu_record_is_scheme (mu_record_t, mu_url_t, int flags); extern int mu_record_set_scheme (mu_record_t, const char *); extern int mu_record_set_is_scheme (mu_record_t, - int (*_is_scheme) (mu_record_t, const char *, int)); + int (*_is_scheme) (mu_record_t, mu_url_t, int)); /* Url. */ extern int mu_record_get_url (mu_record_t, int (*(*)) (mu_url_t)); diff --git a/include/mailutils/url.h b/include/mailutils/url.h index 69985f175..52a42264a 100644 --- a/include/mailutils/url.h +++ b/include/mailutils/url.h @@ -59,9 +59,13 @@ extern int mu_url_get_query (const mu_url_t, char *, size_t, size_t *); extern int mu_url_get_port (const mu_url_t, long *); +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); + +extern int mu_url_expand_path (mu_url_t url); extern const char *mu_url_to_string (const mu_url_t); -extern int mu_url_is_scheme (mu_url_t, const char* scheme); +extern int mu_url_is_scheme (mu_url_t, const char *scheme); extern int mu_url_is_same_scheme (mu_url_t, mu_url_t); extern int mu_url_is_same_user (mu_url_t, mu_url_t); @@ -69,11 +73,11 @@ extern int mu_url_is_same_path (mu_url_t, mu_url_t); extern int mu_url_is_same_host (mu_url_t, mu_url_t); extern int mu_url_is_same_port (mu_url_t, mu_url_t); -extern char* mu_url_decode (const char *s); +extern char *mu_url_decode (const char *s); extern int mu_url_is_ticket (mu_url_t ticket, mu_url_t url); extern int mu_url_init (mu_url_t url, int port, const char *scheme); - + #ifdef __cplusplus } #endif diff --git a/lib/.cvsignore b/lib/.cvsignore index 494fca35f..b01887cc1 100644 --- a/lib/.cvsignore +++ b/lib/.cvsignore @@ -143,6 +143,8 @@ streq.h strerror.c string.h string.in.h +strings.h +strings.in.h stripslash.c strncasecmp.c strndup.c diff --git a/libproto/imap/folder.c b/libproto/imap/folder.c index 815b4ecfe..d718a4d3d 100644 --- a/libproto/imap/folder.c +++ b/libproto/imap/folder.c @@ -112,7 +112,7 @@ static int folder_imap_close (mu_folder_t); static void folder_imap_destroy (mu_folder_t); static int folder_imap_delete (mu_folder_t, const char *); static int folder_imap_list (mu_folder_t, const char *, void *, - size_t, + int, size_t, mu_list_t, mu_folder_enumerate_fp efp, void *edp); static int folder_imap_lsub (mu_folder_t, const char *, const char *, @@ -975,9 +975,10 @@ glob_to_imap (const char *pat, int recursive) return ret; } +/* FIXME: Flags unused */ static int folder_imap_list (mu_folder_t folder, const char *ref, void *name, - size_t max_level, + int flags, size_t max_level, mu_list_t flist, mu_folder_enumerate_fp efp, void *edp) { diff --git a/libproto/include/amd.h b/libproto/include/amd.h index 505b48df6..3c9c5ab94 100644 --- a/libproto/include/amd.h +++ b/libproto/include/amd.h @@ -99,7 +99,6 @@ int _amd_message_insert (struct _amd_data *mhd, struct _amd_message *msg); int amd_message_stream_open (struct _amd_message *mhm); void amd_message_stream_close (struct _amd_message *mhm); void amd_cleanup (void *arg); -int amd_url_init (mu_url_t url, const char *scheme); struct _amd_message *_amd_get_message (struct _amd_data *amd, size_t msgno); int amd_msg_lookup (struct _amd_data *amd, struct _amd_message *msg, size_t *pret); diff --git a/libproto/include/registrar0.h b/libproto/include/registrar0.h index 571c8a5fb..13d114cf8 100644 --- a/libproto/include/registrar0.h +++ b/libproto/include/registrar0.h @@ -36,62 +36,60 @@ extern "C" { Perhaps they can be changed? */ #define MU_POP_PORT 110 -#define MU_POP_SCHEME "pop://" +#define MU_POP_SCHEME "pop" #define MU_POP_SCHEME_LEN (sizeof (MU_POP_SCHEME) - 1) extern int _url_pop_init (mu_url_t); extern int _mailbox_pop_init (mu_mailbox_t); extern int _folder_pop_init (mu_folder_t); #define MU_POPS_PORT 995 -#define MU_POPS_SCHEME "pops://" +#define MU_POPS_SCHEME "pops" #define MU_POPS_SCHEME_LEN (sizeof (MU_POPS_SCHEME) - 1) extern int _url_pops_init (mu_url_t); extern int _mailbox_pops_init (mu_mailbox_t); #define MU_IMAP_PORT 143 -#define MU_IMAP_SCHEME "imap://" +#define MU_IMAP_SCHEME "imap" #define MU_IMAP_SCHEME_LEN (sizeof (MU_IMAP_SCHEME) - 1) extern int _url_imap_init (mu_url_t); extern int _mailbox_imap_init (mu_mailbox_t); extern int _folder_imap_init (mu_folder_t); #define MU_IMAPS_PORT 993 -#define MU_IMAPS_SCHEME "imaps://" +#define MU_IMAPS_SCHEME "imaps" #define MU_IMAPS_SCHEME_LEN (sizeof (MU_IMAPS_SCHEME) - 1) extern int _url_imaps_init (mu_url_t); extern int _mailbox_imaps_init (mu_mailbox_t); -#define MU_MBOX_SCHEME "mbox:" +#define MU_MBOX_SCHEME "mbox" #define MU_MBOX_SCHEME_LEN (sizeof (MU_MBOX_SCHEME) - 1) -extern int _url_mbox_init (mu_url_t); extern int _mailbox_mbox_init (mu_mailbox_t); extern int _folder_mbox_init (mu_folder_t); -#define MU_FILE_SCHEME "file:" +#define MU_FILE_SCHEME "file" #define MU_FILE_SCHEME_LEN (sizeof (MU_FILE_SCHEME) - 1) #define MU_PATH_SCHEME "/" #define MU_PATH_SCHEME_LEN (sizeof (MU_PATH_SCHEME) - 1) -extern int _url_path_init (mu_url_t); extern int _mailbox_path_init (mu_mailbox_t); extern int _folder_path_init (mu_folder_t); -#define MU_SMTP_SCHEME "smtp://" +#define MU_SMTP_SCHEME "smtp" #define MU_SMTP_SCHEME_LEN (sizeof (MU_SMTP_SCHEME) - 1) #define MU_SMTP_PORT 25 extern int _url_smtp_init (mu_url_t); extern int _mailer_smtp_init (mu_mailer_t); -#define MU_SENDMAIL_SCHEME "sendmail:" +#define MU_SENDMAIL_SCHEME "sendmail" #define MU_SENDMAIL_SCHEME_LEN (sizeof (MU_SENDMAIL_SCHEME) - 1) extern int _url_sendmail_init (mu_url_t); extern int _mailer_sendmail_init (mu_mailer_t); -#define MU_MH_SCHEME "mh:" +#define MU_MH_SCHEME "mh" #define MU_MH_SCHEME_LEN (sizeof (MU_MH_SCHEME) - 1) extern int _mailbox_mh_init (mu_mailbox_t mailbox); -#define MU_MAILDIR_SCHEME "maildir:" +#define MU_MAILDIR_SCHEME "maildir" #define MU_MAILDIR_SCHEME_LEN (sizeof (MU_MAILDIR_SCHEME) - 1) extern int _mailbox_maildir_init (mu_mailbox_t mailbox); diff --git a/libproto/include/url0.h b/libproto/include/url0.h index f4cc8af81..a2485e4e0 100644 --- a/libproto/include/url0.h +++ b/libproto/include/url0.h @@ -40,9 +40,10 @@ struct _mu_url char *host; long port; char *path; + char **fvpairs; + int fvcount; char *query; - void *data; void (*_destroy) (mu_url_t url); diff --git a/libproto/maildir/folder.c b/libproto/maildir/folder.c index 3fe14d76e..cc91b32d8 100644 --- a/libproto/maildir/folder.c +++ b/libproto/maildir/folder.c @@ -33,6 +33,7 @@ #include #include +#include #include static int @@ -56,22 +57,21 @@ dir_exists (const char *name, const char *suf) } static int -_maildir_is_scheme (mu_record_t record, const char *url, int flags) +_maildir_is_scheme (mu_record_t record, mu_url_t url, int flags) { - const char *path; - - if (!url || !record->scheme) - return 0; - - if (strncmp (record->scheme, url, strlen (record->scheme)) == 0) + if (mu_url_is_scheme (url, record->scheme)) return MU_FOLDER_ATTRIBUTE_ALL & flags; - if (mu_scheme_autodetect_p (url, &path)) + if (mu_scheme_autodetect_p (url)) { /* Attemp auto-detection */ + const char *path; struct stat st; int rc = 0; + if (mu_url_sget_path (url, &path)) + return 0; + if (stat (path, &st) < 0) return 0; @@ -89,21 +89,11 @@ _maildir_is_scheme (mu_record_t record, const char *url, int flags) return 0; } -/* - MAILDIR url - maildir:path -*/ -int -_maildir_url_init (mu_url_t url) -{ - return amd_url_init (url, MU_MAILDIR_SCHEME); -} - static struct _mu_record _maildir_record = { MU_MAILDIR_PRIO, MU_MAILDIR_SCHEME, - _maildir_url_init, /* Url init. */ + mu_url_expand_path, /* Url init. */ _mailbox_maildir_init, /* Mailbox init. */ NULL, /* Mailer init. */ _maildir_folder_init, /* Folder init. */ diff --git a/libproto/mbox/Makefile.am b/libproto/mbox/Makefile.am index 48a7fd2ef..8bc7290d2 100644 --- a/libproto/mbox/Makefile.am +++ b/libproto/mbox/Makefile.am @@ -26,6 +26,5 @@ libmu_mbox_la_SOURCES = \ folder.c\ mbox.c\ mboxscan.c\ - mbox0.h\ - url.c + mbox0.h diff --git a/libproto/mbox/folder.c b/libproto/mbox/folder.c index 7e8354949..cf23178f3 100644 --- a/libproto/mbox/folder.c +++ b/libproto/mbox/folder.c @@ -50,7 +50,7 @@ static struct _mu_record _mbox_record = { MU_MBOX_PRIO, MU_MBOX_SCHEME, - _url_mbox_init, /* Mailbox init. */ + mu_url_expand_path, /* URL init. */ _mailbox_mbox_init, /* Mailbox init. */ NULL, /* Mailer init. */ _folder_mbox_init, /* Folder init. */ @@ -64,19 +64,18 @@ static struct _mu_record _mbox_record = mu_record_t mu_mbox_record = &_mbox_record; static int -_path_is_scheme (mu_record_t record, const char *url, int flags) +_path_is_scheme (mu_record_t record, mu_url_t url, int flags) { int rc = 0; - const char *path; if (url && record->scheme) { - if (mu_scheme_autodetect_p (url, &path)) - /* implies: - if (strncmp (record->scheme, url, strlen(record->scheme)) == 0) */ + if (mu_scheme_autodetect_p (url)) { struct stat st; - + const char *path; + + mu_url_sget_path (url, &path); if (stat (path, &st) < 0) { if (errno == ENOENT) @@ -92,6 +91,10 @@ _path_is_scheme (mu_record_t record, const char *url, int flags) } else if (flags & MU_FOLDER_ATTRIBUTE_FILE) { +#if 0 + /* This effectively sieves out all non-mailbox files, + but it makes mu_folder_enumerate crawl, which is + intolerable for imap4d LIST command. */ int fd = open (path, O_RDONLY); if (fd != -1) { @@ -101,6 +104,9 @@ _path_is_scheme (mu_record_t record, const char *url, int flags) rc |= MU_FOLDER_ATTRIBUTE_FILE; close (fd); } +#else + rc |= MU_FOLDER_ATTRIBUTE_FILE; +#endif } } @@ -116,7 +122,7 @@ static struct _mu_record _path_record = { MU_PATH_PRIO, MU_PATH_SCHEME, - _url_path_init, /* Mailbox init. */ + NULL, /* URL init. */ _mailbox_mbox_init, /* Mailbox init. */ NULL, /* Mailer init. */ _folder_mbox_init, /* Folder init. */ diff --git a/libproto/mbox/url.c b/libproto/mbox/url.c deleted file mode 100644 index 6841e13a2..000000000 --- a/libproto/mbox/url.c +++ /dev/null @@ -1,301 +0,0 @@ -/* GNU Mailutils -- a suite of utilities for electronic mail - Copyright (C) 1999, 2000, 2003, 2007 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, write to the - Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301 USA */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include -#include -#include -#include - -#ifdef HAVE_STRINGS_H -# include -#endif - -#include -#include -#include -#include - -static void url_mbox_destroy (mu_url_t purl); - -static void -url_mbox_destroy (mu_url_t url MU_ARG_UNUSED) -{ -} - -/* Default mailbox path generator */ -static char * -_url_path_default (const char *spooldir, const char *user, int unused) -{ - char *mbox = malloc (sizeof(spooldir) + strlen(user) + 2); - if (!mbox) - errno = ENOMEM; - else - sprintf (mbox, "%s/%s", spooldir, user); - return mbox; -} - -/* 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; -} - -/* - UNIX Mbox - mbox:path[;type=TYPE][;param=PARAM][;user=USERNAME] -*/ -int -_url_mbox_init (mu_url_t url) -{ - const char *name = mu_url_to_string (url); - size_t len = strlen (name); - char *p; - - /* reject the obvious */ - if (name == NULL || strncmp (MU_MBOX_SCHEME, name, MU_MBOX_SCHEME_LEN) != 0 - || len < (MU_MBOX_SCHEME_LEN + 1) /* (scheme)+1+(path)*/) - return EINVAL; - - /* do I need to decode url encoding '% hex hex' ? */ - - /* TYPE */ - url->_destroy = url_mbox_destroy; - - /* SCHEME */ - url->scheme = strdup (MU_MBOX_SCHEME); - if (url->scheme == NULL) - { - url_mbox_destroy (url); - return ENOMEM; - } - - /* PATH */ - name += MU_MBOX_SCHEME_LEN; /* pass the scheme */ - url->path = strdup (name); - if (url->path == NULL) - { - url_mbox_destroy (url); - return ENOMEM; - } - p = strchr (url->path, ';'); - if (p) - { - char *(*fun)() = _url_path_default; - char *user = NULL; - int param = 0; - - *p++ = 0; - while (p) - { - char *q = strchr (p, ';'); - if (q) - *q++ = 0; - if (strncasecmp (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 - { - url_mbox_destroy (url); - return MU_ERR_NOENT; - } - } - else if (strncasecmp (p, "user=", 5) == 0) - { - user = p + 5; - } - else if (strncasecmp (p, "param=", 6) == 0) - { - param = strtoul (p+6, NULL, 0); - } - p = q; - } - - if (user) - { - p = fun (url->path, user, param); - free (url->path); - url->path = p; - } - else - { - url_mbox_destroy (url); - return MU_ERR_NOENT; - } - } - - return 0; -} - -static void -url_path_destroy (mu_url_t url MU_ARG_UNUSED) -{ -} - -int -_url_path_init (mu_url_t url) -{ - const char *name = mu_url_to_string (url); - const char *path; - - /* reject the obvious */ - if (name == NULL || *name == '\0') - return EINVAL; - - mu_scheme_autodetect_p (name, &path); - name = strdup (path); - free (url->name); - url->name = (char*) name; - - /* TYPE */ - url->_destroy = url_path_destroy; - - /* SCHEME */ - url->scheme = strdup (MU_PATH_SCHEME); - if (url->scheme == NULL) - { - url_path_destroy (url); - return ENOMEM; - } - - /* PATH */ - url->path = strdup (name); - if (url->path == NULL) - { - url_path_destroy (url); - return ENOMEM; - } - - return 0; -} diff --git a/libproto/mh/folder.c b/libproto/mh/folder.c index a54bda2fc..7d7f7b1c7 100644 --- a/libproto/mh/folder.c +++ b/libproto/mh/folder.c @@ -88,22 +88,22 @@ mh_dir_p (const char *name) } static int -_mh_is_scheme (mu_record_t record, const char *url, int flags) +_mh_is_scheme (mu_record_t record, mu_url_t url, int flags) { - const char *path; int rc = 0; - if (!url || !record->scheme) - return 0; - - if (strncmp (record->scheme, url, strlen (record->scheme)) == 0) + if (mu_url_is_scheme (url, record->scheme)) return MU_FOLDER_ATTRIBUTE_ALL & flags; - if (mu_scheme_autodetect_p (url, &path)) + if (mu_scheme_autodetect_p (url)) { /* Attemp auto-detection */ + const char *path; struct stat st; + if (mu_url_sget_path (url, &path)) + return 0; + if (stat (path, &st) < 0) return 0; /* mu_mailbox_open will complain*/ @@ -119,21 +119,11 @@ _mh_is_scheme (mu_record_t record, const char *url, int flags) return 0; } -/* - MH url - mh:path -*/ -static int -_mh_url_init (mu_url_t url) -{ - return amd_url_init (url, MU_MH_SCHEME); -} - static struct _mu_record _mh_record = { MU_MH_PRIO, MU_MH_SCHEME, - _mh_url_init, /* Url init. */ + mu_url_expand_path, /* Url init. */ _mailbox_mh_init, /* Mailbox init. */ NULL, /* Mailer init. */ _mh_folder_init, /* Folder init. */ diff --git a/libproto/nntp/folder.c b/libproto/nntp/folder.c index e3a70aa80..55d69ed60 100644 --- a/libproto/nntp/folder.c +++ b/libproto/nntp/folder.c @@ -63,7 +63,7 @@ static int nntp_folder_open (mu_folder_t, int); static int nntp_folder_close (mu_folder_t); static void nntp_folder_destroy (mu_folder_t folder); static int nntp_folder_list (mu_folder_t folder, const char *ref, - void *name, + void *name, int flags, size_t max, mu_list_t flist, mu_folder_enumerate_fp efp, void *edp); @@ -186,7 +186,7 @@ nntp_folder_destroy (mu_folder_t folder) static int -nntp_folder_list (mu_folder_t folder, const char *ref, void *pat, +nntp_folder_list (mu_folder_t folder, const char *ref, void *pat, int flags, size_t max_level, mu_list_t flist, mu_folder_enumerate_fp efp, void *edp) { diff --git a/m4/.cvsignore b/m4/.cvsignore index 8b0dd4b11..7c968a538 100644 --- a/m4/.cvsignore +++ b/m4/.cvsignore @@ -84,6 +84,7 @@ strchrnul.m4 strdup.m4 strerror.m4 string_h.m4 +strings_h.m4 strndup.m4 strnlen.m4 strtok_r.m4 diff --git a/mail/mail.h b/mail/mail.h index 86c20c472..704904eec 100644 --- a/mail/mail.h +++ b/mail/mail.h @@ -373,6 +373,8 @@ void util_rfc2047_decode (char **value); void util_mark_read (mu_message_t msg); +const char *util_url_to_string (mu_url_t url); + int is_address_field (const char *name); extern int ml_got_interrupt (void); diff --git a/mail/quit.c b/mail/quit.c index 38476db20..94e0d04fe 100644 --- a/mail/quit.c +++ b/mail/quit.c @@ -55,7 +55,7 @@ mail_mbox_close () ngettext ("Held %d message in %s\n", "Held %d messages in %s\n", held_count), - held_count, mu_url_to_string (url)); + held_count, util_url_to_string (url)); mu_mailbox_close (mbox); mu_mailbox_destroy (&mbox); return 0; @@ -75,7 +75,7 @@ mail_mbox_commit () int is_user_mbox; mu_mailbox_get_url (mbox, &url); - is_user_mbox = strcmp (mu_url_to_string (url), getenv ("MBOX")) == 0; + is_user_mbox = strcmp (util_url_to_string (url), getenv ("MBOX")) == 0; { mu_mailbox_t mb; @@ -151,7 +151,7 @@ mail_mbox_commit () ngettext ("Saved %d message in %s\n", "Saved %d messages in %s\n", saved_count), - saved_count, mu_url_to_string (u)); + saved_count, util_url_to_string (u)); mu_mailbox_close (dest_mbox); mu_mailbox_destroy (&dest_mbox); } diff --git a/mail/summary.c b/mail/summary.c index ab0b73dae..e56910498 100644 --- a/mail/summary.c +++ b/mail/summary.c @@ -61,7 +61,7 @@ mail_summary (int argc MU_ARG_UNUSED, char **argv MU_ARG_UNUSED) { mu_url_t url = NULL; mu_mailbox_get_url (mbox, &url); - printf("\"%s\": ", mu_url_to_string (url)); + printf("\"%s\": ", util_url_to_string (url)); } printf (ngettext ("%d message", "%d messages", count), count); if (mnew > 0) diff --git a/mail/util.c b/mail/util.c index 8af140848..108b6b15d 100644 --- a/mail/util.c +++ b/mail/util.c @@ -1460,3 +1460,18 @@ util_rfc2047_decode (char **value) } } +const char * +util_url_to_string (mu_url_t url) +{ + const char *scheme; + if (mu_url_sget_scheme (url, &scheme) == 0) + { + if (strcmp (scheme, "file") == 0 || strcmp (scheme, "mbox") == 0) + { + const char *path; + if (mu_url_sget_path (url, &path) == 0) + return path; + } + } + return mu_url_to_string (url); +} diff --git a/mailbox/amd.c b/mailbox/amd.c index aa76b2784..cd46a43dd 100644 --- a/mailbox/amd.c +++ b/mailbox/amd.c @@ -1531,50 +1531,4 @@ amd_envelope_sender (mu_envelope_t envelope, char *buf, size_t len, size_t *psiz return 0; } -static void -amd_url_destroy (mu_url_t url MU_ARG_UNUSED) -{ -} - -int -amd_url_init (mu_url_t url, const char *scheme) -{ - const char *name = mu_url_to_string (url); - const char *path_ptr = name; - size_t len = strlen (name); - size_t scheme_len = strlen (scheme); - - if (!name) - return 0; - - if (mu_scheme_autodetect_p (name, &path_ptr)) - /* nothing */ ; - /* reject the obvious */ - else if (strncmp (scheme, name, scheme_len) != 0 - || len < scheme_len + 1) - return EINVAL; - else - path_ptr = name + scheme_len; - - /* TYPE */ - url->_destroy = amd_url_destroy; - - /* SCHEME */ - url->scheme = strdup (scheme); - if (url->scheme == NULL) - { - amd_url_destroy (url); - return ENOMEM; - } - - /* PATH */ - url->path = strdup (path_ptr); - if (url->path == NULL) - { - amd_url_destroy (url); - return ENOMEM; - } - - return 0; -} diff --git a/mailbox/argcv.c b/mailbox/argcv.c index ba6a1b029..576d2c5bc 100644 --- a/mailbox/argcv.c +++ b/mailbox/argcv.c @@ -28,6 +28,7 @@ /* Keep mailutils namespace clean */ #define argcv_get mu_argcv_get #define argcv_get_n mu_argcv_get_n +#define argcv_get_np mu_argcv_get_np #define argcv_string mu_argcv_string #define argcv_free mu_argcv_free #define argcv_unquote_char mu_argcv_unquote_char @@ -47,15 +48,45 @@ #define isws(c) ((c)==' '||(c)=='\t'||(c)=='\n') #define isdelim(c,delim) (strchr(delim,(c))!=NULL) +struct argcv_info +{ + int len; + const char *command; + const char *delim; + const char *comment; + int flags; + + int start; + int end; + int save; + int finish_pos; +}; + +static void +init_argcv_info (struct argcv_info *ap, int flags, + int len, const char *command, const char *delim, + const char *comment) +{ + memset (ap, 0, sizeof *ap); + ap->len = len; + ap->command = command; + ap->delim = delim; + ap->comment = comment; + ap->flags = flags; +} + static int -argcv_scan (int len, const char *command, const char *delim, const char* cmnt, - int *start, int *end, int *save) +argcv_scan (struct argcv_info *ap) { int i = 0; + int len = ap->len; + const char *command = ap->command; + const char *delim = ap->delim; + const char *comment = ap->comment; for (;;) { - i = *save; + i = ap->save; if (i >= len) return i + 1; @@ -63,7 +94,7 @@ argcv_scan (int len, const char *command, const char *delim, const char* cmnt, /* Skip initial whitespace */ while (i < len && isws (command[i])) i++; - *start = i; + ap->start = i; if (!isdelim (command[i], delim)) { @@ -80,11 +111,11 @@ argcv_scan (int len, const char *command, const char *delim, const char* cmnt, if (command[i] == '\'' || command[i] == '"') { int j; - for (j = i+1; j < len && command[j] != command[i]; j++) + for (j = i + 1; j < len && command[j] != command[i]; j++) if (command[j] == '\\') j++; if (j < len) - i = j+1; + i = j + 1; else i++; } @@ -95,27 +126,36 @@ argcv_scan (int len, const char *command, const char *delim, const char* cmnt, } i--; } + else if (!(ap->flags & MU_ARGCV_RETURN_DELIMS)) + { + while (i < len && isdelim (command[i], delim)) + i++; + ap->save = i; + continue; + } + - *end = i; - *save = i + 1; + ap->end = i; + ap->save = ap->finish_pos = i + 1; /* If we have a token, and it starts with a comment character, skip to the newline and restart the token search. */ - if (*save <= len) + if (ap->save <= len) { - if (strchr (cmnt, command[*start]) != NULL) + if (strchr (comment, command[ap->start]) != NULL) { - i = *save; + ap->finish_pos = ap->start; + i = ap->save; while (i < len && command[i] != '\n') i++; - *save = i; + ap->save = i; continue; } } break; } - return *save; + return ap->save; } static char quote_transtab[] = "\\\\a\ab\bf\fn\nr\rt\t"; @@ -312,66 +352,84 @@ argcv_quote_copy (char *dst, const char *src) } int -argcv_get_n (const char *command, int len, const char *delim, const char *cmnt, - int *argc, char ***argv) +argcv_get_np (const char *command, int len, + const char *delim, const char *cmnt, + int flags, + int *pargc, char ***pargv, char **endp) { int i = 0; - int start, end, save; - - *argv = NULL; - - /* Count number of arguments */ - *argc = 0; - save = 0; - + struct argcv_info info; + int argc; + char **argv; + if (!delim) delim = ""; if (!cmnt) cmnt = ""; - - while (argcv_scan (len, command, delim, cmnt, &start, &end, &save) <= len) - (*argc)++; - *argv = calloc ((*argc + 1), sizeof (char *)); - if (*argv == NULL) + init_argcv_info (&info, flags, len, command, delim, cmnt); + + /* Count number of arguments */ + argc = 0; + while (argcv_scan (&info) <= len) + argc++; + + argv = calloc ((argc + 1), sizeof (char *)); + if (argv == NULL) return ENOMEM; i = 0; - save = 0; - for (i = 0; i < *argc; i++) + info.save = 0; + for (i = 0; i < argc; i++) { int n; int unquote; - argcv_scan (len, command, delim, cmnt, &start, &end, &save); + argcv_scan (&info); - if ((command[start] == '"' || command[end] == '\'') - && command[end] == command[start]) + if ((command[info.start] == '"' || command[info.end] == '\'') + && command[info.end] == command[info.start]) { - if (start < end) + if (info.start < info.end) { - start++; - end--; + info.start++; + info.end--; } unquote = 0; } else unquote = 1; - n = end - start + 1; - (*argv)[i] = calloc (n+1, sizeof (char)); - if ((*argv)[i] == NULL) - return ENOMEM; + n = info.end - info.start + 1; + argv[i] = calloc (n + 1, sizeof (char)); + if (argv[i] == NULL) + { + argcv_free (i, argv); + return ENOMEM; + } if (unquote) - argcv_unquote_copy ((*argv)[i], &command[start], n); + argcv_unquote_copy (argv[i], &command[info.start], n); else - memcpy ((*argv)[i], &command[start], n); - (*argv)[i][n] = 0; + memcpy (argv[i], &command[info.start], n); + argv[i][n] = 0; } - (*argv)[i] = NULL; + argv[i] = NULL; + + *pargc = argc; + *pargv = argv; + if (endp) + *endp = (char*) (command + info.finish_pos); return 0; } +int +argcv_get_n (const char *command, int len, const char *delim, const char *cmnt, + int *pargc, char ***pargv) +{ + return argcv_get_np (command, len, delim, cmnt, MU_ARGCV_RETURN_DELIMS, + pargc, pargv, NULL); +} + int argcv_get (const char *command, const char *delim, const char *cmnt, int *argc, char ***argv) @@ -445,3 +503,35 @@ argcv_string (int argc, char **argv, char **pstring) return 0; } +void +mu_argcv_remove (int *pargc, char ***pargv, + int (*sel) (const char *, void *), void *data) +{ + int i, j; + int argc = *pargc; + char **argv = *pargv; + int cnt = 0; + + for (i = j = 0; i < argc; i++) + { + if (sel (argv[i], data)) + { + free (argv[i]); + cnt++; + } + else + { + if (i != j) + argv[j] = argv[i]; + j++; + } + } + if (i != j) + argv[j] = NULL; + argc -= cnt; + + *pargc = argc; + *pargv = argv; +} + + diff --git a/mailbox/file_stream.c b/mailbox/file_stream.c index 82511c60b..47ff5d9dc 100644 --- a/mailbox/file_stream.c +++ b/mailbox/file_stream.c @@ -677,7 +677,7 @@ struct _prog_stream pid_t pid; int status; pid_t writer_pid; - size_t argc; + int argc; char **argv; mu_stream_t in, out; diff --git a/mailbox/folder.c b/mailbox/folder.c index ac87abf9d..44cbcc31f 100644 --- a/mailbox/folder.c +++ b/mailbox/folder.c @@ -73,22 +73,37 @@ mu_folder_create_from_record (mu_folder_t *pfolder, const char *name, == 0) { int (*f_init) (mu_folder_t) = NULL; - int (*u_init) (mu_url_t) = NULL; mu_record_get_folder (record, &f_init); - mu_record_get_url (record, &u_init); - if (f_init && u_init) + if (f_init) { int status; mu_url_t url; mu_folder_t folder; + int (*u_init) (mu_url_t) = NULL; /* Parse the url, it may be a bad one and we should bailout if this failed. */ - if ((status = mu_url_create (&url, name) != 0) - || (status = u_init (url)) != 0) + if ((status = mu_url_create (&url, name)) != 0) return status; + status = mu_url_parse (url); + if (status) + { + mu_url_destroy (url); + return status; + } + mu_record_get_url (record, &u_init); + if (u_init) + { + status = u_init (url); + if (status) + { + mu_url_destroy (url); + return status; + } + } + mu_monitor_wrlock (&folder_lock); /* Check if we already have the same URL folder. */ diff --git a/mailbox/gdebug.c b/mailbox/gdebug.c index af60fc2e1..f35377970 100644 --- a/mailbox/gdebug.c +++ b/mailbox/gdebug.c @@ -165,7 +165,7 @@ int mu_global_debug_from_string (const char *string, const char *errpfx) { int rc; - size_t argc; + int argc; char **argv; int i; diff --git a/mailbox/mailbox.c b/mailbox/mailbox.c index f500e6b1c..af690d554 100644 --- a/mailbox/mailbox.c +++ b/mailbox/mailbox.c @@ -42,20 +42,28 @@ #include #include +#include static int -mailbox_folder_create (mu_folder_t *pfolder, const char *name) +mailbox_folder_create (mu_mailbox_t mbox, const char *name, + mu_record_t record) { int rc; - char *p, *fname = strdup (name); + char *fname; - if (!fname) - return ENOMEM; + if ((rc = mu_url_aget_path (mbox->url, &fname))) + return rc; - p = strrchr (fname, '/'); /* FIXME: Is this always appropriate? */ - if (p && !(mu_is_proto (fname) && strncmp (fname, "file:", 5))) - *p = 0; - rc = mu_folder_create (pfolder, fname); + if (mu_url_is_scheme (mbox->url, "file") + || mu_url_is_scheme (mbox->url, "mbox") + || mu_url_is_scheme (mbox->url, "mh") + || mu_url_is_scheme (mbox->url, "maildir")) + { + char *p = strrchr (fname, '/'); /* FIXME: Is this always appropriate? */ + if (p) + *p = 0; + } + rc = mu_folder_create_from_record (&mbox->folder, fname, record); free (fname); return rc; } @@ -85,22 +93,21 @@ mu_mailbox_get_default_proto () } static int -_create_mailbox (mu_mailbox_t *pmbox, const char *name) +_create_mailbox0 (mu_mailbox_t *pmbox, mu_url_t url, const char *name) { + int status; mu_record_t record = NULL; - if (mu_registrar_lookup (name, MU_FOLDER_ATTRIBUTE_FILE, &record, NULL) == 0) + if (mu_registrar_lookup_url (url, MU_FOLDER_ATTRIBUTE_FILE, &record, NULL) + == 0) { mu_log_level_t level; int (*m_init) (mu_mailbox_t) = NULL; - int (*u_init) (mu_url_t) = NULL; mu_record_get_mailbox (record, &m_init); - mu_record_get_url (record, &u_init); - if (m_init && u_init) + if (m_init) { - int status; - mu_url_t url; + int (*u_init) (mu_url_t) = NULL; mu_mailbox_t mbox; /* Allocate memory for mbox. */ @@ -117,19 +124,31 @@ _create_mailbox (mu_mailbox_t *pmbox, const char *name) return status; } - /* Parse the url, it may be a bad one and we should bailout if this - failed. */ - if ((status = mu_url_create (&url, name)) != 0 - || (status = u_init (url)) != 0) + mu_record_get_url (record, &u_init); + if (u_init && (status = u_init (url)) != 0) { mu_mailbox_destroy (&mbox); return status; } + + /* Make sure scheme contains actual mailbox scheme */ + if (strcmp (url->scheme, record->scheme)) + { + char *p = strdup (record->scheme); + if (!p) + { + mu_mailbox_destroy (&mbox); + return errno; + } + free (url->scheme); + url->scheme = p; + } + mbox->url = url; /* Create the folder before initializing the concrete mailbox. The mailbox needs it's back pointer. */ - status = mailbox_folder_create (&mbox->folder, name); + status = mailbox_folder_create (mbox, name, record); if (status == 0) status = m_init (mbox); /* Create the concrete mailbox type. */ @@ -160,6 +179,21 @@ _create_mailbox (mu_mailbox_t *pmbox, const char *name) return MU_ERR_NO_HANDLER; } +static int +_create_mailbox (mu_mailbox_t *pmbox, const char *name) +{ + int status; + mu_url_t url; + + status = mu_url_create (&url, name); + if (status) + return status; + status = mu_url_parse (url); + if (status == 0) + status = _create_mailbox0 (pmbox, url, name); + return status; +} + /* The Mailbox Factory. Create an iterator for registrar and see if any url scheme match, Then we call the mailbox's mu_url_create() to parse the URL. Last diff --git a/mailbox/mutil.c b/mailbox/mutil.c index 25c8ac2e3..89fab1896 100644 --- a/mailbox/mutil.c +++ b/mailbox/mutil.c @@ -59,6 +59,7 @@ #include #include #include +#include #include @@ -1243,21 +1244,15 @@ mu_true_answer_p (const char *p) return -1; } -/* Returns true if SCHEME represents a local mail folder. Stores - real folder path to PATH */ +/* Returns true if SCHEME represents a local (autodetect) mail folder. */ int -mu_scheme_autodetect_p (const char *scheme, const char **path) +mu_scheme_autodetect_p (mu_url_t url) { - *path = scheme; - if (strncmp (MU_FILE_SCHEME, scheme, MU_FILE_SCHEME_LEN) == 0) + if (mu_url_is_scheme (url, "file")) { - *path += MU_FILE_SCHEME_LEN; + mu_url_expand_path (url); return 1; } - if (access (scheme, F_OK) == 0 - /* FIXME: this can return true even if the folder is unreadable */ - || strncmp (MU_PATH_SCHEME, scheme, MU_PATH_SCHEME_LEN) == 0) - return 1; return 0; } @@ -1329,7 +1324,7 @@ mu_decode_filter (mu_stream_t *pfilter, mu_stream_t input, mu_stream_t filter; int status = mu_filter_create (&filter, input, filter_type, - MU_FILTER_DECODE, MU_STREAM_READ); + MU_FILTER_DECODE, MU_STREAM_READ); if (status) return status; diff --git a/mailbox/registrar.c b/mailbox/registrar.c index 2b3919157..437974aa3 100644 --- a/mailbox/registrar.c +++ b/mailbox/registrar.c @@ -34,6 +34,7 @@ #include #include #include +#include #include @@ -90,8 +91,8 @@ mu_registrar_get_iterator (mu_iterator_t *pitr) } int -mu_registrar_lookup (const char *name, int flags, - mu_record_t *precord, int *pflags) +mu_registrar_lookup_url (mu_url_t url, int flags, + mu_record_t *precord, int *pflags) { mu_iterator_t iterator; int status = mu_registrar_get_iterator (&iterator); @@ -104,7 +105,7 @@ mu_registrar_lookup (const char *name, int flags, int rc; mu_record_t record; mu_iterator_current (iterator, (void **)&record); - if ((rc = mu_record_is_scheme (record, name, flags))) + if ((rc = mu_record_is_scheme (record, url, flags))) { status = 0; if (precord) @@ -118,6 +119,23 @@ mu_registrar_lookup (const char *name, int flags, return status; } +int +mu_registrar_lookup (const char *name, int flags, + mu_record_t *precord, int *pflags) +{ + int rc; + mu_url_t url; + + 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); + mu_url_destroy (&url); + return rc; +} + static int _compare_prio (const void *item, const void *value) { @@ -156,18 +174,16 @@ mu_unregistrar_record (mu_record_t record) } int -mu_record_is_scheme (mu_record_t record, const char *scheme, int flags) +mu_record_is_scheme (mu_record_t record, mu_url_t url, int flags) { if (record == NULL) return 0; /* Overload. */ if (record->_is_scheme) - return record->_is_scheme (record, scheme, flags); + return record->_is_scheme (record, url, flags); - if (scheme - && record->scheme - && strncasecmp (record->scheme, scheme, strlen (record->scheme)) == 0) + if (mu_url_is_scheme (url, record->scheme)) return MU_FOLDER_ATTRIBUTE_ALL; return 0; @@ -183,8 +199,8 @@ mu_record_set_scheme (mu_record_t record, const char *scheme) } int -mu_record_set_is_scheme (mu_record_t record, int (*_is_scheme) - (mu_record_t, const char *, int)) +mu_record_set_is_scheme (mu_record_t record, + int (*_is_scheme) (mu_record_t, mu_url_t, int)) { if (record == NULL) return EINVAL; diff --git a/mailbox/testsuite/Urls b/mailbox/testsuite/Urls index f7d8cb084..7a10c3072 100644 --- a/mailbox/testsuite/Urls +++ b/mailbox/testsuite/Urls @@ -627,4 +627,41 @@ ftp://ftp.example.org:111/mbox/user%40host => SUCCESS path query <> +ftp://ftp.example.org:111/mbox/user%40host;type=pass => SUCCESS + scheme + user <> + passwd <> + auth <> + host + port 111 + path + param[0] + query <> + +mbox:/var/spool/mail;type=index;param=2;user=gray => SUCCESS + scheme + user <> + passwd <> + auth <> + host <> + port 0 + path + param[0] + param[1] + param[2] + query <> + +mbox:///var/spool/mail;type=index;param=2;user=gray => SUCCESS + scheme + user <> + passwd <> + auth <> + host <> + port 0 + path + param[0] + param[1] + param[2] + query <> + # NOTE: This file must end with an empty line diff --git a/mailbox/url.c b/mailbox/url.c index bf4ae0e31..c3ea2c9f9 100644 --- a/mailbox/url.c +++ b/mailbox/url.c @@ -30,6 +30,7 @@ #include #include +#include #include /* @@ -86,6 +87,9 @@ mu_url_destroy (mu_url_t * purl) if (url->path) free (url->path); + if (url->fvcount) + mu_argcv_free (url->fvcount, url->fvpairs); + if (url->query) free (url->query); @@ -100,11 +104,12 @@ mu_url_parse (mu_url_t url) { int err = 0; char *n = NULL; - struct _mu_url u = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + struct _mu_url u; if (!url || !url->name) return EINVAL; + memset (&u, 0, sizeof u); /* can't have been parsed already */ if (url->scheme || url->user || url->passwd || url->auth || url->host || url->path || url->query) @@ -125,14 +130,17 @@ mu_url_parse (mu_url_t url) though. */ -#define UALLOC(X) \ - if(u.X && u.X[0] && (url->X = mu_url_decode(u.X)) == 0) { \ - err = ENOMEM; \ - goto CLEANUP; \ - } else { \ - /* Set zero-length strings to NULL. */ \ - u.X = NULL; \ - } +#define UALLOC(X) \ + if (u.X && u.X[0] && (url->X = mu_url_decode(u.X)) == 0) \ + { \ + err = ENOMEM; \ + goto CLEANUP; \ + } \ + else \ + { \ + /* Set zero-length strings to NULL. */ \ + u.X = NULL; \ + } UALLOC (scheme); UALLOC (user); @@ -142,6 +150,8 @@ mu_url_parse (mu_url_t url) UALLOC (path); UALLOC (query); #undef UALLOC + url->fvcount = u.fvcount; + url->fvpairs = u.fvpairs; url->port = u.port; } @@ -150,7 +160,7 @@ CLEANUP: if (err) { -#define UFREE(X) if(X) { free(X); X = 0; } +#define UFREE(X) if (X) { free(X); X = 0; } UFREE (url->scheme); UFREE (url->user); @@ -199,111 +209,126 @@ url_parse0 (mu_url_t u, char *name) if (name == NULL) return EINVAL; - /* Parse out the SCHEME. */ - p = strchr (name, ':'); - if (p == NULL) - return MU_ERR_PARSE; - - *p++ = 0; - - u->scheme = name; + if (name[0] == '/') + { + u->scheme = "file"; + } + else + { + /* Parse out the SCHEME. */ + p = strchr (name, ':'); + if (p == NULL) + return MU_ERR_PARSE; - /* RFC 1738, section 2.1, lower the scheme case */ - for (; name < p; name++) - *name = tolower (*name); + *p++ = 0; - name = p; + u->scheme = name; + /* RFC 1738, section 2.1, lower the scheme case */ + for (; name < p; name++) + *name = tolower (*name); + + name = p; + } + /* Check for nothing following the scheme. */ if (!*name) return 0; - if (strncmp (name, "//", 2) != 0) + if (strncmp (name, "//", 2) == 0) { - u->path = name; - return 0; - } - - name += 2; + name += 2; - if (name[0] == '/') - { - u->path = name; - return 0; - } - - /* Split into LHS and RHS of the '@', and then parse each side. */ - u->host = strchr (name, '@'); - if (u->host == NULL) - u->host = name; - else - { - /* 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[0] == '/') { - if (*name == ';') + 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 { - /* Make sure it's the auth token. */ - if (strncasecmp (name + 1, "auth=", 5) == 0) - { - *name++ = 0; + /* Parse the LHS into an identification/authentication pair. */ + *u->host++ = 0; - name += 5; + u->user = name; - u->auth = name; + /* Try to split the user into a: + : + or + ;AUTH= + */ - break; + for (; *name; name++) + { + if (*name == ';') + { + /* Make sure it's the auth token. */ + if (strncasecmp (name + 1, "auth=", 5) == 0) + { + *name++ = 0; + name += 5; + u->auth = name; + break; + } + } + if (*name == ':') + { + *name++ = 0; + u->passwd = name; + break; + } } } - if (*name == ':') + + /* Parse the host and port from the RHS. */ + p = strchr (u->host, ':'); + if (p) { - *name++ = 0; - u->passwd = name; - break; + *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, ";/?"); } } - - /* Parse the host and port from the RHS. */ - p = strchr (u->host, ':'); - - if (p) + 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, ";?"); + } - 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; + if (*p == ';') + { + *p++ = 0; + mu_argcv_get_np (p, strlen (p), ";", "?", 0, + &u->fvcount, &u->fvpairs, &p); } - else - p = u->host + strcspn (u->host, "/?"); - /* Either way, if we're not at a nul, we're at a path or query. */ if (*p == '?') { /* found a query */ *p++ = 0; u->query = p; } - if (*p == '/') - { - /* found a path */ - *p++ = 0; - u->path = p; - } return 0; } @@ -431,6 +456,46 @@ DECL_ACCESSORS (host) DECL_ACCESSORS (path) DECL_ACCESSORS (query) +/* 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_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_get_port (const mu_url_t url, long *pport) @@ -572,3 +637,189 @@ mu_url_init (mu_url_t url, int port, const char *scheme) return status; } + +/* Default mailbox path generator */ +static char * +_url_path_default (const char *spooldir, const char *user, int unused) +{ + char *mbox = malloc (sizeof(spooldir) + strlen(user) + 2); + if (!mbox) + errno = ENOMEM; + else + sprintf (mbox, "%s/%s", spooldir, user); + return mbox; +} + +/* 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'