commit 46584e5358dbd32b8549b15ce543c33482bc6d60
parent 3bfc3c5063b5c5a02d77c97dd43461e7e19ca0f7
Author: Oswald Buddenhagen <ossi@users.sf.net>
Date: Fri, 3 Jun 2022 20:58:09 +0200
add support for Maildir Paths with suffixes
that is, Path not ending with a slash.
pedantically, this is a bugfix, as the manual already suggested that
this is possible (and at least one user got the hint, though he was
disappointed).
the IMAP driver already supports this.
Diffstat:
3 files changed, 60 insertions(+), 6 deletions(-)
diff --git a/NEWS b/NEWS
@@ -21,6 +21,8 @@ MaxMessages and MaxSize can be used together now.
Added support for IMAP mailbox names with non-ASCII characters.
+Added support for Maildir Paths with suffixes.
+
The unfiltered list of mailboxes in each Store can be printed now.
A proper summary is now printed prior to exiting.
diff --git a/src/drv_maildir.c b/src/drv_maildir.c
@@ -35,6 +35,7 @@ typedef union maildir_store_conf {
struct {
STORE_CONF
char *path;
+ char *path_sfx;
char *inbox;
#ifdef USE_DB
int alt_map;
@@ -121,16 +122,20 @@ static char *
maildir_join_path( maildir_store_conf_t *conf, int in_inbox, const char *box )
{
char *out, *p;
- const char *prefix;
- uint pl, bl, n;
+ const char *prefix, *infix;
+ uint pl, il, bl, n;
char c;
if (in_inbox || conf->sub_style == SUB_MAILDIRPP) {
prefix = conf->inbox;
+ infix = NULL;
+ il = 0;
} else {
if (maildir_ensure_path( conf ) < 0)
return NULL;
prefix = conf->path;
+ infix = conf->path_sfx;
+ il = strlen( infix ) + 1;
}
pl = strlen( prefix );
for (bl = 0, n = 0; (c = box[bl]); bl++) {
@@ -157,12 +162,16 @@ maildir_join_path( maildir_store_conf_t *conf, int in_inbox, const char *box )
default: /* SUB_LEGACY and SUB_UNSET */
break;
}
- out = nfmalloc( pl + bl + n + 1 );
+ out = nfmalloc( pl + il + bl + n + 1 );
memcpy( out, prefix, pl );
p = out + pl;
if (conf->sub_style == SUB_MAILDIRPP) {
*p++ = '/';
*p++ = '.';
+ } else if (il) {
+ *p++ = '/';
+ memcpy( p, infix, il - 1 );
+ p += il - 1;
}
while ((c = *box++)) {
if (c == '/') {
@@ -366,6 +375,7 @@ maildir_list_maildirpp( maildir_store_t *ctx, int flags, const char *inbox )
static int
maildir_list_recurse( maildir_store_t *ctx, int isBox, int flags,
const char *inbox, uint inboxLen,
+ char *suffix, int suffixLen,
char *path, int pathLen, char *name, int nameLen )
{
DIR *dir;
@@ -399,6 +409,16 @@ maildir_list_recurse( maildir_store_t *ctx, int isBox, int flags,
pl = nfsnprintf( path + pathLen, _POSIX_PATH_MAX - pathLen, "%s", ent );
if (pl == 3 && (!memcmp( ent, "cur", 3 ) || !memcmp( ent, "new", 3 ) || !memcmp( ent, "tmp", 3 )))
continue;
+ if (suffixLen) {
+ if (!starts_with( ent, pl, suffix, suffixLen ))
+ continue;
+ if (pl == suffixLen) {
+ error( "Maildir error: empty mailbox name under %s - did you forget the trailing slash?\n", path );
+ closedir( dir );
+ return -1;
+ }
+ ent += suffixLen;
+ }
pl += pathLen;
if (inbox && equals( path, pl, inbox, inboxLen )) {
// Inbox nested into Path.
@@ -429,7 +449,7 @@ maildir_list_recurse( maildir_store_t *ctx, int isBox, int flags,
add_string_list( &ctx->boxes, name );
path[pl] = 0;
name[nl++] = '/';
- if (maildir_list_recurse( ctx, isBox + 1, flags, inbox, inboxLen, path, pl, name, nl ) < 0) {
+ if (maildir_list_recurse( ctx, isBox + 1, flags, inbox, inboxLen, NULL, 0, path, pl, name, nl ) < 0) {
closedir( dir );
return -1;
}
@@ -450,7 +470,7 @@ maildir_list_inbox( maildir_store_t *ctx, int flags )
add_string_list( &ctx->boxes, "INBOX" );
return maildir_list_recurse(
- ctx, 1, flags, NULL, 0,
+ ctx, 1, flags, NULL, 0, NULL, 0,
path, nfsnprintf( path, _POSIX_PATH_MAX, "%s/", ctx->conf->inbox ),
name, nfsnprintf( name, _POSIX_PATH_MAX, "INBOX/" ) );
}
@@ -469,7 +489,8 @@ maildir_list_path( maildir_store_t *ctx, int flags )
const char *inbox = ctx->conf->inbox;
return maildir_list_recurse(
ctx, 0, flags, inbox, strlen( inbox ),
- path, nfsnprintf( path, _POSIX_PATH_MAX, "%s", ctx->conf->path ),
+ ctx->conf->path_sfx, strlen( ctx->conf->path_sfx ),
+ path, nfsnprintf( path, _POSIX_PATH_MAX, "%s/", ctx->conf->path ),
name, 0 );
}
@@ -1914,6 +1935,11 @@ maildir_parse_store( conffile_t *cfg, store_conf_t **storep )
if (starts_with( store->path, -1, store->inbox, inboxLen ) && store->path[inboxLen] == '/') {
error( "Maildir store '%s': Path cannot be nested under Inbox\n", store->name );
cfg->err = 1;
+ } else {
+ char *s = strrchr( store->path, '/' );
+ assert( s ); // due to expand_strdup()
+ store->path_sfx = s + 1;
+ *s = 0;
}
}
}
diff --git a/src/mbsyncrc.sample b/src/mbsyncrc.sample
@@ -57,6 +57,32 @@ Group boxes
Channels work personal remote
+# Due to the divergent Path suffixes, it's possible to have
+# multiple Stores homed in the same directory.
+# You could even put them all directly into $HOME.
+
+MaildirStore local-personal
+Path ~/Mail/personal-
+Inbox ~/Mail/personal-INBOX
+
+MaildirStore local-work
+Path ~/Mail/work-
+# Just because.
+Inbox ~/Mail/w0rk_InBoX
+
+Channel personal-joined
+Far :personal:
+Near :local-personal:
+Paterns *
+
+Channel work-joined
+Far :work:
+Near :local-work:
+Paterns *
+
+Group joined personal-joined work-joined
+
+
IMAPStore st1
Host st1.domain.com
AuthMech CRAM-MD5