From 83ebe9022d88d9493d7ee5739f4503af1e28448b Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Fri, 24 Mar 2017 14:06:19 +0100 Subject: [PATCH] introduce get_box_path() driver callback ... and make 'path' private to the maildir driver. --- src/driver.h | 7 +++--- src/drv_imap.c | 7 ++++++ src/drv_maildir.c | 57 +++++++++++++++++++++++++++++------------------ src/sync.c | 5 +++-- 4 files changed, 49 insertions(+), 27 deletions(-) diff --git a/src/driver.h b/src/driver.h index 43eb147..24f137d 100644 --- a/src/driver.h +++ b/src/driver.h @@ -90,7 +90,6 @@ typedef struct store { char listed; /* was _list already run? */ /* currently open mailbox */ - char *path; /* own */ message_t *msgs; /* own */ int uidvalidity; int uidnext; /* from SELECT responses */ @@ -167,10 +166,12 @@ struct driver { void (*list_store)( store_t *ctx, int flags, void (*cb)( int sts, void *aux ), void *aux ); - /* 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. */ + /* Invoked before open_box(), this informs the driver which box is to be opened. */ 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. */ void (*create_box)( store_t *ctx, void (*cb)( int sts, void *aux ), void *aux ); diff --git a/src/drv_imap.c b/src/drv_imap.c index 5afddaf..8eb3d31 100644 --- a/src/drv_imap.c +++ b/src/drv_imap.c @@ -2306,6 +2306,12 @@ imap_select_box( store_t *gctx, const char *name ) 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_p3( imap_store_t *, imap_cmd_t *, int ); @@ -3212,6 +3218,7 @@ struct driver imap_driver = { imap_cancel_store, imap_list_store, imap_select_box, + imap_get_box_path, imap_create_box, imap_open_box, imap_confirm_box_empty, diff --git a/src/drv_maildir.c b/src/drv_maildir.c index a5bdf3f..d888d2a 100644 --- a/src/drv_maildir.c +++ b/src/drv_maildir.c @@ -72,6 +72,7 @@ typedef struct { int uvfd, uvok, nuid, is_inbox, fresh[3]; int minuid, maxuid, newuid, seenuid; int_array_t excs; + char *path; /* own */ char *trash; #ifdef USE_DB DB *db; @@ -265,7 +266,7 @@ maildir_cleanup( store_t *gctx ) ctx->db->close( ctx->db, 0 ); free( ctx->usedb ); #endif /* USE_DB */ - free( gctx->path ); + free( ctx->path ); free( ctx->excs.data ); if (ctx->uvfd >= 0) close( ctx->uvfd ); @@ -920,7 +921,7 @@ maildir_scan( maildir_store_t *ctx, msg_t_array_alloc_t *msglist ) } } #endif /* USE_DB */ - bl = nfsnprintf( buf, sizeof(buf) - 4, "%s/", ctx->gen.path ); + bl = nfsnprintf( buf, sizeof(buf) - 4, "%s/", ctx->path ); restat: now = time( 0 ); 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; if (starts_with( name, -1, "INBOX", 5 ) && (!name[5] || name[5] == '/')) { if (!name[5]) { - gctx->path = nfstrdup( conf->inbox ); + ctx->path = nfstrdup( conf->inbox ); ctx->is_inbox = 1; } else { - gctx->path = maildir_join_path( conf, 1, name + 5 ); + ctx->path = maildir_join_path( conf, 1, name + 5 ); ctx->is_inbox = 0; } } else { - if (!(gctx->path = maildir_join_path( conf, 0, name ))) + if (!(ctx->path = maildir_join_path( conf, 0, name ))) return DRV_CANCELED; 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 @@ -1258,10 +1265,10 @@ maildir_open_box( store_t *gctx, int ret; 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; - nfsnprintf( uvpath, sizeof(uvpath), "%s/.uidvalidity", gctx->path ); + nfsnprintf( uvpath, sizeof(uvpath), "%s/.uidvalidity", ctx->path ); #ifndef USE_DB if ((ctx->uvfd = open( uvpath, O_RDWR|O_CREAT, 0600 )) < 0) { sys_error( "Maildir error: cannot write %s", uvpath ); @@ -1271,13 +1278,13 @@ maildir_open_box( store_t *gctx, #else ctx->usedb = 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 (((maildir_store_conf_t *)gctx->conf)->alt_map) { if ((ctx->uvfd = open( uvpath, O_RDWR|O_CREAT, 0600 )) >= 0) goto dbok; } 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) goto fnok; } @@ -1301,7 +1308,9 @@ static void maildir_create_box( store_t *gctx, 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 @@ -1322,18 +1331,19 @@ static void maildir_delete_box( store_t *gctx, void (*cb)( int sts, void *aux ), void *aux ) { + maildir_store_t *ctx = (maildir_store_t *)gctx; int i, bl, ret = DRV_OK; struct stat st; 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 (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; } } 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; } else if ((ret = maildir_clear_tmp( buf, sizeof(buf), bl )) == DRV_OK) { nfsnprintf( buf + bl, sizeof(buf) - bl, ".uidvalidity" ); @@ -1362,10 +1372,12 @@ maildir_delete_box( store_t *gctx, static int 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". * Consequently, the rmdir may legitimately fail. This behavior follows the IMAP spec. */ - if (rmdir( gctx->path ) && errno != ENOENT && errno != ENOTEMPTY) { - sys_error( "Maildir warning: cannot remove '%s'", gctx->path ); + if (rmdir( ctx->path ) && errno != ENOENT && errno != ENOTEMPTY) { + sys_error( "Maildir warning: cannot remove '%s'", ctx->path ); return DRV_BOX_BAD; } 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]; 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) break; 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 ); } - box = gctx->path; + box = ctx->path; } else { uid = 0; 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; char buf[_POSIX_PATH_MAX], nbuf[_POSIX_PATH_MAX]; - bbl = nfsnprintf( buf, sizeof(buf), "%s/", gctx->path ); - memcpy( nbuf, gctx->path, bbl - 1 ); + bbl = nfsnprintf( buf, sizeof(buf), "%s/", ctx->path ); + memcpy( nbuf, ctx->path, bbl - 1 ); memcpy( nbuf + bbl - 1, "/cur/", 5 ); for (;;) { 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]; 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 ); 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 : "" ); @@ -1764,7 +1776,7 @@ maildir_close_box( store_t *gctx, for (;;) { 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) 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 ); @@ -1895,6 +1907,7 @@ struct driver maildir_driver = { maildir_free_store, /* _cancel_, but it's the same */ maildir_list_store, maildir_select_box, + maildir_get_box_path, maildir_create_box, maildir_open_box, maildir_confirm_box_empty, diff --git a/src/sync.c b/src/sync.c index 340758c..a8d1e33 100644 --- a/src/sync.c +++ b/src/sync.c @@ -577,11 +577,12 @@ prepare_state( sync_vars_t *svars ) chan = svars->chan; 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 ); return 0; } - nfasprintf( &svars->dname, "%s/." EXE "state", svars->ctx[S]->path ); + nfasprintf( &svars->dname, "%s/." EXE "state", path ); } else { csname = clean_strdup( svars->box_name[S] ); if (chan->sync_state)