From 5d5e07eb63b37dba7c37715c44dcbb4518af5b9b Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Wed, 18 May 2022 22:40:25 +0200 Subject: [PATCH] add --list-stores mode this is useful for verifying the store configuration, and finding the right mailbox names. REFMAIL: YaZC3XUTWjyfjgn+@ugly --- NEWS | 2 + src/Makefile.am | 2 +- src/config.c | 2 - src/driver.c | 2 + src/driver.h | 2 + src/main.c | 13 +++- src/main_list.c | 188 ++++++++++++++++++++++++++++++++++++++++++++++++ src/main_p.h | 1 + src/mbsync.1 | 9 +++ 9 files changed, 216 insertions(+), 5 deletions(-) create mode 100644 src/main_list.c diff --git a/NEWS b/NEWS index aa53a19..27eb2c0 100644 --- a/NEWS +++ b/NEWS @@ -6,6 +6,8 @@ The old locations remain supported. The reference point for relative local paths in the configuration file is now the file's containing directory. +The unfiltered list of mailboxes in each Store can be printed now. + [1.4.0] The 'isync' compatibility wrapper was removed. diff --git a/src/Makefile.am b/src/Makefile.am index e756044..f241db2 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -8,7 +8,7 @@ mbsync_SOURCES = \ drv_imap.c \ drv_maildir.c \ sync.c sync_state.c \ - main.c main_sync.c + main.c main_sync.c main_list.c noinst_HEADERS = \ common.h config.h socket.h \ driver.h \ diff --git a/src/config.c b/src/config.c index 880f027..f932920 100644 --- a/src/config.c +++ b/src/config.c @@ -20,8 +20,6 @@ char FieldDelimiter = ';'; char FieldDelimiter = ':'; #endif -static store_conf_t *stores; - char * expand_strdup( const char *s, const conffile_t *cfile ) { diff --git a/src/driver.c b/src/driver.c index f5f73ba..05bbb9b 100644 --- a/src/driver.c +++ b/src/driver.c @@ -7,6 +7,8 @@ #include "driver.h" +store_conf_t *stores; + driver_t *drivers[N_DRIVERS] = { &maildir_driver, &imap_driver }; void diff --git a/src/driver.h b/src/driver.h index d7c4e3d..e810bf1 100644 --- a/src/driver.h +++ b/src/driver.h @@ -31,6 +31,8 @@ typedef struct store_conf { STORE_CONF } store_conf_t; +extern store_conf_t *stores; + /* For message->flags */ // Keep the MESSAGE_FLAGS in sync (grep that)! /* The order is according to alphabetical maildir flag sort */ diff --git a/src/main.c b/src/main.c index 010397e..0196db3 100644 --- a/src/main.c +++ b/src/main.c @@ -33,6 +33,7 @@ PACKAGE " " VERSION " - mailbox synchronizer\n" " " EXE " [flags] {{channel[:box,...]|group} ...|-a}\n" " -a, --all operate on all defined channels\n" " -l, --list list mailboxes instead of syncing them\n" +" -ls, --list-stores raw listing of stores' mailboxes\n" " -n, --new propagate new messages\n" " -d, --delete propagate message deletions\n" " -f, --flags propagate message flag changes\n" @@ -173,6 +174,8 @@ main( int argc, char **argv ) mvars->all = 1; } else if (!strcmp( opt, "list" )) { mvars->list = 1; + } else if (!strcmp( opt, "list-stores" )) { + mvars->list_stores = 1; } else if (!strcmp( opt, "help" )) { usage( 0 ); } else if (!strcmp( opt, "version" )) { @@ -295,7 +298,10 @@ main( int argc, char **argv ) mvars->all = 1; break; case 'l': - mvars->list = 1; + if (*ochar == 's') + mvars->list_stores = 1, ochar++; + else + mvars->list = 1; break; case 'c': if (oind >= argc) { @@ -468,6 +474,9 @@ main( int argc, char **argv ) if (load_config( config )) return 1; - sync_chans( mvars, argv + oind ); + if (mvars->list_stores) + list_stores( mvars, argv + oind ); + else + sync_chans( mvars, argv + oind ); return mvars->ret; } diff --git a/src/main_list.c b/src/main_list.c new file mode 100644 index 0000000..adda4b9 --- /dev/null +++ b/src/main_list.c @@ -0,0 +1,188 @@ +// SPDX-FileCopyrightText: 2022 Oswald Buddenhagen +// SPDX-License-Identifier: GPL-2.0-or-later WITH LicenseRef-isync-GPL-exception +// +// mbsync - mailbox synchronizer +// + +#include "main_p.h" + +typedef struct store_ent { + struct store_ent *next; + store_conf_t *conf; +} store_ent_t; + +typedef struct { + core_vars_t *cvars; + store_conf_t *store; + driver_t *drv; + store_t *ctx; + store_ent_t *storeptr; + int cben, done; +} list_vars_t; + +static store_ent_t * +add_store( store_ent_t ***storeapp, store_conf_t *store ) +{ + store_ent_t *se = nfzalloc( sizeof(*se) ); + se->conf = store; + **storeapp = se; + *storeapp = &se->next; + return se; +} + +static void do_list_stores( list_vars_t *lvars ); +static void list_next_store( list_vars_t *lvars ); + +void +list_stores( core_vars_t *cvars, char **argv ) +{ + list_vars_t lvars[1]; + store_ent_t *strs = NULL, **strapp = &strs; + store_conf_t *store; + + memset( lvars, 0, sizeof(*lvars) ); + lvars->cvars = cvars; + + if (!stores) { + fputs( "No stores defined.\n", stderr ); + cvars->ret = 1; + return; + } + + if (!*argv) { // Implicit --all + for (store = stores; store; store = store->next) + add_store( &strapp, store ); + } else { + for (; *argv; argv++) { + for (store = stores; store; store = store->next) { + if (!strcmp( store->name, *argv )) { + add_store( &strapp, store ); + goto gotstr; + } + } + error( "No store named '%s' defined.\n", *argv ); + cvars->ret = 1; + gotstr: ; + } + } + if (cvars->ret) + return; + lvars->storeptr = strs; + + do_list_stores( lvars ); + main_loop(); +} + +static void +list_store_bad( void *aux ) +{ + list_vars_t *lvars = (list_vars_t *)aux; + + lvars->drv->cancel_store( lvars->ctx ); + lvars->cvars->ret = 1; + list_next_store( lvars ); +} + +static void +advance_store( list_vars_t *lvars ) +{ + store_ent_t *nstr = lvars->storeptr->next; + free( lvars->storeptr ); + lvars->storeptr = nstr; +} + +static void list_store_connected( int sts, void *aux ); + +static void +do_list_stores( list_vars_t *lvars ) +{ + while (lvars->storeptr) { + lvars->store = lvars->storeptr->conf; + lvars->drv = lvars->store->driver; + int st = lvars->drv->get_fail_state( lvars->store ); + if (st != FAIL_TEMP) { + info( "Skipping %sfailed store %s.\n", + (st == FAIL_WAIT) ? "temporarily " : "", lvars->store->name ); + lvars->cvars->ret = 1; + goto next; + } + + uint dcaps = lvars->drv->get_caps( NULL ); + store_t *ctx = lvars->drv->alloc_store( lvars->store, "" ); + if ((DFlags & DEBUG_DRV) || ((DFlags & FORCEASYNC) && !(dcaps & DRV_ASYNC))) { + lvars->drv = &proxy_driver; + ctx = proxy_alloc_store( ctx, "" ); + } + lvars->ctx = ctx; + lvars->drv->set_bad_callback( ctx, list_store_bad, lvars ); + info( "Opening store %s...\n", lvars->store->name ); + lvars->cben = lvars->done = 0; + lvars->drv->connect_store( lvars->ctx, list_store_connected, lvars ); + if (!lvars->done) { + lvars->cben = 1; + return; + } + + next: + advance_store( lvars ); + } + cleanup_drivers(); +} + +static void +list_next_store( list_vars_t *lvars ) +{ + if (lvars->cben) { + advance_store( lvars ); + do_list_stores( lvars ); + } +} + +static void +list_done_store( list_vars_t *lvars ) +{ + lvars->done = 1; + lvars->drv->free_store( lvars->ctx ); + list_next_store( lvars ); +} + +static void list_store_listed( int sts, string_list_t *boxes, void *aux ); + +static void +list_store_connected( int sts, void *aux ) +{ + list_vars_t *lvars = (list_vars_t *)aux; + + switch (sts) { + case DRV_CANCELED: + return; + case DRV_OK: + lvars->drv->list_store( lvars->ctx, LIST_INBOX | LIST_PATH_MAYBE, list_store_listed, lvars ); + break; + default: + lvars->cvars->ret = 1; + list_done_store( lvars ); + break; + } +} + +static void +list_store_listed( int sts, string_list_t *boxes, void *aux ) +{ + list_vars_t *lvars = (list_vars_t *)aux; + string_list_t *box; + + switch (sts) { + case DRV_CANCELED: + return; + case DRV_OK: + printf( "===== %s:\n", lvars->ctx->conf->name ); + for (box = boxes; box; box = box->next) + puts( box->string ); + break; + default: + lvars->cvars->ret = 1; + break; + } + list_done_store( lvars ); +} diff --git a/src/main_p.h b/src/main_p.h index 317367a..75f619c 100644 --- a/src/main_p.h +++ b/src/main_p.h @@ -20,5 +20,6 @@ typedef struct { } core_vars_t; void sync_chans( core_vars_t *cvars, char **argv ); +void list_stores( core_vars_t *cvars, char **argv ); #endif diff --git a/src/mbsync.1 b/src/mbsync.1 index 403b2ce..ee54129 100644 --- a/src/mbsync.1 +++ b/src/mbsync.1 @@ -11,6 +11,8 @@ mbsync - synchronize IMAP4 and Maildir mailboxes . .SH SYNOPSIS \fBmbsync\fR [\fIoptions\fR ...] {{\fIchannel\fR[\fB:\fIbox\fR[{\fB,\fR|\fB\\n\fR}...]]|\fIgroup\fR} ...|\fB-a\fR} +.br +\fBmbsync\fR --list-stores [\fIoptions\fR ...] [\fIstore\fR} ...] . .SH DESCRIPTION \fBmbsync\fR is a command line application which synchronizes mailboxes; @@ -43,6 +45,13 @@ command line are ignored. Don't synchronize anything, but list all mailboxes in the selected Channels and exit. .TP +\fB-ls\fR, \fB--list-stores\fR +Don't synchronize anything, but list all mailboxes in the selected Stores +and exit. +If no Stores are specified, all configured ones are listed. +These are raw Store contents, not filtered by any Channel's \fBPatterns\fR. +This option may be used to verify each Store's configuration. +.TP \fB-C\fR[\fBf\fR][\fBn\fR], \fB--create\fR[\fB-far\fR|\fB-near\fR] Override any \fBCreate\fR options from the config file. See below. .TP