commit 5d5e07eb63b37dba7c37715c44dcbb4518af5b9b
parent d5a5da94755877fe055b0b5d540195860ef5814d
Author: Oswald Buddenhagen <ossi@users.sf.net>
Date: Wed, 18 May 2022 22:40:25 +0200
add --list-stores mode
this is useful for verifying the store configuration, and finding the
right mailbox names.
REFMAIL: YaZC3XUTWjyfjgn+@ugly
Diffstat:
9 files changed, 216 insertions(+), 5 deletions(-)
diff --git 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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -0,0 +1,188 @@
+// SPDX-FileCopyrightText: 2022 Oswald Buddenhagen <ossi@users.sf.net>
+// 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
@@ -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
@@ -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