introduce get_box_path() driver callback

... and make 'path' private to the maildir driver.
This commit is contained in:
Oswald Buddenhagen 2017-03-24 14:06:19 +01:00
parent d624c9af5d
commit 83ebe9022d
4 changed files with 49 additions and 27 deletions

View File

@ -90,7 +90,6 @@ typedef struct store {
char listed; /* was _list already run? */ char listed; /* was _list already run? */
/* currently open mailbox */ /* currently open mailbox */
char *path; /* own */
message_t *msgs; /* own */ message_t *msgs; /* own */
int uidvalidity; int uidvalidity;
int uidnext; /* from SELECT responses */ int uidnext; /* from SELECT responses */
@ -167,10 +166,12 @@ struct driver {
void (*list_store)( store_t *ctx, int flags, void (*list_store)( store_t *ctx, int flags,
void (*cb)( int sts, void *aux ), void *aux ); void (*cb)( int sts, void *aux ), void *aux );
/* Invoked before open_box(), this informs the driver which box is to be opened. /* Invoked before open_box(), this informs the driver which box is to be opened. */
* As a side effect, this should resolve ctx->path if applicable. */
int (*select_box)( store_t *ctx, const char *name ); int (*select_box)( store_t *ctx, const char *name );
/* Get the selected box' on-disk path, if applicable, null otherwise. */
const char *(*get_box_path)( store_t *ctx );
/* Create the selected mailbox. */ /* Create the selected mailbox. */
void (*create_box)( store_t *ctx, void (*create_box)( store_t *ctx,
void (*cb)( int sts, void *aux ), void *aux ); void (*cb)( int sts, void *aux ), void *aux );

View File

@ -2306,6 +2306,12 @@ imap_select_box( store_t *gctx, const char *name )
return DRV_OK; return DRV_OK;
} }
static const char *
imap_get_box_path( store_t *gctx ATTR_UNUSED )
{
return 0;
}
static void imap_open_box_p2( imap_store_t *, imap_cmd_t *, int ); static void imap_open_box_p2( imap_store_t *, imap_cmd_t *, int );
static void imap_open_box_p3( imap_store_t *, imap_cmd_t *, int ); static void imap_open_box_p3( imap_store_t *, imap_cmd_t *, int );
@ -3212,6 +3218,7 @@ struct driver imap_driver = {
imap_cancel_store, imap_cancel_store,
imap_list_store, imap_list_store,
imap_select_box, imap_select_box,
imap_get_box_path,
imap_create_box, imap_create_box,
imap_open_box, imap_open_box,
imap_confirm_box_empty, imap_confirm_box_empty,

View File

@ -72,6 +72,7 @@ typedef struct {
int uvfd, uvok, nuid, is_inbox, fresh[3]; int uvfd, uvok, nuid, is_inbox, fresh[3];
int minuid, maxuid, newuid, seenuid; int minuid, maxuid, newuid, seenuid;
int_array_t excs; int_array_t excs;
char *path; /* own */
char *trash; char *trash;
#ifdef USE_DB #ifdef USE_DB
DB *db; DB *db;
@ -265,7 +266,7 @@ maildir_cleanup( store_t *gctx )
ctx->db->close( ctx->db, 0 ); ctx->db->close( ctx->db, 0 );
free( ctx->usedb ); free( ctx->usedb );
#endif /* USE_DB */ #endif /* USE_DB */
free( gctx->path ); free( ctx->path );
free( ctx->excs.data ); free( ctx->excs.data );
if (ctx->uvfd >= 0) if (ctx->uvfd >= 0)
close( ctx->uvfd ); close( ctx->uvfd );
@ -920,7 +921,7 @@ maildir_scan( maildir_store_t *ctx, msg_t_array_alloc_t *msglist )
} }
} }
#endif /* USE_DB */ #endif /* USE_DB */
bl = nfsnprintf( buf, sizeof(buf) - 4, "%s/", ctx->gen.path ); bl = nfsnprintf( buf, sizeof(buf) - 4, "%s/", ctx->path );
restat: restat:
now = time( 0 ); now = time( 0 );
for (i = 0; i < 2; i++) { for (i = 0; i < 2; i++) {
@ -1236,18 +1237,24 @@ maildir_select_box( store_t *gctx, const char *name )
ctx->fresh[0] = ctx->fresh[1] = 0; ctx->fresh[0] = ctx->fresh[1] = 0;
if (starts_with( name, -1, "INBOX", 5 ) && (!name[5] || name[5] == '/')) { if (starts_with( name, -1, "INBOX", 5 ) && (!name[5] || name[5] == '/')) {
if (!name[5]) { if (!name[5]) {
gctx->path = nfstrdup( conf->inbox ); ctx->path = nfstrdup( conf->inbox );
ctx->is_inbox = 1; ctx->is_inbox = 1;
} else { } else {
gctx->path = maildir_join_path( conf, 1, name + 5 ); ctx->path = maildir_join_path( conf, 1, name + 5 );
ctx->is_inbox = 0; ctx->is_inbox = 0;
} }
} else { } else {
if (!(gctx->path = maildir_join_path( conf, 0, name ))) if (!(ctx->path = maildir_join_path( conf, 0, name )))
return DRV_CANCELED; return DRV_CANCELED;
ctx->is_inbox = 0; ctx->is_inbox = 0;
} }
return gctx->path ? DRV_OK : DRV_BOX_BAD; return ctx->path ? DRV_OK : DRV_BOX_BAD;
}
static const char *
maildir_get_box_path( store_t *gctx )
{
return ((maildir_store_t *)gctx)->path;
} }
static void static void
@ -1258,10 +1265,10 @@ maildir_open_box( store_t *gctx,
int ret; int ret;
char uvpath[_POSIX_PATH_MAX]; char uvpath[_POSIX_PATH_MAX];
if ((ret = maildir_validate( gctx->path, ctx->is_inbox, ctx )) != DRV_OK) if ((ret = maildir_validate( ctx->path, ctx->is_inbox, ctx )) != DRV_OK)
goto bail; goto bail;
nfsnprintf( uvpath, sizeof(uvpath), "%s/.uidvalidity", gctx->path ); nfsnprintf( uvpath, sizeof(uvpath), "%s/.uidvalidity", ctx->path );
#ifndef USE_DB #ifndef USE_DB
if ((ctx->uvfd = open( uvpath, O_RDWR|O_CREAT, 0600 )) < 0) { if ((ctx->uvfd = open( uvpath, O_RDWR|O_CREAT, 0600 )) < 0) {
sys_error( "Maildir error: cannot write %s", uvpath ); sys_error( "Maildir error: cannot write %s", uvpath );
@ -1271,13 +1278,13 @@ maildir_open_box( store_t *gctx,
#else #else
ctx->usedb = 0; ctx->usedb = 0;
if ((ctx->uvfd = open( uvpath, O_RDWR, 0600 )) < 0) { if ((ctx->uvfd = open( uvpath, O_RDWR, 0600 )) < 0) {
nfsnprintf( uvpath, sizeof(uvpath), "%s/.isyncuidmap.db", gctx->path ); nfsnprintf( uvpath, sizeof(uvpath), "%s/.isyncuidmap.db", ctx->path );
if ((ctx->uvfd = open( uvpath, O_RDWR, 0600 )) < 0) { if ((ctx->uvfd = open( uvpath, O_RDWR, 0600 )) < 0) {
if (((maildir_store_conf_t *)gctx->conf)->alt_map) { if (((maildir_store_conf_t *)gctx->conf)->alt_map) {
if ((ctx->uvfd = open( uvpath, O_RDWR|O_CREAT, 0600 )) >= 0) if ((ctx->uvfd = open( uvpath, O_RDWR|O_CREAT, 0600 )) >= 0)
goto dbok; goto dbok;
} else { } else {
nfsnprintf( uvpath, sizeof(uvpath), "%s/.uidvalidity", gctx->path ); nfsnprintf( uvpath, sizeof(uvpath), "%s/.uidvalidity", ctx->path );
if ((ctx->uvfd = open( uvpath, O_RDWR|O_CREAT, 0600 )) >= 0) if ((ctx->uvfd = open( uvpath, O_RDWR|O_CREAT, 0600 )) >= 0)
goto fnok; goto fnok;
} }
@ -1301,7 +1308,9 @@ static void
maildir_create_box( store_t *gctx, maildir_create_box( store_t *gctx,
void (*cb)( int sts, void *aux ), void *aux ) void (*cb)( int sts, void *aux ), void *aux )
{ {
cb( maildir_validate( gctx->path, 1, (maildir_store_t *)gctx ), aux ); maildir_store_t *ctx = (maildir_store_t *)gctx;
cb( maildir_validate( ctx->path, 1, ctx ), aux );
} }
static int static int
@ -1322,18 +1331,19 @@ static void
maildir_delete_box( store_t *gctx, maildir_delete_box( store_t *gctx,
void (*cb)( int sts, void *aux ), void *aux ) void (*cb)( int sts, void *aux ), void *aux )
{ {
maildir_store_t *ctx = (maildir_store_t *)gctx;
int i, bl, ret = DRV_OK; int i, bl, ret = DRV_OK;
struct stat st; struct stat st;
char buf[_POSIX_PATH_MAX]; char buf[_POSIX_PATH_MAX];
bl = nfsnprintf( buf, sizeof(buf) - 4, "%s/", gctx->path ); bl = nfsnprintf( buf, sizeof(buf) - 4, "%s/", ctx->path );
if (stat( buf, &st )) { if (stat( buf, &st )) {
if (errno != ENOENT) { if (errno != ENOENT) {
sys_error( "Maildir error: cannot access mailbox '%s'", gctx->path ); sys_error( "Maildir error: cannot access mailbox '%s'", ctx->path );
ret = DRV_BOX_BAD; ret = DRV_BOX_BAD;
} }
} else if (!S_ISDIR(st.st_mode)) { } else if (!S_ISDIR(st.st_mode)) {
error( "Maildir error: '%s' is no valid mailbox\n", gctx->path ); error( "Maildir error: '%s' is no valid mailbox\n", ctx->path );
ret = DRV_BOX_BAD; ret = DRV_BOX_BAD;
} else if ((ret = maildir_clear_tmp( buf, sizeof(buf), bl )) == DRV_OK) { } else if ((ret = maildir_clear_tmp( buf, sizeof(buf), bl )) == DRV_OK) {
nfsnprintf( buf + bl, sizeof(buf) - bl, ".uidvalidity" ); nfsnprintf( buf + bl, sizeof(buf) - bl, ".uidvalidity" );
@ -1362,10 +1372,12 @@ maildir_delete_box( store_t *gctx,
static int static int
maildir_finish_delete_box( store_t *gctx ) maildir_finish_delete_box( store_t *gctx )
{ {
maildir_store_t *ctx = (maildir_store_t *)gctx;
/* Subfolders are not deleted; the deleted folder is only "stripped of its mailboxness". /* Subfolders are not deleted; the deleted folder is only "stripped of its mailboxness".
* Consequently, the rmdir may legitimately fail. This behavior follows the IMAP spec. */ * Consequently, the rmdir may legitimately fail. This behavior follows the IMAP spec. */
if (rmdir( gctx->path ) && errno != ENOENT && errno != ENOTEMPTY) { if (rmdir( ctx->path ) && errno != ENOENT && errno != ENOTEMPTY) {
sys_error( "Maildir warning: cannot remove '%s'", gctx->path ); sys_error( "Maildir warning: cannot remove '%s'", ctx->path );
return DRV_BOX_BAD; return DRV_BOX_BAD;
} }
return DRV_OK; return DRV_OK;
@ -1487,7 +1499,7 @@ maildir_fetch_msg( store_t *gctx, message_t *gmsg, msg_data_t *data,
char buf[_POSIX_PATH_MAX]; char buf[_POSIX_PATH_MAX];
for (;;) { for (;;) {
nfsnprintf( buf, sizeof(buf), "%s/%s/%s", gctx->path, subdirs[gmsg->status & M_RECENT], msg->base ); nfsnprintf( buf, sizeof(buf), "%s/%s/%s", ctx->path, subdirs[gmsg->status & M_RECENT], msg->base );
if ((fd = open( buf, O_RDONLY )) >= 0) if ((fd = open( buf, O_RDONLY )) >= 0)
break; break;
if ((ret = maildir_again( ctx, msg, "Cannot open %s", buf, 0 )) != DRV_OK) { if ((ret = maildir_again( ctx, msg, "Cannot open %s", buf, 0 )) != DRV_OK) {
@ -1555,7 +1567,7 @@ maildir_store_msg( store_t *gctx, msg_data_t *data, int to_trash,
} }
nfsnprintf( base + bl, sizeof(base) - bl, ",U=%d", uid ); nfsnprintf( base + bl, sizeof(base) - bl, ",U=%d", uid );
} }
box = gctx->path; box = ctx->path;
} else { } else {
uid = 0; uid = 0;
box = ctx->trash; box = ctx->trash;
@ -1640,8 +1652,8 @@ maildir_set_msg_flags( store_t *gctx, message_t *gmsg, int uid ATTR_UNUSED, int
int j, ret, ol, fl, bbl, bl, tl; int j, ret, ol, fl, bbl, bl, tl;
char buf[_POSIX_PATH_MAX], nbuf[_POSIX_PATH_MAX]; char buf[_POSIX_PATH_MAX], nbuf[_POSIX_PATH_MAX];
bbl = nfsnprintf( buf, sizeof(buf), "%s/", gctx->path ); bbl = nfsnprintf( buf, sizeof(buf), "%s/", ctx->path );
memcpy( nbuf, gctx->path, bbl - 1 ); memcpy( nbuf, ctx->path, bbl - 1 );
memcpy( nbuf + bbl - 1, "/cur/", 5 ); memcpy( nbuf + bbl - 1, "/cur/", 5 );
for (;;) { for (;;) {
bl = bbl + nfsnprintf( buf + bbl, sizeof(buf) - bbl, "%s/", subdirs[gmsg->status & M_RECENT] ); bl = bbl + nfsnprintf( buf + bbl, sizeof(buf) - bbl, "%s/", subdirs[gmsg->status & M_RECENT] );
@ -1715,7 +1727,7 @@ maildir_trash_msg( store_t *gctx, message_t *gmsg,
char buf[_POSIX_PATH_MAX], nbuf[_POSIX_PATH_MAX]; char buf[_POSIX_PATH_MAX], nbuf[_POSIX_PATH_MAX];
for (;;) { for (;;) {
nfsnprintf( buf, sizeof(buf), "%s/%s/%s", gctx->path, subdirs[gmsg->status & M_RECENT], msg->base ); nfsnprintf( buf, sizeof(buf), "%s/%s/%s", ctx->path, subdirs[gmsg->status & M_RECENT], msg->base );
s = strstr( msg->base, ((maildir_store_conf_t *)gctx->conf)->info_prefix ); s = strstr( msg->base, ((maildir_store_conf_t *)gctx->conf)->info_prefix );
nfsnprintf( nbuf, sizeof(nbuf), "%s/%s/%ld.%d_%d.%s%s", ctx->trash, nfsnprintf( nbuf, sizeof(nbuf), "%s/%s/%ld.%d_%d.%s%s", ctx->trash,
subdirs[gmsg->status & M_RECENT], (long)time( 0 ), Pid, ++MaildirCount, Hostname, s ? s : "" ); subdirs[gmsg->status & M_RECENT], (long)time( 0 ), Pid, ++MaildirCount, Hostname, s ? s : "" );
@ -1764,7 +1776,7 @@ maildir_close_box( store_t *gctx,
for (;;) { for (;;) {
retry = 0; retry = 0;
basel = nfsnprintf( buf, sizeof(buf), "%s/", gctx->path ); basel = nfsnprintf( buf, sizeof(buf), "%s/", ctx->path );
for (msg = gctx->msgs; msg; msg = msg->next) for (msg = gctx->msgs; msg; msg = msg->next)
if (!(msg->status & M_DEAD) && (msg->flags & F_DELETED)) { if (!(msg->status & M_DEAD) && (msg->flags & F_DELETED)) {
nfsnprintf( buf + basel, sizeof(buf) - basel, "%s/%s", subdirs[msg->status & M_RECENT], ((maildir_message_t *)msg)->base ); nfsnprintf( buf + basel, sizeof(buf) - basel, "%s/%s", subdirs[msg->status & M_RECENT], ((maildir_message_t *)msg)->base );
@ -1895,6 +1907,7 @@ struct driver maildir_driver = {
maildir_free_store, /* _cancel_, but it's the same */ maildir_free_store, /* _cancel_, but it's the same */
maildir_list_store, maildir_list_store,
maildir_select_box, maildir_select_box,
maildir_get_box_path,
maildir_create_box, maildir_create_box,
maildir_open_box, maildir_open_box,
maildir_confirm_box_empty, maildir_confirm_box_empty,

View File

@ -577,11 +577,12 @@ prepare_state( sync_vars_t *svars )
chan = svars->chan; chan = svars->chan;
if (!strcmp( chan->sync_state ? chan->sync_state : global_conf.sync_state, "*" )) { if (!strcmp( chan->sync_state ? chan->sync_state : global_conf.sync_state, "*" )) {
if (!svars->ctx[S]->path) { const char *path = svars->drv[S]->get_box_path( svars->ctx[S] );
if (!path) {
error( "Error: store '%s' does not support in-box sync state\n", chan->stores[S]->name ); error( "Error: store '%s' does not support in-box sync state\n", chan->stores[S]->name );
return 0; return 0;
} }
nfasprintf( &svars->dname, "%s/." EXE "state", svars->ctx[S]->path ); nfasprintf( &svars->dname, "%s/." EXE "state", path );
} else { } else {
csname = clean_strdup( svars->box_name[S] ); csname = clean_strdup( svars->box_name[S] );
if (chan->sync_state) if (chan->sync_state)