isync

mailbox synchronization program
git clone https://git.code.sf.net/p/isync/isync
Log | Files | Refs | README | LICENSE

commit 1de3ecd8830e98754721fd3f0267f9890aed2d2a
parent f361738ad20720a56e6d4e2932f5c0f8070f8779
Author: Oswald Buddenhagen <ossi@users.sf.net>
Date:   Sat, 28 Mar 2015 17:51:27 +0100

pre-calculate channel and box lists (as far as possible)

... instead of determining them on the fly, because
- it enables early display of totals (to be used soon)
- it enables re-use of the data (to be used at some point)
- the code is less cryptic

note that we leak the data created in main(), consistently with other
configuration-related data.

Diffstat:
Msrc/main.c | 315++++++++++++++++++++++++++++++++++++++++---------------------------------------
1 file changed, 159 insertions(+), 156 deletions(-)

diff --git a/src/main.c b/src/main.c @@ -234,17 +234,89 @@ typedef struct box_ent { int present[2]; } box_ent_t; +typedef struct chan_ent { + struct chan_ent *next; + channel_conf_t *conf; + box_ent_t *boxes; + char boxlist; +} chan_ent_t; + +static chan_ent_t * +add_channel( chan_ent_t ***chanapp, channel_conf_t *chan, int ops[] ) +{ + chan_ent_t *ce = nfcalloc( sizeof(*ce) ); + ce->conf = chan; + + merge_actions( chan, ops, XOP_HAVE_TYPE, OP_MASK_TYPE, OP_MASK_TYPE ); + merge_actions( chan, ops, XOP_HAVE_CREATE, OP_CREATE, 0 ); + merge_actions( chan, ops, XOP_HAVE_REMOVE, OP_REMOVE, 0 ); + merge_actions( chan, ops, XOP_HAVE_EXPUNGE, OP_EXPUNGE, 0 ); + + **chanapp = ce; + *chanapp = &ce->next; + return ce; +} + +static chan_ent_t * +add_named_channel( chan_ent_t ***chanapp, char *channame, int ops[] ) +{ + channel_conf_t *chan; + chan_ent_t *ce; + box_ent_t *boxes = 0, **mboxapp = &boxes, *mbox; + char *boxp, *nboxp; + int boxl, boxlist = 0; + + if ((boxp = strchr( channame, ':' ))) + *boxp++ = 0; + for (chan = channels; chan; chan = chan->next) + if (!strcmp( chan->name, channame )) + goto gotchan; + error( "No channel or group named '%s' defined.\n", channame ); + return 0; + gotchan: + if (boxp) { + if (!chan->patterns) { + error( "Cannot override mailbox in channel '%s' - no Patterns.\n", channame ); + return 0; + } + boxlist = 1; + do { + nboxp = strpbrk( boxp, ",\n" ); + if (nboxp) { + boxl = nboxp - boxp; + *nboxp++ = 0; + } else { + boxl = strlen( boxp ); + } + mbox = nfmalloc( sizeof(*mbox) ); + if (boxl) + mbox->name = nfstrndup( boxp, boxl ); + else + mbox->name = nfstrndup( "INBOX", 5 ); + mbox->present[M] = mbox->present[S] = BOX_POSSIBLE; + mbox->next = 0; + *mboxapp = mbox; + mboxapp = &mbox->next; + boxp = nboxp; + } while (boxp); + } + + ce = add_channel( chanapp, chan, ops ); + ce->boxes = boxes; + ce->boxlist = boxlist; + return ce; +} + typedef struct { int t[2]; channel_conf_t *chan; driver_t *drv[2]; store_t *ctx[2]; - box_ent_t *boxes; - string_list_t *chanptr; + chan_ent_t *chanptr; + box_ent_t *boxptr; char *names[2]; - char **argv; - int oind, ret, multiple, all, list, ops[2], state[2]; - char done, skip, cben, boxlist; + int ret, multiple, all, list, state[2]; + char done, skip, cben; } main_vars_t; #define AUX &mvars->t[t] @@ -262,9 +334,12 @@ int main( int argc, char **argv ) { main_vars_t mvars[1]; + chan_ent_t *chans = 0, **chanapp = &chans; group_conf_t *group; + channel_conf_t *chan; + string_list_t *channame; char *config = 0, *opt, *ochar; - int cops = 0, op, pseudo = 0; + int oind, cops = 0, op, ops[2] = { 0, 0 }, pseudo = 0; tzset(); gethostname( Hostname, sizeof(Hostname) ); @@ -280,22 +355,22 @@ main( int argc, char **argv ) memset( mvars, 0, sizeof(*mvars) ); mvars->t[1] = 1; - for (mvars->oind = 1, ochar = 0; ; ) { + for (oind = 1, ochar = 0; ; ) { if (!ochar || !*ochar) { - if (mvars->oind >= argc) + if (oind >= argc) break; - if (argv[mvars->oind][0] != '-') + if (argv[oind][0] != '-') break; - if (argv[mvars->oind][1] == '-') { - opt = argv[mvars->oind++] + 2; + if (argv[oind][1] == '-') { + opt = argv[oind++] + 2; if (!*opt) break; if (!strcmp( opt, "config" )) { - if (mvars->oind >= argc) { + if (oind >= argc) { error( "--config requires an argument.\n" ); return 1; } - config = argv[mvars->oind++]; + config = argv[oind++]; } else if (starts_with( opt, -1, "config=", 7 )) config = opt + 7; else if (!strcmp( opt, "all" )) @@ -319,9 +394,9 @@ main( int argc, char **argv ) } else if (!strcmp( opt, "debug" )) DFlags |= DEBUG | QUIET; else if (!strcmp( opt, "pull" )) - cops |= XOP_PULL, mvars->ops[M] |= XOP_HAVE_TYPE; + cops |= XOP_PULL, ops[M] |= XOP_HAVE_TYPE; else if (!strcmp( opt, "push" )) - cops |= XOP_PUSH, mvars->ops[M] |= XOP_HAVE_TYPE; + cops |= XOP_PUSH, ops[M] |= XOP_HAVE_TYPE; else if (starts_with( opt, -1, "create", 6 )) { opt += 6; op = OP_CREATE|XOP_HAVE_CREATE; @@ -329,12 +404,12 @@ main( int argc, char **argv ) if (!*opt) cops |= op; else if (!strcmp( opt, "-master" )) - mvars->ops[M] |= op; + ops[M] |= op; else if (!strcmp( opt, "-slave" )) - mvars->ops[S] |= op; + ops[S] |= op; else goto badopt; - mvars->ops[M] |= op & (XOP_HAVE_CREATE|XOP_HAVE_REMOVE|XOP_HAVE_EXPUNGE); + ops[M] |= op & (XOP_HAVE_CREATE|XOP_HAVE_REMOVE|XOP_HAVE_EXPUNGE); } else if (starts_with( opt, -1, "remove", 6 )) { opt += 6; op = OP_REMOVE|XOP_HAVE_REMOVE; @@ -344,15 +419,15 @@ main( int argc, char **argv ) op = OP_EXPUNGE|XOP_HAVE_EXPUNGE; goto lcop; } else if (!strcmp( opt, "no-expunge" )) - mvars->ops[M] |= XOP_HAVE_EXPUNGE; + ops[M] |= XOP_HAVE_EXPUNGE; else if (!strcmp( opt, "no-create" )) - mvars->ops[M] |= XOP_HAVE_CREATE; + ops[M] |= XOP_HAVE_CREATE; else if (!strcmp( opt, "no-remove" )) - mvars->ops[M] |= XOP_HAVE_REMOVE; + ops[M] |= XOP_HAVE_REMOVE; else if (!strcmp( opt, "full" )) - mvars->ops[M] |= XOP_HAVE_TYPE|XOP_PULL|XOP_PUSH; + ops[M] |= XOP_HAVE_TYPE|XOP_PULL|XOP_PUSH; else if (!strcmp( opt, "noop" )) - mvars->ops[M] |= XOP_HAVE_TYPE; + ops[M] |= XOP_HAVE_TYPE; else if (starts_with( opt, -1, "pull", 4 )) { op = XOP_PULL; lcac: @@ -380,19 +455,19 @@ main( int argc, char **argv ) op |= OP_FLAGS; else { badopt: - error( "Unknown option '%s'\n", argv[mvars->oind - 1] ); + error( "Unknown option '%s'\n", argv[oind - 1] ); return 1; } switch (op & XOP_MASK_DIR) { - case XOP_PULL: mvars->ops[S] |= op & OP_MASK_TYPE; break; - case XOP_PUSH: mvars->ops[M] |= op & OP_MASK_TYPE; break; + case XOP_PULL: ops[S] |= op & OP_MASK_TYPE; break; + case XOP_PUSH: ops[M] |= op & OP_MASK_TYPE; break; default: cops |= op; break; } - mvars->ops[M] |= XOP_HAVE_TYPE; + ops[M] |= XOP_HAVE_TYPE; } continue; } - ochar = argv[mvars->oind++] + 1; + ochar = argv[oind++] + 1; if (!*ochar) { error( "Invalid option '-'\n" ); return 1; @@ -410,24 +485,24 @@ main( int argc, char **argv ) ochar++; pseudo = 1; } - if (mvars->oind >= argc) { + if (oind >= argc) { error( "-c requires an argument.\n" ); return 1; } - config = argv[mvars->oind++]; + config = argv[oind++]; break; case 'C': op = OP_CREATE|XOP_HAVE_CREATE; cop: if (*ochar == 'm') - mvars->ops[M] |= op, ochar++; + ops[M] |= op, ochar++; else if (*ochar == 's') - mvars->ops[S] |= op, ochar++; + ops[S] |= op, ochar++; else if (*ochar == '-') ochar++; else cops |= op; - mvars->ops[M] |= op & (XOP_HAVE_CREATE|XOP_HAVE_REMOVE|XOP_HAVE_EXPUNGE); + ops[M] |= op & (XOP_HAVE_CREATE|XOP_HAVE_REMOVE|XOP_HAVE_EXPUNGE); break; case 'R': op = OP_REMOVE|XOP_HAVE_REMOVE; @@ -439,7 +514,7 @@ main( int argc, char **argv ) cops |= XOP_PULL|XOP_PUSH; /* fallthrough */ case '0': - mvars->ops[M] |= XOP_HAVE_TYPE; + ops[M] |= XOP_HAVE_TYPE; break; case 'n': case 'd': @@ -462,13 +537,13 @@ main( int argc, char **argv ) } if (op & OP_MASK_TYPE) switch (op & XOP_MASK_DIR) { - case XOP_PULL: mvars->ops[S] |= op & OP_MASK_TYPE; break; - case XOP_PUSH: mvars->ops[M] |= op & OP_MASK_TYPE; break; + case XOP_PULL: ops[S] |= op & OP_MASK_TYPE; break; + case XOP_PUSH: ops[M] |= op & OP_MASK_TYPE; break; default: cops |= op; break; } else cops |= op; - mvars->ops[M] |= XOP_HAVE_TYPE; + ops[M] |= XOP_HAVE_TYPE; break; case 'L': op = XOP_PULL; @@ -518,33 +593,42 @@ main( int argc, char **argv ) } #endif - if (merge_ops( cops, mvars->ops )) + if (merge_ops( cops, ops )) return 1; if (load_config( config, pseudo )) return 1; - if (!mvars->all && !argv[mvars->oind]) { - fputs( "No channel specified. Try '" EXE " -h'\n", stderr ); - return 1; - } if (!channels) { fputs( "No channels defined. Try 'man " EXE "'\n", stderr ); return 1; } - mvars->chan = channels; - if (mvars->all) - mvars->multiple = channels->next != 0; - else if (argv[mvars->oind + 1]) - mvars->multiple = 1; - else - for (group = groups; group; group = group->next) - if (!strcmp( group->name, argv[mvars->oind] )) { - mvars->multiple = 1; - break; + if (mvars->all) { + for (chan = channels; chan; chan = chan->next) + add_channel( &chanapp, chan, ops ); + } else { + for (; argv[oind]; oind++) { + for (group = groups; group; group = group->next) { + if (!strcmp( group->name, argv[oind] )) { + for (channame = group->channels; channame; channame = channame->next) + if (!add_named_channel( &chanapp, channame->string, ops )) + mvars->ret = 1; + goto gotgrp; + } } - mvars->argv = argv; + if (!add_named_channel( &chanapp, argv[oind], ops )) + mvars->ret = 1; + gotgrp: ; + } + } + if (!chans) { + fputs( "No channel specified. Try '" EXE " -h'\n", stderr ); + return 1; + } + mvars->chanptr = chans; + mvars->multiple = !!chans->next; + mvars->cben = 1; sync_chans( mvars, E_START ); main_loop(); @@ -558,7 +642,6 @@ main( int argc, char **argv ) static void store_opened( store_t *ctx, void *aux ); static void store_listed( int sts, void *aux ); static int sync_listed_boxes( main_vars_t *mvars, box_ent_t *mbox ); -static void done_sync_dyn( int sts, void *aux ); static void done_sync_2_dyn( int sts, void *aux ); static void done_sync( int sts, void *aux ); @@ -567,10 +650,8 @@ static void done_sync( int sts, void *aux ); static void sync_chans( main_vars_t *mvars, int ent ) { - group_conf_t *group; - channel_conf_t *chan; box_ent_t *mbox, *nmbox, **mboxapp; - char *channame, **boxes[2], *boxp, *nboxp; + char **boxes[2]; const char *labels[2]; int t, mb, sb, cmp; @@ -580,68 +661,8 @@ sync_chans( main_vars_t *mvars, int ent ) case E_OPEN: goto opened; case E_SYNC: goto syncone; } - for (;;) { - mvars->boxlist = 0; - mvars->boxes = 0; - if (!mvars->all) { - if (mvars->chanptr) - channame = mvars->chanptr->string; - else { - for (group = groups; group; group = group->next) - if (!strcmp( group->name, mvars->argv[mvars->oind] )) { - mvars->chanptr = group->channels; - channame = mvars->chanptr->string; - goto gotgrp; - } - channame = mvars->argv[mvars->oind]; - gotgrp: ; - } - if ((boxp = strchr( channame, ':' ))) - *boxp++ = 0; - for (chan = channels; chan; chan = chan->next) - if (!strcmp( chan->name, channame )) - goto gotchan; - error( "No channel or group named '%s' defined.\n", channame ); - mvars->ret = 1; - goto gotnone; - gotchan: - mvars->chan = chan; - if (boxp) { - if (!chan->patterns) { - error( "Cannot override mailbox in channel '%s' - no Patterns.\n", channame ); - mvars->ret = 1; - goto gotnone; - } - mvars->boxlist = 1; - mboxapp = &mvars->boxes; - for (;;) { - nboxp = strpbrk( boxp, ",\n" ); - if (nboxp) { - t = nboxp - boxp; - *nboxp++ = 0; - } else { - t = strlen( boxp ); - } - mbox = nfmalloc( sizeof(*mbox) ); - if (t) - mbox->name = nfstrndup( boxp, t ); - else - mbox->name = nfstrndup( "INBOX", 5 ); - mbox->present[M] = mbox->present[S] = BOX_POSSIBLE; - mbox->next = 0; - *mboxapp = mbox; - mboxapp = &mbox->next; - if (!nboxp) - break; - boxp = nboxp; - } - } - } - merge_actions( mvars->chan, mvars->ops, XOP_HAVE_TYPE, OP_MASK_TYPE, OP_MASK_TYPE ); - merge_actions( mvars->chan, mvars->ops, XOP_HAVE_CREATE, OP_CREATE, 0 ); - merge_actions( mvars->chan, mvars->ops, XOP_HAVE_REMOVE, OP_REMOVE, 0 ); - merge_actions( mvars->chan, mvars->ops, XOP_HAVE_EXPUNGE, OP_EXPUNGE, 0 ); - + do { + mvars->chan = mvars->chanptr->conf; info( "Channel %s\n", mvars->chan->name ); mvars->skip = mvars->cben = 0; for (t = 0; t < 2; t++) { @@ -675,11 +696,11 @@ sync_chans( main_vars_t *mvars, int ent ) if (mvars->state[M] != ST_OPEN || mvars->state[S] != ST_OPEN) return; - if (!mvars->boxlist && mvars->chan->patterns) { - mvars->boxlist = 1; + if (!mvars->chanptr->boxlist && mvars->chan->patterns) { + mvars->chanptr->boxlist = 2; boxes[M] = filter_boxes( mvars->ctx[M]->boxes, mvars->chan->boxes[M], mvars->chan->patterns ); boxes[S] = filter_boxes( mvars->ctx[S]->boxes, mvars->chan->boxes[S], mvars->chan->patterns ); - mboxapp = &mvars->boxes; + mboxapp = &mvars->chanptr->boxes; for (mb = sb = 0; boxes[M][mb] || boxes[S][sb]; ) { mbox = nfmalloc( sizeof(*mbox) ); if (!(cmp = !boxes[M][mb] - !boxes[S][sb]) && !(cmp = cmp_box_names( boxes[M] + mb, boxes[S] + sb ))) { @@ -706,14 +727,15 @@ sync_chans( main_vars_t *mvars, int ent ) free( boxes[M] ); free( boxes[S] ); } + mvars->boxptr = mvars->chanptr->boxes; if (mvars->list && mvars->multiple) printf( "%s:\n", mvars->chan->name ); syncml: mvars->done = mvars->cben = 0; - if (mvars->boxlist) { - while ((mbox = mvars->boxes)) { - mvars->boxes = mbox->next; + if (mvars->chanptr->boxlist) { + while ((mbox = mvars->boxptr)) { + mvars->boxptr = mbox->next; if (sync_listed_boxes( mvars, mbox )) goto syncw; } @@ -743,23 +765,18 @@ sync_chans( main_vars_t *mvars, int ent ) mvars->skip = mvars->cben = 1; return; } - for (nmbox = mvars->boxes; (mbox = nmbox); ) { - nmbox = mbox->next; - free( mbox->name ); - free( mbox ); + if (mvars->chanptr->boxlist == 2) { + for (nmbox = mvars->chanptr->boxes; (mbox = nmbox); ) { + nmbox = mbox->next; + free( mbox->name ); + free( mbox ); + } + mvars->chanptr->boxes = 0; + mvars->chanptr->boxlist = 0; } next2: - if (mvars->all) { - if (!(mvars->chan = mvars->chan->next)) - break; - } else { - if (mvars->chanptr && (mvars->chanptr = mvars->chanptr->next)) - continue; - gotnone: - if (!mvars->argv[++mvars->oind]) - break; - } - } + ; + } while ((mvars->chanptr = mvars->chanptr->next)); for (t = 0; t < N_DRIVERS; t++) drivers[t]->cleanup(); } @@ -789,7 +806,7 @@ store_opened( store_t *ctx, void *aux ) return; } mvars->ctx[t] = ctx; - if (!mvars->skip && !mvars->boxlist && mvars->chan->patterns && !ctx->listed) { + if (!mvars->skip && !mvars->chanptr->boxlist && mvars->chan->patterns && !ctx->listed) { for (flags = 0, cpat = mvars->chan->patterns; cpat; cpat = cpat->next) { const char *pat = cpat->string; if (*pat != '!') { @@ -873,36 +890,22 @@ sync_listed_boxes( main_vars_t *mvars, box_ent_t *mbox ) if (!mvars->list) { nfasprintf( &mvars->names[M], "%s%s", mpfx, mbox->name ); nfasprintf( &mvars->names[S], "%s%s", spfx, mbox->name ); - free( mbox->name ); sync_boxes( mvars->ctx, (const char **)mvars->names, mbox->present, mvars->chan, done_sync_2_dyn, mvars ); - free( mbox ); return 1; } printf( "%s%s <=> %s%s\n", mpfx, mbox->name, spfx, mbox->name ); } else { if (!mvars->list) { mvars->names[M] = mvars->names[S] = mbox->name; - sync_boxes( mvars->ctx, (const char **)mvars->names, mbox->present, mvars->chan, done_sync_dyn, mvars ); - free( mbox ); + sync_boxes( mvars->ctx, (const char **)mvars->names, mbox->present, mvars->chan, done_sync, mvars ); return 1; } puts( mbox->name ); } - free( mbox->name ); - free( mbox ); return 0; } static void -done_sync_dyn( int sts, void *aux ) -{ - main_vars_t *mvars = (main_vars_t *)aux; - - free( mvars->names[M] ); - done_sync( sts, aux ); -} - -static void done_sync_2_dyn( int sts, void *aux ) { main_vars_t *mvars = (main_vars_t *)aux;