introduce ability to flatten the hierarchy of Stores
This commit is contained in:
parent
2585dd3324
commit
dfd7516b9a
13
src/config.c
13
src/config.c
|
@ -430,7 +430,18 @@ parse_generic_store( store_conf_t *store, conffile_t *cfg, int *err )
|
||||||
store->max_size = parse_size( cfg );
|
store->max_size = parse_size( cfg );
|
||||||
else if (!strcasecmp( "MapInbox", cfg->cmd ))
|
else if (!strcasecmp( "MapInbox", cfg->cmd ))
|
||||||
store->map_inbox = nfstrdup( cfg->val );
|
store->map_inbox = nfstrdup( cfg->val );
|
||||||
else {
|
else if (!strcasecmp( "Flatten", cfg->cmd )) {
|
||||||
|
int sl = strlen( cfg->val );
|
||||||
|
if (sl != 1) {
|
||||||
|
error( "%s:%d: malformed flattened hierarchy delimiter\n", cfg->file, cfg->line );
|
||||||
|
*err = 1;
|
||||||
|
} else if (cfg->val[0] == '/') {
|
||||||
|
error( "%s:%d: flattened hierarchy delimiter cannot be the canonical delimiter '/'\n", cfg->file, cfg->line );
|
||||||
|
*err = 1;
|
||||||
|
} else {
|
||||||
|
store->flat_delim = cfg->val[0];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
error( "%s:%d: unknown keyword '%s'\n", cfg->file, cfg->line, cfg->cmd );
|
error( "%s:%d: unknown keyword '%s'\n", cfg->file, cfg->line, cfg->cmd );
|
||||||
*err = 1;
|
*err = 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -142,6 +142,7 @@ typedef struct store_conf {
|
||||||
const char *trash;
|
const char *trash;
|
||||||
unsigned max_size; /* off_t is overkill */
|
unsigned max_size; /* off_t is overkill */
|
||||||
unsigned trash_remote_new:1, trash_only_new:1;
|
unsigned trash_remote_new:1, trash_only_new:1;
|
||||||
|
char flat_delim;
|
||||||
} store_conf_t;
|
} store_conf_t;
|
||||||
|
|
||||||
typedef struct string_list {
|
typedef struct string_list {
|
||||||
|
@ -216,7 +217,8 @@ typedef struct store {
|
||||||
void *bad_callback_aux;
|
void *bad_callback_aux;
|
||||||
|
|
||||||
/* currently open mailbox */
|
/* currently open mailbox */
|
||||||
const char *name; /* foreign! maybe preset? */
|
const char *orig_name; /* foreign! maybe preset? */
|
||||||
|
char *name; /* foreign! maybe preset? */
|
||||||
char *path; /* own */
|
char *path; /* own */
|
||||||
message_t *msgs; /* own */
|
message_t *msgs; /* own */
|
||||||
int uidvalidity;
|
int uidvalidity;
|
||||||
|
|
|
@ -718,12 +718,21 @@ static void
|
||||||
store_listed( int sts, void *aux )
|
store_listed( int sts, void *aux )
|
||||||
{
|
{
|
||||||
MVARS(aux)
|
MVARS(aux)
|
||||||
|
string_list_t *box;
|
||||||
|
|
||||||
switch (sts) {
|
switch (sts) {
|
||||||
case DRV_CANCELED:
|
case DRV_CANCELED:
|
||||||
return;
|
return;
|
||||||
case DRV_OK:
|
case DRV_OK:
|
||||||
mvars->ctx[t]->listed = 1;
|
mvars->ctx[t]->listed = 1;
|
||||||
|
if (mvars->ctx[t]->conf->flat_delim) {
|
||||||
|
for (box = mvars->ctx[t]->boxes; box; box = box->next) {
|
||||||
|
if (map_name( box->string, mvars->ctx[t]->conf->flat_delim, '/' ) < 0) {
|
||||||
|
error( "Error: flattened mailbox name '%s' contains canonical hierarchy delimiter\n", box->string );
|
||||||
|
mvars->ret = mvars->skip = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if (mvars->ctx[t]->conf->map_inbox)
|
if (mvars->ctx[t]->conf->map_inbox)
|
||||||
add_string_list( &mvars->ctx[t]->boxes, mvars->ctx[t]->conf->map_inbox );
|
add_string_list( &mvars->ctx[t]->boxes, mvars->ctx[t]->conf->map_inbox );
|
||||||
break;
|
break;
|
||||||
|
|
12
src/mbsync.1
12
src/mbsync.1
|
@ -150,6 +150,15 @@ Channels section.
|
||||||
This virtual mailbox does not support subfolders.
|
This virtual mailbox does not support subfolders.
|
||||||
..
|
..
|
||||||
.TP
|
.TP
|
||||||
|
\fBFlatten\fR \fIdelim\fR
|
||||||
|
Flatten the hierarchy within this Store by substituting the canonical
|
||||||
|
hierarchy delimiter \fB/\fR with \fIdelim\fR.
|
||||||
|
This can be useful when the MUA used to access the Store provides
|
||||||
|
suboptimal handling of hierarchical mailboxes, as is the case with
|
||||||
|
\fBMutt\fR.
|
||||||
|
A common choice for the delimiter is \fB.\fR.
|
||||||
|
..
|
||||||
|
.TP
|
||||||
\fBTrash\fR \fImailbox\fR
|
\fBTrash\fR \fImailbox\fR
|
||||||
Specifies a mailbox (relative to \fBPath\fR) to copy deleted messages to
|
Specifies a mailbox (relative to \fBPath\fR) to copy deleted messages to
|
||||||
prior to expunging. See \fBINHERENT PROBLEMS\fR below.
|
prior to expunging. See \fBINHERENT PROBLEMS\fR below.
|
||||||
|
@ -318,6 +327,9 @@ This option is meaningless if a \fBPath\fR was specified.
|
||||||
\fBPathDelimiter\fR \fIdelim\fR
|
\fBPathDelimiter\fR \fIdelim\fR
|
||||||
Specify the server's hierarchy delimiter character.
|
Specify the server's hierarchy delimiter character.
|
||||||
(Default: taken from the server's first "personal" NAMESPACE)
|
(Default: taken from the server's first "personal" NAMESPACE)
|
||||||
|
.br
|
||||||
|
Do \fBNOT\fR abuse this to re-interpret the hierarchy.
|
||||||
|
Use \fBFlatten\fR instead.
|
||||||
..
|
..
|
||||||
.SS Channels
|
.SS Channels
|
||||||
.TP
|
.TP
|
||||||
|
|
22
src/sync.c
22
src/sync.c
|
@ -467,6 +467,7 @@ stats( sync_vars_t *svars )
|
||||||
static void sync_bail( sync_vars_t *svars );
|
static void sync_bail( sync_vars_t *svars );
|
||||||
static void sync_bail1( sync_vars_t *svars );
|
static void sync_bail1( sync_vars_t *svars );
|
||||||
static void sync_bail2( sync_vars_t *svars );
|
static void sync_bail2( sync_vars_t *svars );
|
||||||
|
static void sync_bail3( sync_vars_t *svars );
|
||||||
static void cancel_done( void *aux );
|
static void cancel_done( void *aux );
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -605,9 +606,16 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan,
|
||||||
svars->srecadd = &svars->srecs;
|
svars->srecadd = &svars->srecs;
|
||||||
|
|
||||||
for (t = 0; t < 2; t++) {
|
for (t = 0; t < 2; t++) {
|
||||||
ctx[t]->name =
|
ctx[t]->orig_name =
|
||||||
(!names[t] || (ctx[t]->conf->map_inbox && !strcmp( ctx[t]->conf->map_inbox, names[t] ))) ?
|
(!names[t] || (ctx[t]->conf->map_inbox && !strcmp( ctx[t]->conf->map_inbox, names[t] ))) ?
|
||||||
"INBOX" : names[t];
|
"INBOX" : names[t];
|
||||||
|
ctx[t]->name = nfstrdup( ctx[t]->orig_name );
|
||||||
|
if (ctx[t]->conf->flat_delim && map_name( ctx[t]->name, '/', ctx[t]->conf->flat_delim ) < 0) {
|
||||||
|
error( "Error: canonical mailbox name '%s' contains flattened hierarchy delimiter\n", ctx[t]->name );
|
||||||
|
svars->ret = SYNC_FAIL;
|
||||||
|
sync_bail3( svars );
|
||||||
|
return;
|
||||||
|
}
|
||||||
ctx[t]->uidvalidity = -1;
|
ctx[t]->uidvalidity = -1;
|
||||||
set_bad_callback( ctx[t], store_bad, AUX );
|
set_bad_callback( ctx[t], store_bad, AUX );
|
||||||
svars->drv[t] = ctx[t]->conf->driver;
|
svars->drv[t] = ctx[t]->conf->driver;
|
||||||
|
@ -615,7 +623,7 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan,
|
||||||
/* Both boxes must be fully set up at this point, so that error exit paths
|
/* Both boxes must be fully set up at this point, so that error exit paths
|
||||||
* don't run into uninitialized variables. */
|
* don't run into uninitialized variables. */
|
||||||
for (t = 0; t < 2; t++) {
|
for (t = 0; t < 2; t++) {
|
||||||
info( "Selecting %s %s...\n", str_ms[t], ctx[t]->name );
|
info( "Selecting %s %s...\n", str_ms[t], ctx[t]->orig_name );
|
||||||
DRIVER_CALL(select( ctx[t], (chan->ops[t] & OP_CREATE) != 0, box_selected, AUX ));
|
DRIVER_CALL(select( ctx[t], (chan->ops[t] & OP_CREATE) != 0, box_selected, AUX ));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -696,7 +704,7 @@ box_selected( int sts, void *aux )
|
||||||
}
|
}
|
||||||
if (fcntl( svars->lfd, F_SETLK, &lck )) {
|
if (fcntl( svars->lfd, F_SETLK, &lck )) {
|
||||||
error( "Error: channel :%s:%s-:%s:%s is locked\n",
|
error( "Error: channel :%s:%s-:%s:%s is locked\n",
|
||||||
chan->stores[M]->name, ctx[M]->name, chan->stores[S]->name, ctx[S]->name );
|
chan->stores[M]->name, ctx[M]->orig_name, chan->stores[S]->name, ctx[S]->orig_name );
|
||||||
svars->ret = SYNC_FAIL;
|
svars->ret = SYNC_FAIL;
|
||||||
sync_bail1( svars );
|
sync_bail1( svars );
|
||||||
return;
|
return;
|
||||||
|
@ -1721,6 +1729,14 @@ sync_bail2( sync_vars_t *svars )
|
||||||
free( svars->jname );
|
free( svars->jname );
|
||||||
free( svars->dname );
|
free( svars->dname );
|
||||||
flushn();
|
flushn();
|
||||||
|
sync_bail3( svars );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
sync_bail3( sync_vars_t *svars )
|
||||||
|
{
|
||||||
|
free( svars->ctx[M]->name );
|
||||||
|
free( svars->ctx[S]->name );
|
||||||
sync_deref( svars );
|
sync_deref( svars );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user