summaryrefslogtreecommitdiffabout
authorSergey Poznyakoff <gray@gnu.org>2019-01-21 05:17:56 (GMT)
committer Sergey Poznyakoff <gray@gnu.org>2019-01-21 08:31:37 (GMT)
commitdb7165424199a473265eda5d35f2399e8816e92d (patch) (side-by-side diff)
treec55a57f21f540c45b93f60543bca8bbb24b9bc3a
parent29a837b1126c701191affceb092afbb8de5d5ffc (diff)
downloadmailutils-db7165424199a473265eda5d35f2399e8816e92d.tar.gz
mailutils-db7165424199a473265eda5d35f2399e8816e92d.tar.bz2
Improve folder handling and expansion in mail. Add convenience functions to the library.
* configure.ac: Build libmailutils/wicket * libmailutils/Makefile.am: Likewise. * libmailutils/base/wicket.c: Move file wicket stuff to ... * libmailutils/wicket/file.c: ... here * libmailutils/wicket/noauth.c: New file. * libmailutils/wicket/Makefile.am: New file. * include/mailutils/auth.h (mu_noauth_ticket_create) (mu_noauth_wicket_create): New protos. * include/mailutils/folder.h (mu_folder_attach_ticket) (mu_folder_is_local): New protos. * include/mailutils/mailbox.h (mu_mailbox_attach_ticket): New proto. * include/mailutils/sys/folder.h (_mu_folder): Remove flags. Add new member: is_local. * libmailutils/mailbox/folder.c (mu_folder_create_from_record): Set is_local. (mu_folder_attach_ticket): New function. (mu_folder_is_local): New function. * libmailutils/mailbox/mbx_default.c (mu_mailbox_attach_ticket): New function. * libmailutils/url/create.c: Allow for trailing / in url. * libproto/imap/mbox.c (_imap_mbx_open): Do initial scan. (__imap_msg_get_stream): Initialize clos.size. * libproto/imap/tests/imapfolder.c: Attach ticket to the folder. * mail/cd.c (mail_cd): Expand directory name (~, %, + notations) prior to use. * mail/file.c (mail_file): Attach ticket to the mailbox. * mail/copy.c (append_to_mailbox): Likewise. * mail/mailline.c: Rewrite directory expansion. Implement fully functional folder expansion. * mail/util.c (util_folder_path) (util_outfolder_name): Rewrite using mu_mailbox_expand_name.
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--configure.ac1
-rw-r--r--include/mailutils/auth.h3
-rw-r--r--include/mailutils/folder.h3
-rw-r--r--include/mailutils/mailbox.h2
-rw-r--r--include/mailutils/sys/folder.h5
-rw-r--r--libmailutils/Makefile.am5
-rw-r--r--libmailutils/base/wicket.c253
-rw-r--r--libmailutils/mailbox/folder.c49
-rw-r--r--libmailutils/mailbox/mbx_default.c43
-rw-r--r--libmailutils/url/create.c11
-rw-r--r--libmailutils/wicket/Makefile.am28
-rw-r--r--libmailutils/wicket/file.c266
-rw-r--r--libmailutils/wicket/noauth.c65
-rw-r--r--libproto/imap/mbox.c7
-rw-r--r--libproto/imap/tests/imapfolder.c1
-rw-r--r--mail/cd.c15
-rw-r--r--mail/copy.c1
-rw-r--r--mail/file.c24
-rw-r--r--mail/mailline.c353
-rw-r--r--mail/mailvar.c2
-rw-r--r--mail/util.c133
21 files changed, 771 insertions, 499 deletions
diff --git a/configure.ac b/configure.ac
index 8f44007..0ef4a23 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1517,12 +1517,13 @@ AC_CONFIG_FILES([
libmailutils/property/Makefile
libmailutils/server/Makefile
libmailutils/string/Makefile
libmailutils/stream/Makefile
libmailutils/stdstream/Makefile
libmailutils/url/Makefile
+ libmailutils/wicket/Makefile
libmailutils/Makefile
messages/Makefile
mh/Makefile
mh/etc/Makefile
mimeview/Makefile
movemail/Makefile
diff --git a/include/mailutils/auth.h b/include/mailutils/auth.h
index b4a650e..73fa98e 100644
--- a/include/mailutils/auth.h
+++ b/include/mailutils/auth.h
@@ -71,12 +71,15 @@ int mu_wicket_set_destroy (mu_wicket_t wicket,
void (*_destroy) (mu_wicket_t));
int mu_wicket_set_data (mu_wicket_t wicket, void *data);
void *mu_wicket_get_data (mu_wicket_t wicket);
int mu_wicket_set_get_ticket (mu_wicket_t wicket,
int (*_get_ticket) (mu_wicket_t, void *,
const char *, mu_ticket_t *));
+
+int mu_noauth_ticket_create (mu_ticket_t *pticket);
+int mu_noauth_wicket_create (mu_wicket_t *pwicket);
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_locus_point *loc,
mu_url_t url, int parse_flags,
mu_url_t *pticket_url);
diff --git a/include/mailutils/folder.h b/include/mailutils/folder.h
index 2d71a0e..1232798 100644
--- a/include/mailutils/folder.h
+++ b/include/mailutils/folder.h
@@ -57,12 +57,15 @@ extern int mu_folder_enumerate (mu_folder_t, const char *,
void *, int,
size_t, mu_list_t *,
mu_folder_enumerate_fp, void *);
extern int mu_folder_lsub (mu_folder_t, const char *, const char *,
mu_list_t *);
+extern int mu_folder_attach_ticket (mu_folder_t folder);
+extern int mu_folder_is_local (mu_folder_t folder);
+
/* Match function */
extern int mu_folder_set_match (mu_folder_t folder, mu_folder_match_fp pmatch);
extern int mu_folder_get_match (mu_folder_t folder,
mu_folder_match_fp *pmatch);
/* Two often used matchers: */
diff --git a/include/mailutils/mailbox.h b/include/mailutils/mailbox.h
index 5c5f4c6..e54ae88 100644
--- a/include/mailutils/mailbox.h
+++ b/include/mailutils/mailbox.h
@@ -69,12 +69,14 @@ extern int mu_mailbox_messages_count (mu_mailbox_t, size_t *);
extern int mu_mailbox_messages_recent (mu_mailbox_t, size_t *);
extern int mu_mailbox_message_unseen (mu_mailbox_t, size_t *);
extern int mu_mailbox_expunge (mu_mailbox_t);
extern int mu_mailbox_sync (mu_mailbox_t);
extern int mu_mailbox_save_attributes (mu_mailbox_t) MU_DEPRECATED;
+extern int mu_mailbox_attach_ticket (mu_mailbox_t mbox);
+
#define MU_UIDL_LENGTH 70
#define MU_UIDL_BUFFER_SIZE (MU_UIDL_LENGTH+1)
struct mu_uidl
{
size_t msgno;
diff --git a/include/mailutils/sys/folder.h b/include/mailutils/sys/folder.h
index c32835e..050a18f 100644
--- a/include/mailutils/sys/folder.h
+++ b/include/mailutils/sys/folder.h
@@ -25,24 +25,21 @@
# include <mailutils/folder.h>
# ifdef __cplusplus
extern "C" {
# endif
-# define MU_FOLDER_LIST 0
-# define MU_FOLDER_ENUM 1
-
struct _mu_folder
{
/* Data */
mu_authority_t authority;
mu_observable_t observable;
mu_property_t property;
mu_monitor_t monitor;
mu_url_t url;
- int flags;
+ int is_local;
int ref;
size_t uid;
/* Back pointer to the specific mailbox */
void *data;
diff --git a/libmailutils/Makefile.am b/libmailutils/Makefile.am
index c940d9c..55b6238 100644
--- a/libmailutils/Makefile.am
+++ b/libmailutils/Makefile.am
@@ -15,13 +15,13 @@
# Public License along with this library. If not, see
# <http://www.gnu.org/licenses/>.
SUBDIRS = \
auth base address list sockaddr cidr cfg cli diag\
filter locus mailbox mailer mime msgset opt server string stream stdstream\
- property url imapio datetime . tests
+ property url imapio datetime wicket . tests
lib_LTLIBRARIES = libmailutils.la
libmailutils_la_SOURCES =
libmailutils_la_LIBADD = \
@@ -46,10 +46,11 @@ libmailutils_la_LIBADD = \
opt/libopt.la\
property/libproperty.la\
server/libserver.la\
string/libstring.la\
stream/libstream.la\
stdstream/libstdstream.la\
- url/liburl.la
+ url/liburl.la\
+ wicket/libwicket.la
libmailutils_la_LDFLAGS = -version-info @VI_CURRENT@:@VI_REVISION@:@VI_AGE@
diff --git a/libmailutils/base/wicket.c b/libmailutils/base/wicket.c
index c60ddff..22cd2c1 100644
--- a/libmailutils/base/wicket.c
+++ b/libmailutils/base/wicket.c
@@ -16,30 +16,15 @@
<http://www.gnu.org/licenses/>. */
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <pwd.h>
-#include <string.h>
#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <ctype.h>
#include <mailutils/errno.h>
-#include <mailutils/util.h>
-#include <mailutils/mu_auth.h>
-#include <mailutils/stream.h>
-#include <mailutils/cstr.h>
-#include <mailutils/nls.h>
-#include <mailutils/errno.h>
-
#include <mailutils/sys/auth.h>
#include <mailutils/sys/url.h>
int
mu_wicket_create (mu_wicket_t *pwicket)
{
@@ -132,244 +117,6 @@ mu_wicket_set_get_ticket (mu_wicket_t wicket,
if (!wicket)
return EINVAL;
wicket->_get_ticket = _get_ticket;
return 0;
}
-
-/* A "file wicket" implementation */
-
-struct file_wicket
-{
- char *filename;
-};
-
-static void
-_file_wicket_destroy (mu_wicket_t wicket)
-{
- struct file_wicket *fw = mu_wicket_get_data (wicket);
- free (fw->filename);
- free (fw);
-}
-
-struct file_ticket
-{
- char *filename;
- char *user;
- mu_url_t tickurl;
-};
-
-static void
-file_ticket_destroy (mu_ticket_t ticket)
-{
- struct file_ticket *ft = mu_ticket_get_data (ticket);
- if (ft)
- {
- free (ft->filename);
- free (ft->user);
- mu_url_destroy (&ft->tickurl);
- free (ft);
- }
-}
-
-int
-file_ticket_get_cred (mu_ticket_t ticket, mu_url_t url, const char *challenge,
- char **pplain, mu_secret_t *psec)
-{
- struct file_ticket *ft = mu_ticket_get_data (ticket);
- int rc = 0;
-
- if (!ft->tickurl)
- {
- rc = mu_wicket_file_match_url (ft->filename, url,
- MU_URL_PARSE_ALL,
- &ft->tickurl);
- if (rc)
- return rc;
- }
- if (pplain)
- {
- if (ft->user)
- {
- *pplain = strdup (ft->user);
- if (!*pplain)
- rc = ENOMEM;
- }
- else
- rc = mu_url_aget_user (ft->tickurl, pplain);
- }
- else
- rc = mu_url_get_secret (ft->tickurl, psec);
- return rc;
-}
-
-static int
-_file_wicket_get_ticket (mu_wicket_t wicket, void *data,
- const char *user, mu_ticket_t *pticket)
-{
- int rc;
- mu_ticket_t ticket;
- struct file_wicket *fw = data;
- struct file_ticket *ft = calloc (1, sizeof (*ft));
- ft->filename = strdup (fw->filename);
- if (!ft->filename)
- {
- free (ft);
- return ENOMEM;
- }
- if (user)
- {
- ft->user = strdup (user);
- if (!ft->user)
- {
- free (ft->filename);
- free (ft);
- return ENOMEM;
- }
- }
- else
- ft->user = NULL;
-
- rc = mu_ticket_create (&ticket, NULL);
- if (rc)
- {
- free (ft->filename);
- free (ft->user);
- free (ft);
- return rc;
- }
-
- mu_ticket_set_destroy (ticket, file_ticket_destroy, NULL);
- mu_ticket_set_data (ticket, ft, NULL);
- mu_ticket_set_get_cred (ticket, file_ticket_get_cred, NULL);
-
- *pticket = ticket;
- return 0;
-}
-
-int
-mu_wicket_stream_match_url (mu_stream_t stream, struct mu_locus_point *loc,
- mu_url_t url, int parse_flags,
- mu_url_t *pticket_url)
-{
- int rc;
- mu_url_t u = NULL;
- char *buf = NULL;
- size_t bufsize = 0;
- size_t len;
- mu_url_t pret = NULL;
- int weight = 0;
- int line = loc->mu_line;
-
- while ((rc = mu_stream_getline (stream, &buf, &bufsize, &len)) == 0
- && len > 0)
- {
- char *p;
- int err;
- int n;
-
- loc->mu_line++;
- p = mu_str_stripws (buf);
-
- /* Skip empty lines and comments. */
- if (*p == 0 || *p == '#')
- continue;
-
- if ((err = mu_url_create_hint (&u, p, parse_flags, NULL)) != 0)
- {
- /* Skip erroneous entry */
- mu_error (_("%s:%u: cannot create URL: %s"),
- loc->mu_file, loc->mu_line, mu_strerror (err));
- continue;
- }
-
- if (!mu_url_has_flag (u, MU_URL_USER|MU_URL_SECRET))
- {
- mu_error (_("%s:%u: URL is missing required parts"),
- loc->mu_file, loc->mu_line);
- mu_url_destroy (&u);
- continue;
- }
-
- if (!mu_url_matches_ticket (u, url, &n))
- {
- mu_url_destroy (&u);
- continue;
- }
-
- if (!pret || n < weight)
- {
- pret = u;
- weight = n;
- line = loc->mu_line;
- if (weight == 0)
- break;
- }
- }
- free (buf);
-
- if (rc == 0)
- {
- if (pret)
- {
- *pticket_url = pret;
- loc->mu_line = line;
- }
- else
- rc = MU_ERR_NOENT;
- }
-
- return rc;
-}
-
-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;
- int rc;
- struct mu_locus_point loc;
-
- rc = mu_file_stream_create (&stream, name, MU_STREAM_READ);
- if (rc)
- return rc;
- loc.mu_file = (char*) name;
- loc.mu_line = 0;
- loc.mu_col = 0;
- rc = mu_wicket_stream_match_url (stream, &loc, url, parse_flags,
- pticket_url);
- mu_stream_close (stream);
- mu_stream_destroy (&stream);
- return rc;
-}
-
-int
-mu_file_wicket_create (mu_wicket_t *pwicket, const char *filename)
-{
- mu_wicket_t wicket;
- int rc;
- struct file_wicket *fw = calloc (1, sizeof (*fw));
-
- if (!fw)
- return ENOMEM;
- fw->filename = strdup (filename);
- if (!fw->filename)
- {
- free (fw);
- return ENOMEM;
- }
-
- rc = mu_wicket_create (&wicket);
- if (rc)
- {
- free (fw->filename);
- free (fw);
- return rc;
- }
- mu_wicket_set_data (wicket, fw);
- mu_wicket_set_destroy (wicket, _file_wicket_destroy);
- mu_wicket_set_get_ticket (wicket, _file_wicket_get_ticket);
- *pwicket = wicket;
- return 0;
-}
-
diff --git a/libmailutils/mailbox/folder.c b/libmailutils/mailbox/folder.c
index 64f997d..6773544 100644
--- a/libmailutils/mailbox/folder.c
+++ b/libmailutils/mailbox/folder.c
@@ -33,13 +33,13 @@
#include <mailutils/registrar.h>
#include <mailutils/url.h>
#include <mailutils/errno.h>
#include <mailutils/property.h>
#include <mailutils/mailbox.h>
#include <mailutils/imaputil.h>
-
+#include <mailutils/util.h>
#include <mailutils/sys/folder.h>
/* Internal folder list. */
static mu_list_t known_folder_list;
static int is_known_folder (mu_url_t, mu_folder_t *);
@@ -118,12 +118,13 @@ mu_folder_create_from_record (mu_folder_t *pfolder, mu_url_t url,
/* Allocate memory for the folder. */
folder = calloc (1, sizeof (*folder));
if (folder != NULL)
{
folder->url = url;
+ folder->is_local = record->flags & MU_RECORD_LOCAL;
/* Initialize the internal foilder lock, now so the
concrete folder could use it. */
status = mu_monitor_create (&folder->monitor, 0, folder);
if (status == 0)
{
/* Create the concrete folder type. */
@@ -167,12 +168,58 @@ mu_folder_create (mu_folder_t *pfolder, const char *name)
rc = mu_folder_create_from_record (pfolder, url, NULL);
if (rc)
mu_url_destroy (&url);
return rc;
}
+int
+mu_folder_attach_ticket (mu_folder_t folder)
+{
+ mu_authority_t auth = NULL;
+ int rc = MU_ERR_NOENT;
+
+ if (mu_folder_get_authority (folder, &auth) == 0 && auth)
+ {
+ char *filename = mu_tilde_expansion (mu_ticket_file,
+ MU_HIERARCHY_DELIMITER, NULL);
+ mu_wicket_t wicket;
+
+ mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_TRACE1,
+ ("Reading user ticket file %s", filename));
+ if ((rc = mu_file_wicket_create (&wicket, filename)) == 0)
+ {
+ mu_ticket_t ticket;
+
+ if ((rc = mu_wicket_get_ticket (wicket, NULL, &ticket)) == 0)
+ {
+ rc = mu_authority_set_ticket (auth, ticket);
+ mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_TRACE1,
+ ("Retrieved and set ticket: %d", rc));
+ }
+ else
+ mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_ERROR,
+ ("Error retrieving ticket: %s\n",
+ mu_strerror (rc)));
+ mu_wicket_destroy (&wicket);
+ }
+ else
+ mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_ERROR,
+ ("Error creating wicket: %s\n", mu_strerror (rc)));
+ free (filename);
+ }
+ return rc;
+}
+
+int
+mu_folder_is_local (mu_folder_t folder)
+{
+ if (!folder)
+ return -1;
+ return folder->is_local;
+}
+
/* The folder is destroy if it is the last reference. */
void
mu_folder_destroy (mu_folder_t *pfolder)
{
if (pfolder && *pfolder)
{
diff --git a/libmailutils/mailbox/mbx_default.c b/libmailutils/mailbox/mbx_default.c
index 29890bf..bd9f876 100644
--- a/libmailutils/mailbox/mbx_default.c
+++ b/libmailutils/mailbox/mbx_default.c
@@ -341,50 +341,21 @@ percent_expand (const char *file, char **mbox)
status = user_mailbox_name (user, mbox);
free (user);
return status;
}
-static void
-attach_auth_ticket (mu_mailbox_t mbox)
+int
+mu_mailbox_attach_ticket (mu_mailbox_t mbox)
{
+ int rc;
mu_folder_t folder = NULL;
- mu_authority_t auth = NULL;
- if (mu_mailbox_get_folder (mbox, &folder) == 0
- && mu_folder_get_authority (folder, &auth) == 0
- && auth)
- {
- char *filename = mu_tilde_expansion (mu_ticket_file,
- MU_HIERARCHY_DELIMITER, NULL);
- mu_wicket_t wicket;
- int rc;
-
- mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_TRACE1,
- ("Reading user ticket file %s", filename));
- if ((rc = mu_file_wicket_create (&wicket, filename)) == 0)
- {
- mu_ticket_t ticket;
-
- if ((rc = mu_wicket_get_ticket (wicket, NULL, &ticket)) == 0)
- {
- rc = mu_authority_set_ticket (auth, ticket);
- mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_TRACE1,
- ("Retrieved and set ticket: %d", rc));
- }
- else
- mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_ERROR,
- ("Error retrieving ticket: %s\n",
- mu_strerror (rc)));
- mu_wicket_destroy (&wicket);
- }
- else
- mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_ERROR,
- ("Error creating wicket: %s\n", mu_strerror (rc)));
- free (filename);
- }
+ if ((rc = mu_mailbox_get_folder (mbox, &folder)) == 0)
+ rc = mu_folder_attach_ticket (folder);
+ return rc;
}
/* Expand mailbox name according to the following rules:
NAME Expands to
-------------+------------------------------------
@@ -487,10 +458,10 @@ mu_mailbox_create_default (mu_mailbox_t *pmbox, const char *mail)
if (status)
return status;
status = mu_mailbox_create (pmbox, mboxname);
free (mboxname);
if (status == 0)
- attach_auth_ticket (*pmbox);
+ mu_mailbox_attach_ticket (*pmbox);
return status;
}
diff --git a/libmailutils/url/create.c b/libmailutils/url/create.c
index 124be32..3b19a4f 100644
--- a/libmailutils/url/create.c
+++ b/libmailutils/url/create.c
@@ -266,13 +266,22 @@ _mu_url_ctx_parse_host (struct mu_url_ctx *ctx, int has_host)
url->flags |= MU_URL_PORT;
}
if (*ctx->cur == '/')
{
if (has_host)
- ctx->cur++;
+ {
+ ctx->cur++;
+ if (*ctx->cur == 0)
+ {
+ rc = str_assign (&url->path, "");
+ if (rc == 0)
+ url->flags |= MU_URL_PATH;
+ return rc;
+ }
+ }
return _mu_url_ctx_parse_path (ctx);
}
if (*ctx->cur == ';')
return _mu_url_ctx_parse_param (ctx);
diff --git a/libmailutils/wicket/Makefile.am b/libmailutils/wicket/Makefile.am
new file mode 100644
index 0000000..b7f3528
--- a/dev/null
+++ b/libmailutils/wicket/Makefile.am
@@ -0,0 +1,28 @@
+# GNU Mailutils -- a suite of utilities for electronic mail
+# Copyright (C) 2010-2019 Free Software Foundation, Inc.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 3 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General
+# Public License along with this library. If not, see
+# <http://www.gnu.org/licenses/>.
+
+noinst_LTLIBRARIES = libwicket.la
+libwicket_la_SOURCES = \
+ file.c\
+ noauth.c
+
+localedir = $(datadir)/locale
+AM_CPPFLAGS = \
+ @MU_LIB_COMMON_INCLUDES@ -I/libmailutils\
+ -DSYSCONFDIR=\"$(sysconfdir)\"\
+ -DSITE_VIRTUAL_PWDDIR=\"@SITE_VIRTUAL_PWDDIR@\"\
+ -DLOCALEDIR=\"$(localedir)\"
diff --git a/libmailutils/wicket/file.c b/libmailutils/wicket/file.c
new file mode 100644
index 0000000..73e7e65
--- a/dev/null
+++ b/libmailutils/wicket/file.c
@@ -0,0 +1,266 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+ Copyright (C) 1999-2019 Free Software Foundation, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General
+ Public License along with this library. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+/* A "file wicket" implementation */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <mailutils/errno.h>
+#include <mailutils/error.h>
+#include <mailutils/auth.h>
+#include <mailutils/url.h>
+#include <mailutils/stream.h>
+#include <mailutils/cstr.h>
+#include <mailutils/nls.h>
+
+struct file_wicket
+{
+ char *filename;
+};
+
+static void
+_file_wicket_destroy (mu_wicket_t wicket)
+{
+ struct file_wicket *fw = mu_wicket_get_data (wicket);
+ free (fw->filename);
+ free (fw);
+}
+
+struct file_ticket
+{
+ char *filename;
+ char *user;
+ mu_url_t tickurl;
+};
+
+static void
+file_ticket_destroy (mu_ticket_t ticket)
+{
+ struct file_ticket *ft = mu_ticket_get_data (ticket);
+ if (ft)
+ {
+ free (ft->filename);
+ free (ft->user);
+ mu_url_destroy (&ft->tickurl);
+ free (ft);
+ }
+}
+
+int
+file_ticket_get_cred (mu_ticket_t ticket, mu_url_t url, const char *challenge,
+ char **pplain, mu_secret_t *psec)
+{
+ struct file_ticket *ft = mu_ticket_get_data (ticket);
+ int rc = 0;
+
+ if (!ft->tickurl)
+ {
+ rc = mu_wicket_file_match_url (ft->filename, url,
+ MU_URL_PARSE_ALL,
+ &ft->tickurl);
+ if (rc)
+ return rc;
+ }
+ if (pplain)
+ {
+ if (ft->user)
+ {
+ *pplain = strdup (ft->user);
+ if (!*pplain)
+ rc = ENOMEM;
+ }
+ else
+ rc = mu_url_aget_user (ft->tickurl, pplain);
+ }
+ else
+ rc = mu_url_get_secret (ft->tickurl, psec);
+ return rc;
+}
+
+static int
+_file_wicket_get_ticket (mu_wicket_t wicket, void *data,
+ const char *user, mu_ticket_t *pticket)
+{
+ int rc;
+ mu_ticket_t ticket;
+ struct file_wicket *fw = data;
+ struct file_ticket *ft = calloc (1, sizeof (*ft));
+ ft->filename = strdup (fw->filename);
+ if (!ft->filename)
+ {
+ free (ft);
+ return ENOMEM;
+ }
+ if (user)
+ {
+ ft->user = strdup (user);
+ if (!ft->user)
+ {
+ free (ft->filename);
+ free (ft);
+ return ENOMEM;
+ }
+ }
+ else
+ ft->user = NULL;
+
+ rc = mu_ticket_create (&ticket, NULL);
+ if (rc)
+ {
+ free (ft->filename);
+ free (ft->user);
+ free (ft);
+ return rc;
+ }
+
+ mu_ticket_set_destroy (ticket, file_ticket_destroy, NULL);
+ mu_ticket_set_data (ticket, ft, NULL);
+ mu_ticket_set_get_cred (ticket, file_ticket_get_cred, NULL);
+
+ *pticket = ticket;
+ return 0;
+}
+
+int
+mu_wicket_stream_match_url (mu_stream_t stream, struct mu_locus_point *loc,
+ mu_url_t url, int parse_flags,
+ mu_url_t *pticket_url)
+{
+ int rc;
+ mu_url_t u = NULL;
+ char *buf = NULL;
+ size_t bufsize = 0;
+ size_t len;
+ mu_url_t pret = NULL;
+ int weight = 0;
+ int line = loc->mu_line;
+
+ while ((rc = mu_stream_getline (stream, &buf, &bufsize, &len)) == 0
+ && len > 0)
+ {
+ char *p;
+ int err;
+ int n;
+
+ loc->mu_line++;
+ p = mu_str_stripws (buf);
+
+ /* Skip empty lines and comments. */
+ if (*p == 0 || *p == '#')
+ continue;
+
+ if ((err = mu_url_create_hint (&u, p, parse_flags, NULL)) != 0)
+ {
+ /* Skip erroneous entry */
+ mu_error (_("%s:%u: cannot create URL: %s"),
+ loc->mu_file, loc->mu_line, mu_strerror (err));
+ continue;
+ }
+
+ if (!mu_url_has_flag (u, MU_URL_USER|MU_URL_SECRET))
+ {
+ mu_error (_("%s:%u: URL is missing required parts"),
+ loc->mu_file, loc->mu_line);
+ mu_url_destroy (&u);
+ continue;
+ }
+
+ if (!mu_url_matches_ticket (u, url, &n))
+ {
+ mu_url_destroy (&u);
+ continue;
+ }
+
+ if (!pret || n < weight)
+ {
+ pret = u;
+ weight = n;
+ line = loc->mu_line;
+ if (weight == 0)
+ break;
+ }
+ }
+ free (buf);
+
+ if (rc == 0)
+ {
+ if (pret)
+ {
+ *pticket_url = pret;
+ loc->mu_line = line;
+ }
+ else
+ rc = MU_ERR_NOENT;
+ }
+
+ return rc;
+}
+
+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;
+ int rc;
+ struct mu_locus_point loc;
+
+ rc = mu_file_stream_create (&stream, name, MU_STREAM_READ);
+ if (rc)
+ return rc;
+ loc.mu_file = (char*) name;
+ loc.mu_line = 0;
+ loc.mu_col = 0;
+ rc = mu_wicket_stream_match_url (stream, &loc, url, parse_flags,
+ pticket_url);
+ mu_stream_close (stream);
+ mu_stream_destroy (&stream);
+ return rc;
+}
+
+int
+mu_file_wicket_create (mu_wicket_t *pwicket, const char *filename)
+{
+ mu_wicket_t wicket;
+ int rc;
+ struct file_wicket *fw = calloc (1, sizeof (*fw));
+
+ if (!fw)
+ return ENOMEM;
+ fw->filename = strdup (filename);
+ if (!fw->filename)
+ {
+ free (fw);
+ return ENOMEM;
+ }
+
+ rc = mu_wicket_create (&wicket);
+ if (rc)
+ {
+ free (fw->filename);
+ free (fw);
+ return rc;
+ }
+ mu_wicket_set_data (wicket, fw);
+ mu_wicket_set_destroy (wicket, _file_wicket_destroy);
+ mu_wicket_set_get_ticket (wicket, _file_wicket_get_ticket);
+ *pwicket = wicket;
+ return 0;
+}
diff --git a/libmailutils/wicket/noauth.c b/libmailutils/wicket/noauth.c
new file mode 100644
index 0000000..2a4da10
--- a/dev/null
+++ b/libmailutils/wicket/noauth.c
@@ -0,0 +1,65 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+ Copyright (C) 1999-2019 Free Software Foundation, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General
+ Public License along with this library. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <mailutils/errno.h>
+#include <mailutils/auth.h>
+
+static int
+noauth_ticket_get_cred (mu_ticket_t ticket, mu_url_t url, const char *challenge,
+ char **pplain, mu_secret_t *psec)
+{
+ return MU_ERR_AUTH_FAILURE;
+}
+
+int
+mu_noauth_ticket_create (mu_ticket_t *pticket)
+{
+ mu_ticket_t ticket;
+ int rc;
+
+ rc = mu_ticket_create (&ticket, NULL);
+ if (rc)
+ return rc;
+ mu_ticket_set_get_cred (ticket, noauth_ticket_get_cred, NULL);
+ *pticket = ticket;
+ return 0;
+}
+
+static int
+noauth_get_ticket (mu_wicket_t wicket, void *data,
+ const char *user, mu_ticket_t *pticket)
+{
+ return mu_noauth_ticket_create (pticket);
+}
+
+int
+mu_noauth_wicket_create (mu_wicket_t *pwicket)
+{
+ mu_wicket_t wicket;
+ int rc;
+
+ rc = mu_wicket_create (&wicket);
+ if (rc)
+ return rc;
+ mu_wicket_set_get_ticket (wicket, noauth_get_ticket);
+ return 0;
+}
diff --git a/libproto/imap/mbox.c b/libproto/imap/mbox.c
index 1442e62..fde568a 100644
--- a/libproto/imap/mbox.c
+++ b/libproto/imap/mbox.c
@@ -180,13 +180,14 @@ __imap_msg_get_stream (struct _mu_imap_message *imsg, size_t msgno,
if (rc == 0)
{
struct save_closure clos;
clos.imsg = imsg;
clos.save_stream = imbx->cache;
-
+ clos.size = 0;
+
rc = mu_msgset_add_range (msgset, msgno, msgno, MU_MSGSET_NUM);
if (rc == 0)
{
_imap_mbx_clrerr (imbx);
rc = _imap_fetch_with_callback (imap, msgset, "BODY[]",
_save_message_callback, &clos);
@@ -754,13 +755,15 @@ _imap_mbx_open (mu_mailbox_t mbox, int flags)
&imbx->stats);
if (rc)
return rc;
if (imbx->stats.flags & MU_IMAP_STAT_MESSAGE_COUNT)
rc = _imap_realloc_messages (imbx, imbx->stats.message_count);
-
+
+ _imap_mbx_scan (mbox, 1, NULL);
+
return rc;
}
static int
_imap_mbx_close (mu_mailbox_t mbox)
{
diff --git a/libproto/imap/tests/imapfolder.c b/libproto/imap/tests/imapfolder.c
index 6f91b63..8d3f6ce 100644
--- a/libproto/imap/tests/imapfolder.c
+++ b/libproto/imap/tests/imapfolder.c
@@ -199,12 +199,13 @@ main (int argc, char **argv)
rc = mu_folder_create (&folder, fname);
if (rc)
{
mu_diag_funcall (MU_DIAG_ERROR, "mu_folder_create", fname, rc);
return 1;
}
+ mu_folder_attach_ticket (folder);
rc = mu_folder_open (folder, MU_STREAM_READ);
if (rc)
{
mu_diag_funcall (MU_DIAG_ERROR, "mu_folder_open", fname, rc);
return 1;
diff --git a/mail/cd.c b/mail/cd.c
index cb71b4c..122a1af 100644
--- a/mail/cd.c
+++ b/mail/cd.c
@@ -21,22 +21,29 @@
* ch[dir] [directory]
*/
int
mail_cd (int argc, char **argv)
{
- char *dir;
+ char *dir, *edir;
+ int rc;
if (argc > 2)
return 1;
else if (argc == 2)
dir = argv[1];
else
dir = getenv ("HOME");
- if (chdir (dir))
+ rc = mu_mailbox_expand_name (dir, &edir);
+ if (rc)
{
- mu_diag_funcall (MU_DIAG_ERROR, "chdir", dir, errno);
+ mu_diag_funcall (MU_DIAG_ERROR, "mu_mailbox_expand_name", dir, rc);
return 1;
}
- return 0;
+
+ rc = chdir (edir);
+ if (rc)
+ mu_diag_funcall (MU_DIAG_ERROR, "chdir", edir, errno);
+ free (edir);
+ return rc;
}
diff --git a/mail/copy.c b/mail/copy.c
index 476b441..15deebe 100644
--- a/mail/copy.c
+++ b/mail/copy.c
@@ -42,12 +42,13 @@ append_to_mailbox (char const *filename, msgset_t *msglist, int mark,
if ((status = mu_mailbox_create (&mbx, filename)) != 0)
{
mu_error (_("Cannot create mailbox %s: %s"), filename,
mu_strerror (status));
return 1;
}
+ mu_mailbox_attach_ticket (mbx);
if ((status = mu_mailbox_open (mbx, MU_STREAM_WRITE | MU_STREAM_CREAT)) != 0)
{
mu_error (_("Cannot open mailbox %s: %s"), filename,
mu_strerror (status));
mu_mailbox_destroy (&mbx);
return 1;
diff --git a/mail/file.c b/mail/file.c
index 517a6b7..bc94f13 100644
--- a/mail/file.c
+++ b/mail/file.c
@@ -27,13 +27,13 @@ static char *prev_name;
*/
char *
mail_expand_name (const char *name)
{
int status = 0;
char *exp = NULL;
-
+
if (strcmp (name, "#") == 0)
{
if (!prev_name)
{
mu_error (_("No previous file"));
return NULL;
@@ -81,40 +81,49 @@ mail_file (int argc, char **argv)
mu_mailbox_t newbox = NULL;
char *name = mail_expand_name (argv[1]);
int status;
if (!name)
return 1;
-
- if ((status = mu_mailbox_create (&newbox, name)) != 0
- || (status = mu_mailbox_open (newbox, MU_STREAM_RDWR)) != 0)
+
+ status = mu_mailbox_create (&newbox, name);
+ if (status)
+ {
+ mu_error(_("Cannot create mailbox %s: %s"), name,
+ mu_strerror (status));
+ free (name);
+ return 1;
+ }
+ mu_mailbox_attach_ticket (newbox);
+
+ if ((status = mu_mailbox_open (newbox, MU_STREAM_RDWR)) != 0)
{
mu_mailbox_destroy (&newbox);
mu_error(_("Cannot open mailbox %s: %s"), name, mu_strerror (status));
free (name);
return 1;
}
free (name); /* won't need it any more */
page_invalidate (1); /* Invalidate current page map */
-
+
mu_mailbox_get_url (mbox, &url);
pname = mu_strdup (mu_url_to_string (url));
if (mail_mbox_close ())
{
if (pname)
free (pname);
mu_mailbox_close (newbox);
mu_mailbox_destroy (&newbox);
return 1;
}
-
+
if (prev_name)
free (prev_name);
prev_name = pname;
-
+
mbox = newbox;
mu_mailbox_messages_count (mbox, &total);
set_cursor (1);
if (mailvar_is_true ("header"))
{
util_do_command ("summary");
@@ -125,7 +134,6 @@ mail_file (int argc, char **argv)
else
{
mu_error (_("%s takes only one argument"), argv[0]);
}
return 1;
}
-
diff --git a/mail/mailline.c b/mail/mailline.c
index f1fa4b2..1574125 100644
--- a/mail/mailline.c
+++ b/mail/mailline.c
@@ -15,12 +15,13 @@
along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */
#include "mail.h"
#include <sys/stat.h>
#include <dirent.h>
#include <mailutils/folder.h>
+#include <mailutils/auth.h>
#ifdef WITH_READLINE
static char **ml_command_completion (char *cmd, int start, int end);
static char *ml_command_generator (const char *text, int state);
#endif
@@ -206,13 +207,13 @@ ml_reread (const char *prompt, char **text)
char **
ml_command_completion (char *cmd, int start, int end)
{
char **ret;
char *p;
struct mu_wordsplit ws;
-
+
for (p = rl_line_buffer; p < rl_line_buffer + start && mu_isblank (*p); p++)
;
if (mu_wordsplit_len (p, end, &ws, MU_WRDSF_DEFFLAGS))
{
mu_error (_("mu_wordsplit_len failed: %s"),
@@ -236,13 +237,13 @@ ml_command_completion (char *cmd, int start, int end)
int point = COMPL_DFL;
if (start == end)
point |= COMPL_WS;
if (mu_str_skip_class (p + end, MU_CTYPE_SPACE)[0] == 0)
point |= COMPL_LASTARG;
-
+
ret = entry->command_completion (ws.ws_wordc, ws.ws_wordv, point);
}
else
ret = NULL;
}
mu_wordsplit_free (&ws);
@@ -292,13 +293,13 @@ ml_attempted_completion_over (void)
/* Concatenate results of two completions. Both A and B are expected to
be returned by rl_completion_matches, i.e. their first entry is the
longest common prefix of the remaining entries, which are sorted
lexicographically. Array B is treated as case-insensitive.
-
+
If either of the arrays is NULL, the other one is returned unchanged.
Otherwise, if A[0] begins with a lowercase letter, all items from B
will be converted to lowercase.
Both A and B (but not their elements) are freed prior to returning.
@@ -309,36 +310,36 @@ ml_attempted_completion_over (void)
static char **
compl_concat (char **a, char **b)
{
size_t i, j, k, n = 0, an, bn;
char **ret;
int lwr = 0;
-
+
if (a)
{
lwr = mu_islower (a[0][0]);
for (an = 0; a[an]; an++)
;
}
else
return b;
-
+
if (b)
{
for (bn = 0; b[bn]; bn++)
{
if (lwr)
mu_strlower (b[bn]);
- }
+ }
}
else
return a;
i = an == 1 ? 0 : 1;
j = bn == 1 ? 0 : 1;
-
+
n = (an - i) + (bn - j) + 1;
ret = mu_calloc (n + 1, sizeof (ret[0]));
if (an == bn && an == 1)
{
/* Compute LCP of both entries */
@@ -353,13 +354,13 @@ compl_concat (char **a, char **b)
ret[0] = mu_strdup ((strlen (a[0]) < strlen (b[0])) ? a[0] : b[0]);
if (i)
free (a[0]);
if (j)
free (b[0]);
-
+
k = 1;
while (k < n)
{
if (!a[i])
{
memcpy (ret + k, b + j, sizeof (b[0]) * (bn - j));
@@ -374,47 +375,47 @@ compl_concat (char **a, char **b)
ret[k++] = (strcmp (a[i], b[j]) < 0) ? a[i++] : b[j++];
}
ret[n] = NULL;
free (a);
free (b);
return ret;
-}
+}
static char *msgtype_generator (const char *text, int state);
static char *header_generator (const char *text, int state);
/* Internal completion generator for commands that take a message list
(if MATCHES is NULL), or a messages list followed by another argument
(if MATCHES is not NULL).
In the latter case the MATCHES function generates expansions for the
last argument. It is used for such commands as write, where the last
object is a mailbox or pipe, where it is a command).
-
+
CLOSURE supplies argument for MATCHES. It is ignored if MATCHES is NULL.
*/
static char **
msglist_closure_compl (int argc, char **argv, int point,
char **(*matches) (void*),
void *closure)
{
char *text = (point & COMPL_WS) ? "" : argv[argc-1];
size_t len = strlen (text);
-
+
if (text[0] == ':')
{
if (text[1] && (text[1] == '/' || text[2]))
{
ml_set_completion_append_character (0);
ml_attempted_completion_over ();
return NULL;
}
ml_set_completion_append_character (' ');
return rl_completion_matches (text, msgtype_generator);
}
-
+
ml_set_completion_append_character (0);
if (len && text[len-1] == ':')
{
char **ret = mu_calloc(2, sizeof (ret[0]));
ret[0] = strcat (strcpy (mu_alloc (len + 2), text), "/");
return ret;
@@ -447,125 +448,225 @@ command_compl (int argc, char **argv, int point)
{
ml_set_completion_append_character (0);
if (point & COMPL_WS)
return NULL;
return rl_completion_matches (argv[argc-1], ml_command_generator);
}
+
+struct filegen
+{
+ mu_list_t list;
+ mu_iterator_t itr;
+ size_t pathlen;
+ char repl;
+ int flags;
+};
-/* Generate file list based on reference prefix TEXT, relative to PATH.
- Remove PATHLEN leading characters from the returned names. Replace
- them with REPL unless it is 0.
+static void
+filegen_free (struct filegen *fg)
+{
+ mu_iterator_destroy (&fg->itr);
+ mu_list_destroy (&fg->list);
+}
- Select only those files that match given FLAGS (MU_FOLDER_ATTRIBUTE_*
- constants).
+enum
+ {
+ any_folder,
+ local_folder
+ };
- STATE is 0 for the first call, 1 otherwise.
- */
-static char *
-file_generator (const char *text, int state,
- char *path, size_t pathlen,
- char repl,
- int flags)
+#define PATHLEN_AUTO ((size_t)-1)
+
+static int
+filegen_init (struct filegen *fg,
+ const char *text,
+ const char *folder_path,
+ int type,
+ size_t pathlen,
+ int repl,
+ int flags)
{
- static mu_list_t list;
- static mu_iterator_t itr;
+ char *pathref;
+ char *wcard;
+ mu_folder_t folder;
+ size_t count, i, len;
+ mu_url_t url;
+ int rc;
- if (!state)
- {
- char *wcard;
- mu_folder_t folder;
- size_t count;
+ pathref = mu_strdup (text);
+ len = strlen (pathref);
+ for (i = len; i > 0; i--)
+ if (pathref[i-1] == '/')
+ break;
+ wcard = mu_alloc (len - i + 2);
+ strcpy (wcard, pathref + i);
+ strcat (wcard, "%");
+ pathref[i] = 0;
- wcard = mu_alloc (strlen (text) + 2);
- strcat (strcpy (wcard, text), "*");
+ rc = mu_folder_create (&folder, folder_path);
+ if (rc)
+ {
+ mu_diag_funcall (MU_DIAG_ERROR, "mu_folder_create", folder_path, rc);
+ free (wcard);
+ free (pathref);
+ return -1;
+ }
- if (mu_folder_create (&folder, path))
+ if (!mu_folder_is_local (folder))
+ {
+ if (type == local_folder)
{
+ mu_error ("%s", _("folder must be set to a local folder"));
free (wcard);
- return NULL;
+ free (pathref);
+ return -1;
}
- mu_folder_list (folder, path, wcard, 1, &list);
+ /* Set ticket for a remote folder */
+ rc = mu_folder_attach_ticket (folder);
+ if (rc)
+ {
+ mu_authority_t auth = NULL;
+
+ if (mu_folder_get_authority (folder, &auth) == 0 && auth)
+ {
+ mu_ticket_t tct;
+ mu_noauth_ticket_create (&tct);
+ rc = mu_authority_set_ticket (auth, tct);
+ if (rc)
+ mu_diag_funcall (MU_DIAG_ERROR, "mu_authority_set_ticket",
+ NULL, rc);
+ }
+ }
+ }
+
+ rc = mu_folder_open (folder, MU_STREAM_READ);
+ if (rc)
+ {
+ mu_diag_funcall (MU_DIAG_ERROR, "mu_folder_open", folder_path, rc);
free (wcard);
+ free (pathref);
+ return -1;
+ }
+
+ if (mu_folder_get_url (folder, &url))
+ {
+ free (wcard);
+ free (pathref);
mu_folder_destroy (&folder);
+ }
- if (mu_list_count (list, &count) || count == 0)
- {
- mu_list_destroy (&list);
- return NULL;
- }
- else if (count == 1)
- ml_set_completion_append_character (0);
+ if (pathlen == PATHLEN_AUTO)
+ {
+ char const *urlpath;
+
+ mu_url_sget_path (url, &urlpath);
+ fg->pathlen = strlen (urlpath);
+ while (fg->pathlen > 0 && urlpath[fg->pathlen-1] == '/')
+ fg->pathlen--;
+ if (fg->pathlen == 1 && urlpath[0] == '/')
+ fg->pathlen = 0;
+ }
+ else
+ fg->pathlen = pathlen;
- if (mu_list_get_iterator (list, &itr))
+ mu_folder_list (folder, pathref, wcard, 1, &fg->list);
+ free (wcard);
+ free (pathref);
+ mu_folder_destroy (&folder);
+
+ if (mu_list_count (fg->list, &count) || count == 0)
+ {
+ mu_list_destroy (&fg->list);
+ return -1;
+ }
+ else if (count == 1)
+ {
+ if (flags & MU_FOLDER_ATTRIBUTE_DIRECTORY)
{
- mu_list_destroy (&list);
- return NULL;
+ struct mu_list_response *resp;
+ mu_list_head (fg->list, (void**)&resp);
+ if (resp->type & MU_FOLDER_ATTRIBUTE_DIRECTORY)
+ {
+ size_t len = strlen (resp->name);
+ resp->name = mu_realloc (resp->name, len + 2);
+ resp->name[len] = resp->separator;
+ resp->name[len+1] = 0;
+ }
}
- mu_iterator_first (itr);
+ ml_set_completion_append_character (0);
}
- while (!mu_iterator_is_done (itr))
+ if (mu_list_get_iterator (fg->list, &fg->itr))
+ {
+ mu_list_destroy (&fg->list);
+ return -1;
+ }
+ mu_iterator_first (fg->itr);
+ fg->repl = repl;
+ fg->flags = flags;
+ return 0;
+}
+
+static char *
+filegen_next (struct filegen *fg)
+{
+ while (!mu_iterator_is_done (fg->itr))
{
struct mu_list_response *resp;
- mu_iterator_current (itr, (void**)&resp);
- mu_iterator_next (itr);
- if (resp->type & flags)
+ mu_iterator_current (fg->itr, (void**)&resp);
+ mu_iterator_next (fg->itr);
+ if (resp->type & fg->flags)
{
char *ret;
- if (pathlen)
- {
- size_t len = strlen (resp->name + pathlen);
- char *ptr;
-
- ret = mu_alloc (len + (repl ? 1 : 0) + 1);
- ptr = ret;
- if (repl)
- *ptr++ = repl;
- memcpy (ptr, resp->name + pathlen, len);
- ptr[len] = 0;
- }
- else
- ret = mu_strdup (resp->name);
+ size_t len = strlen (resp->name + fg->pathlen);
+ char *ptr;
+
+ ret = mu_alloc (len + (fg->repl ? 1 : 0) + 1);
+ ptr = ret;
+ if (fg->repl)
+ *ptr++ = fg->repl;
+ memcpy (ptr, resp->name + fg->pathlen, len);
+ ptr[len] = 0;
+ // if (resp->type & (fg->flags & MU_FOLDER_ATTRIBUTE_DIRECTORY))
return ret;
}
}
- mu_iterator_destroy (&itr);
- mu_list_destroy (&list);
+ filegen_free (fg);
return NULL;
}
static char *
folder_generator (const char *text, int state)
{
- char *ret;
- static size_t pathlen;
+ static struct filegen fg;
if (!state)
{
- char *path = util_folder_path ("");
+ int rc;
+ char *path = util_folder_path ("+");
if (!path)
return NULL;
- pathlen = strlen (path);
- ret = file_generator (text, state, path, pathlen, '+',
- MU_FOLDER_ATTRIBUTE_ALL);
+ rc = filegen_init (&fg, text, path,
+ any_folder,
+ PATHLEN_AUTO, '+',
+ MU_FOLDER_ATTRIBUTE_ALL);
free (path);
+ if (rc)
+ return NULL;
}
- else
- ret = file_generator (text, state, NULL, pathlen, '+',
- MU_FOLDER_ATTRIBUTE_ALL);
- return ret;
+ return filegen_next (&fg);
}
static char *
msgtype_generator (const char *text, int state)
{
/* Allowed message types, plus '/'. The latter can folow a colon,
meaning body lookup */
- static char types[] = "dnorTtu/";
+ static char types[] = "dnorTtu/";
static int i;
char c;
if (!state)
{
i = 0;
@@ -656,13 +757,13 @@ header_generator (const char *text, int state)
}
char **
file_compl (int argc, char **argv, int point)
{
char *text;
-
+
if (point & COMPL_WS)
{
ml_set_completion_append_character (0);
ml_attempted_completion_over ();
return NULL;
}
@@ -676,18 +777,18 @@ file_compl (int argc, char **argv, int point)
case '%':
case '#':
case '&':
ml_attempted_completion_over ();
break;
-
+
default:
/* Suppose it is a file name */
return rl_completion_matches (text, rl_filename_completion_function);
}
-
+
return NULL;
}
struct compl_closure
{
int argc;
@@ -709,59 +810,89 @@ msglist_file_compl (int argc, char **argv, int point)
return msglist_closure_compl (argc, argv, point, file_compl_matches, &clos);
}
static char *
dir_generator (const char *text, int state)
{
- char *ret;
- static size_t pathlen;
- static int repl;
+ static struct filegen fg;
if (!state)
{
char *path;
+ char *p;
+ int rc;
+ char repl;
+ size_t pathlen;
+
switch (text[0])
{
case '+':
- text++;
- repl = '+';
- path = util_folder_path (text);
- pathlen = strlen (path) - strlen (text);
+ {
+ char *f;
+ repl = '+';
+ f = util_folder_path ("+");
+ pathlen = strlen (f);
+ path = mu_make_file_name (f, text + 1);
+ free (f);
+ }
break;
case '~':
repl = '~';
if (text[1] == '/')
{
- path = mu_get_homedir ();
- text += 2;
- pathlen = strlen (path);
- break;
+ char *home = mu_get_homedir ();
+ pathlen = strlen (home);
+ path = mu_make_file_name (home, text + 2);
+ free (home);
}
- /* else FIXME! */
+ else
+ {
+ ml_attempted_completion_over ();
+ return NULL;
+ /* FIXME: implement user-name completion */
+ }
+ break;
case '/':
path = mu_strdup (text);
pathlen = 0;
repl = 0;
break;
default:
- path = mu_strdup ("./");
- pathlen = 2;
+ {
+ char *cwd = mu_getcwd ();
+ pathlen = strlen (cwd);
+ path = mu_make_file_name (cwd, text);
+ free (cwd);
+ }
repl = 0;
}
-
- ret = file_generator (text, state, path, pathlen, repl,
- MU_FOLDER_ATTRIBUTE_DIRECTORY);
- free (path);
+ p = strrchr (path, '/');
+ if (*p)
+ {
+ if (p[1])
+ *p++ = 0;
+ else
+ p = "";
+ rc = filegen_init (&fg, p, path[0] ? path : "/",
+ local_folder,
+ pathlen, repl,
+ MU_FOLDER_ATTRIBUTE_DIRECTORY);
+ }
+ else
+ {
+ ml_attempted_completion_over ();
+ rc = -1;
+ }
+ if (rc)
+ return NULL;
}
- else
- ret = file_generator (text, state, NULL, pathlen, repl,
- MU_FOLDER_ATTRIBUTE_DIRECTORY);
- return ret;
+
+ return filegen_next (&fg);
}
char **
dir_compl (int argc, char **argv, int point)
{
ml_attempted_completion_over ();
@@ -798,26 +929,12 @@ alias_compl (int argc, char **argv, int point)
ml_attempted_completion_over ();
return rl_completion_matches ((point & COMPL_WS) ? "" : argv[argc-1],
alias_generator);
}
static char *
-mkfilename (const char *dir, const char *file)
-{
- size_t len = strlen (dir) + 1 + strlen (file) + 1;
- char *p = malloc (len);
- if (p)
- {
- strcpy (p, dir);
- strcat (p, "/");
- strcat (p, file);
- }
- return p;
-}
-
-static char *
exec_generator (const char *text, int state)
{
static int prefix_len;
static char *var;
static char *dir;
static size_t dsize;
@@ -874,13 +991,13 @@ exec_generator (const char *text, int state)
if (!dp)
continue;
}
while ((ent = readdir (dp)))
{
- char *name = mkfilename (dir, ent->d_name);
+ char *name = mu_make_file_name (dir, ent->d_name);
if (name)
{
int rc = access (name, X_OK);
if (rc == 0)
{
struct stat st;
diff --git a/mail/mailvar.c b/mail/mailvar.c
index 206166c..5cdb7f1 100644
--- a/mail/mailvar.c
+++ b/mail/mailvar.c
@@ -286,13 +286,13 @@ struct mailvar_symbol mailvar_tab[] =
/* These will be implemented later */
{ { "onehop", }, MAILVAR_HIDDEN, NULL },
{ { "quiet", }, MAILVAR_TYPEMASK (mailvar_type_boolean) | MAILVAR_HIDDEN,
"suppresses the printing of the version when first invoked" },
-
+
{ { NULL }, }
};
static int mailvar_symbol_count = sizeof (mailvar_tab) / sizeof (mailvar_tab[0]) - 1;
struct mailvar_symbol *
diff --git a/mail/util.c b/mail/util.c
index 0475e9e..f5471e7 100644
--- a/mail/util.c
+++ b/mail/util.c
@@ -39,13 +39,13 @@ util_do_command (const char *fmt, ...)
char **argv;
int status = 0;
const struct mail_command_entry *entry = NULL;
char *cmd = NULL;
size_t size = 0;
va_list ap;
-
+
va_start (ap, fmt);
status = mu_vasnprintf (&cmd, &size, fmt, ap);
va_end (ap);
if (status)
return status;
@@ -58,13 +58,13 @@ util_do_command (const char *fmt, ...)
return 0;
}
if (cmd[0] == '\0')
{
free (cmd);
-
+
/* Hitting return i.e. no command, is equivalent to next
according to the POSIX spec. Note, that this applies
to interactive state only. */
if (interactive)
cmd = mu_strdup ("next");
else
@@ -82,13 +82,13 @@ util_do_command (const char *fmt, ...)
else
{
char *p;
argc = ws.ws_wordc;
argv = ws.ws_wordv + 1;
-
+
/* Special case: a number alone implies "print" */
if (argc == 1
&& ((strtoul (argv[0], &p, 10) > 0 && *p == 0)
|| (argv[0][1] == 0 && strchr("^$", argv[0][0]))))
{
/* Use the extra slot for "print" command */
@@ -105,22 +105,22 @@ util_do_command (const char *fmt, ...)
entry = mail_find_command ("quit");
if (!entry)
{
/* argv[0] might be a traditional /bin/mail contracted form, e.g.
`d*' or `p4'. */
-
+
char *p;
-
+
for (p = argv[0] + strlen (argv[0]) - 1;
p > argv[0] && !mu_isalpha (*p);
p--)
;
p++;
-
+
if (strlen (p))
{
/* Expand contracted form. That's what we have kept an extra
ws slot for. */
argc++;
argv--;
@@ -128,16 +128,16 @@ util_do_command (const char *fmt, ...)
argv[1] = mu_strdup (p);
*p = 0;
/* Register the new entry in WS */
ws.ws_wordc++;
ws.ws_offs = 0;
}
-
+
entry = mail_find_command (argv[0]);
}
-
+
if (entry)
{
/* Make sure we are not in any if/else */
if (!(if_cond () == 0 && (entry->flags & EF_FLOW) == 0))
status = entry->func (argc, argv);
}
@@ -180,18 +180,18 @@ util_foreach_msg (int argc, char **argv, int flags,
msgset_free (list);
return status;
}
size_t
-util_range_msg (size_t low, size_t high, int flags,
+util_range_msg (size_t low, size_t high, int flags,
msg_handler_t func, void *data)
{
msgset_t msgspec = { 0 };
size_t count, expect_count;
-
+
msgspec.next = NULL;
msgspec.npart = 0;
msgspec.msg_part = &low;
if (!func)
flags |= MSG_SILENT;
@@ -214,13 +214,13 @@ util_range_msg (size_t low, size_t high, int flags,
{
if (!(flags & MSG_SILENT))
mu_error (_("%lu: Inappropriate message (has been deleted)"),
(unsigned long) low);
continue;
}
-
+
if (util_get_message (mbox, low, &mesg) == 0)
{
count ++;
if (func)
func (&msgspec, mesg, data) ;
/* Bail out if we receive an interrupt. */
@@ -247,19 +247,19 @@ util_command_get (const char *cmd)
void *
util_find_entry (void *table, size_t nmemb, size_t size, const char *cmd)
{
int i;
int len = strlen (cmd);
char *p;
-
+
for (p = table, i = 0; i < nmemb; i++, p += size)
{
struct mail_command *cp = (struct mail_command *)p;
int ll = strlen (cp->longname);
int sl = strlen (cp->shortname);
-
+
if (sl > ll && !strncmp (cp->shortname, cmd, sl))
return p;
else if (sl == len && !strcmp (cp->shortname, cmd))
return p;
else if (sl < len && !strncmp (cp->longname, cmd, len))
return p;
@@ -282,13 +282,13 @@ util_help (void *table, size_t nmemb, size_t size, const char *word)
{
struct mail_command *cp = (struct mail_command *)p;
if (cp->synopsis == NULL)
continue;
mu_stream_printf (out, "%s\n", cp->synopsis);
}
-
+
mu_stream_unref (out);
return 0;
}
else
{
@@ -310,13 +310,13 @@ int
util_command_list (void *table, size_t nmemb, size_t size)
{
int i;
char *p;
int cols = util_screen_columns ();
int pos = 0;
-
+
for (p = table, i = 0; i < nmemb; i++, p += size)
{
const char *cmd;
struct mail_command *cp = (struct mail_command *)p;
int len = strlen (cp->longname);
if (len < 1)
@@ -332,13 +332,13 @@ util_command_list (void *table, size_t nmemb, size_t size)
if (pos >= cols)
{
pos = len + 1;
mu_printf ("\n%s ", cmd);
}
else
- mu_printf ("%s ", cmd);
+ mu_printf ("%s ", cmd);
}
mu_printf ("\n");
return 0;
}
/*
@@ -464,50 +464,36 @@ util_fullpath (const char *inpath)
}
char *
util_folder_path (const char *name)
{
char *folder;
- char *tmp;
- char *p;
-
+ int rc;
+
if (mailvar_get (&folder, "folder", mailvar_type_string, 1))
return NULL;
-
+
if (!name)
return NULL;
- if (name[0] == '+')
- name++;
-
- if (folder[0] != '/' && folder[0] != '~')
- {
- char *home = mu_get_homedir ();
- tmp = mu_alloc (strlen (home) + 1 +
- strlen (folder) + 1 +
- strlen (name) + 1);
- sprintf (tmp, "%s/%s/%s", home, folder, name);
- }
- else
+
+ rc = mu_mailbox_expand_name (name, &folder);
+ if (rc)
{
- tmp = mu_alloc (strlen (folder) + 1 +
- strlen (name) + 1);
- sprintf (tmp, "%s/%s", folder, name);
+ mu_diag_funcall (MU_DIAG_ERROR, "mailbox_expand_name", name, rc);
+ return NULL;
}
- p = util_fullpath (tmp);
- free (tmp);
-
- return p;
+ return folder;
}
char *
util_get_sender (int msgno, int strip)
{
mu_message_t msg = NULL;
mu_address_t addr = NULL;
char *buf = NULL, *p;
-
+
mu_mailbox_get_message (mbox, msgno, &msg);
addr = get_sender_address (msg);
if (!addr)
{
mu_envelope_t env = NULL;
const char *buffer;
@@ -656,49 +642,58 @@ util_strcat (char **dest, const char *str)
}
char *
util_outfolder_name (char *str)
{
char *outfolder;
+ char *exp;
+ int rc;
if (!str)
return NULL;
-
+
switch (*str)
{
case '/':
case '~':
- str = util_fullpath (str);
- break;
-
case '+':
- str = util_folder_path (str);
+ rc = mu_mailbox_expand_name (str, &exp);
+ if (rc)
+ {
+ mu_diag_funcall (MU_DIAG_ERROR, "mu_mailbox_expand_name", str, rc);
+ return NULL;
+ }
break;
default:
if (mailvar_get (&outfolder, "outfolder", mailvar_type_string, 0) == 0)
{
- char *ns = NULL;
- mu_asprintf (&ns, "%s/%s", outfolder, str);
- str = util_fullpath (ns);
- free (ns);
+ char *s = mu_make_file_name (outfolder, str);
+ rc = mu_mailbox_expand_name (s, &exp);
+ if (rc)
+ {
+ mu_diag_funcall (MU_DIAG_ERROR, "mu_mailbox_expand_name", s, rc);
+ free (s);
+ return NULL;
+ }
+ free (s);
}
break;
}
- return mu_strdup (str);
+ return exp;
}
/* Save an outgoing message. The SAVEFILE argument overrides the setting
of the "record" variable. */
void
util_save_outgoing (mu_message_t msg, char *savefile)
{
char *record;
-
+
if (mailvar_get (&record, "record", mailvar_type_string, 0) == 0)
{
int rc;
mu_mailbox_t outbox;
char *filename = util_outfolder_name (savefile ? savefile : record);
@@ -722,13 +717,13 @@ util_save_outgoing (mu_message_t msg, char *savefile)
mu_error (_("Cannot append message to `%s': %s"),
filename, mu_strerror (rc));
}
mu_mailbox_close (outbox);
mu_mailbox_destroy (&outbox);
-
+
free (filename);
}
}
static int
util_descend_subparts (mu_message_t mesg, msgset_t *msgset, mu_message_t *part)
@@ -833,24 +828,24 @@ util_merge_addresses (char **addr_str, const char *value)
{
mu_address_t addr, new_addr;
int rc;
if ((rc = mu_address_create (&new_addr, value)) != 0)
return rc;
-
+
if ((rc = mu_address_create (&addr, *addr_str)) != 0)
{
mu_address_destroy (&new_addr);
return rc;
}
rc = mu_address_union (&addr, new_addr);
if (rc == 0)
{
char *val;
-
+
rc = mu_address_aget_printable (addr, &val);
if (rc == 0)
{
if (!val)
return MU_ERR_NOENT;
free (*addr_str);
@@ -870,51 +865,51 @@ is_address_field (const char *name)
MU_HEADER_TO,
MU_HEADER_CC,
MU_HEADER_BCC,
0
};
char **p;
-
+
for (p = address_fields; *p; p++)
if (mu_c_strcasecmp (*p, name) == 0)
return 1;
return 0;
}
int
util_header_expand (mu_header_t *phdr)
{
size_t i, nfields = 0;
mu_header_t hdr;
int errcnt = 0, rc;
-
+
rc = mu_header_create (&hdr, "", 0);
if (rc)
{
mu_error (_("Cannot create temporary header: %s"), mu_strerror (rc));
return 1;
}
-
+
mu_header_get_field_count (*phdr, &nfields);
for (i = 1; i <= nfields; i++)
{
const char *name, *value;
-
+
if (mu_header_sget_field_name (*phdr, i, &name))
continue;
if (mu_header_sget_field_value (*phdr, i, &value))
continue;
-
+
if (is_address_field (name))
{
const char *s;
mu_address_t addr = NULL;
struct mu_wordsplit ws;
size_t j;
-
+
if (mu_header_sget_value (hdr, name, &s) == 0)
mu_address_create (&addr, s);
ws.ws_delim = ",";
if (mu_wordsplit (value, &ws,
MU_WRDSF_DELIM|MU_WRDSF_SQUEEZE_DELIMS|
@@ -929,15 +924,15 @@ util_header_expand (mu_header_t *phdr)
for (j = 0; j < ws.ws_wordc; j++)
{
const char *exp;
mu_address_t new_addr;
char *p = ws.ws_wordv[j];
-
+
if (mailvar_is_true ("inplacealiases"))
- /* If inplacealiases was set, the value was already expanded */
+ /* If inplacealiases was set, the value was already expanded */
exp = p;
else
exp = alias_expand (p);
rc = mu_address_create (&new_addr, p);
if (rc)
{
@@ -946,21 +941,21 @@ util_header_expand (mu_header_t *phdr)
mu_error (_("Cannot parse address `%s' (while expanding `%s'): %s"),
exp, p, mu_strerror (rc));
else
mu_error (_("Cannot parse address `%s': %s"),
p, mu_strerror (rc));
}
-
+
mu_address_union (&addr, new_addr);
mu_address_destroy (&new_addr);
}
-
+
if (addr)
{
const char *newvalue;
-
+
rc = mu_address_sget_printable (addr, &newvalue);
if (rc == 0 && newvalue)
mu_header_set_value (hdr, name, newvalue, 1);
mu_address_destroy (&addr);
}
}
@@ -986,13 +981,13 @@ util_get_message (mu_mailbox_t mbox, size_t msgno, mu_message_t *msg)
if (msgno > total)
{
util_error_range (msgno);
return MU_ERR_NOENT;
}
-
+
status = mu_mailbox_get_message (mbox, msgno, msg);
if (status)
{
mu_error (_("Cannot get message %lu: %s"),
(unsigned long) msgno, mu_strerror (status));
return status;
@@ -1057,13 +1052,13 @@ util_get_charset (void)
if (mu_c_strcasecmp (charset, "auto") == 0)
{
struct mu_lc_all lc_all = { .flags = 0 };
char *tmp = getenv ("LC_ALL");
if (!tmp)
tmp = getenv ("LANG");
-
+
if (tmp && mu_parse_lc_all (tmp, &lc_all, MU_LC_CSET) == 0)
{
charset = mu_strdup (lc_all.charset);
mu_lc_all_free (&lc_all);
}
else
@@ -1086,13 +1081,13 @@ util_rfc2047_decode (char **value)
charset = util_get_charset ();
if (!charset)
return;
rc = mu_rfc2047_decode (charset, *value, &tmp);
free (charset);
-
+
if (rc)
{
if (mailvar_is_true ("verbose"))
mu_error (_("Cannot decode line `%s': %s"), *value, mu_strerror (rc));
}
else
@@ -1121,13 +1116,13 @@ util_url_to_string (mu_url_t url)
mu_stream_t
open_pager (size_t lines)
{
const char *pager;
unsigned pagelines = util_get_crt ();
mu_stream_t str;
-
+
if (pagelines && lines > pagelines && (pager = getenv ("PAGER")))
{
int rc = mu_command_stream_create (&str, pager, MU_STREAM_WRITE);
if (rc)
{
mu_diag_funcall (MU_DIAG_ERROR, "mu_prog_stream_create",

Return to:

Send suggestions and report system problems to the System administrator.