add --list-stores mode

this is useful for verifying the store configuration, and finding the
right mailbox names.

REFMAIL: YaZC3XUTWjyfjgn+@ugly
This commit is contained in:
Oswald Buddenhagen 2022-05-18 22:40:25 +02:00
parent d5a5da9475
commit 5d5e07eb63
9 changed files with 216 additions and 5 deletions

2
NEWS
View File

@ -6,6 +6,8 @@ The old locations remain supported.
The reference point for relative local paths in the configuration file The reference point for relative local paths in the configuration file
is now the file's containing directory. is now the file's containing directory.
The unfiltered list of mailboxes in each Store can be printed now.
[1.4.0] [1.4.0]
The 'isync' compatibility wrapper was removed. The 'isync' compatibility wrapper was removed.

View File

@ -8,7 +8,7 @@ mbsync_SOURCES = \
drv_imap.c \ drv_imap.c \
drv_maildir.c \ drv_maildir.c \
sync.c sync_state.c \ sync.c sync_state.c \
main.c main_sync.c main.c main_sync.c main_list.c
noinst_HEADERS = \ noinst_HEADERS = \
common.h config.h socket.h \ common.h config.h socket.h \
driver.h \ driver.h \

View File

@ -20,8 +20,6 @@ char FieldDelimiter = ';';
char FieldDelimiter = ':'; char FieldDelimiter = ':';
#endif #endif
static store_conf_t *stores;
char * char *
expand_strdup( const char *s, const conffile_t *cfile ) expand_strdup( const char *s, const conffile_t *cfile )
{ {

View File

@ -7,6 +7,8 @@
#include "driver.h" #include "driver.h"
store_conf_t *stores;
driver_t *drivers[N_DRIVERS] = { &maildir_driver, &imap_driver }; driver_t *drivers[N_DRIVERS] = { &maildir_driver, &imap_driver };
void void

View File

@ -31,6 +31,8 @@ typedef struct store_conf {
STORE_CONF STORE_CONF
} store_conf_t; } store_conf_t;
extern store_conf_t *stores;
/* For message->flags */ /* For message->flags */
// Keep the MESSAGE_FLAGS in sync (grep that)! // Keep the MESSAGE_FLAGS in sync (grep that)!
/* The order is according to alphabetical maildir flag sort */ /* The order is according to alphabetical maildir flag sort */

View File

@ -33,6 +33,7 @@ PACKAGE " " VERSION " - mailbox synchronizer\n"
" " EXE " [flags] {{channel[:box,...]|group} ...|-a}\n" " " EXE " [flags] {{channel[:box,...]|group} ...|-a}\n"
" -a, --all operate on all defined channels\n" " -a, --all operate on all defined channels\n"
" -l, --list list mailboxes instead of syncing them\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" " -n, --new propagate new messages\n"
" -d, --delete propagate message deletions\n" " -d, --delete propagate message deletions\n"
" -f, --flags propagate message flag changes\n" " -f, --flags propagate message flag changes\n"
@ -173,6 +174,8 @@ main( int argc, char **argv )
mvars->all = 1; mvars->all = 1;
} else if (!strcmp( opt, "list" )) { } else if (!strcmp( opt, "list" )) {
mvars->list = 1; mvars->list = 1;
} else if (!strcmp( opt, "list-stores" )) {
mvars->list_stores = 1;
} else if (!strcmp( opt, "help" )) { } else if (!strcmp( opt, "help" )) {
usage( 0 ); usage( 0 );
} else if (!strcmp( opt, "version" )) { } else if (!strcmp( opt, "version" )) {
@ -295,6 +298,9 @@ main( int argc, char **argv )
mvars->all = 1; mvars->all = 1;
break; break;
case 'l': case 'l':
if (*ochar == 's')
mvars->list_stores = 1, ochar++;
else
mvars->list = 1; mvars->list = 1;
break; break;
case 'c': case 'c':
@ -468,6 +474,9 @@ main( int argc, char **argv )
if (load_config( config )) if (load_config( config ))
return 1; return 1;
if (mvars->list_stores)
list_stores( mvars, argv + oind );
else
sync_chans( mvars, argv + oind ); sync_chans( mvars, argv + oind );
return mvars->ret; return mvars->ret;
} }

188
src/main_list.c Normal file
View File

@ -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 );
}

View File

@ -20,5 +20,6 @@ typedef struct {
} core_vars_t; } core_vars_t;
void sync_chans( core_vars_t *cvars, char **argv ); void sync_chans( core_vars_t *cvars, char **argv );
void list_stores( core_vars_t *cvars, char **argv );
#endif #endif

View File

@ -11,6 +11,8 @@ mbsync - synchronize IMAP4 and Maildir mailboxes
. .
.SH SYNOPSIS .SH SYNOPSIS
\fBmbsync\fR [\fIoptions\fR ...] {{\fIchannel\fR[\fB:\fIbox\fR[{\fB,\fR|\fB\\n\fR}...]]|\fIgroup\fR} ...|\fB-a\fR} \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 .SH DESCRIPTION
\fBmbsync\fR is a command line application which synchronizes mailboxes; \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 Don't synchronize anything, but list all mailboxes in the selected Channels
and exit. and exit.
.TP .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] \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. Override any \fBCreate\fR options from the config file. See below.
.TP .TP