isync

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

commit 8aa22a62e790c4ced512e0f74c407725162a3b0d
parent 1de3ecd8830e98754721fd3f0267f9890aed2d2a
Author: Oswald Buddenhagen <ossi@users.sf.net>
Date:   Sat, 28 Mar 2015 17:26:08 +0100

make progress counters global

which means they are now cumulative, and include channels and boxes.

Diffstat:
Msrc/common.h | 6++++++
Msrc/drv_imap.c | 2++
Msrc/main.c | 61++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
Msrc/mbsync.1 | 15+++++++++++++++
Msrc/sync.c | 77+++++++++++++++++++++++++++++------------------------------------------------
5 files changed, 108 insertions(+), 53 deletions(-)

diff --git a/src/common.h b/src/common.h @@ -78,6 +78,12 @@ extern const char *Home; extern int BufferLimit; +extern int new_total[2], new_done[2]; +extern int flags_total[2], flags_done[2]; +extern int trash_total[2], trash_done[2]; + +void stats( void ); + /* util.c */ void ATTR_PRINTFLIKE(1, 2) debug( const char *, ... ); diff --git a/src/drv_imap.c b/src/drv_imap.c @@ -1728,6 +1728,7 @@ ensure_password( imap_server_conf_t *srvc ) int ret; char buffer[80]; + flushn(); if (!(fp = popen( srvc->pass_cmd, "r" ))) { pipeerr: sys_error( "Skipping account %s, password command failed", srvc->name ); @@ -1754,6 +1755,7 @@ ensure_password( imap_server_conf_t *srvc ) } else if (!srvc->pass) { char *pass, prompt[80]; + flushn(); sprintf( prompt, "Password (%s): ", srvc->name ); pass = getpass( prompt ); if (!pass) { diff --git a/src/main.c b/src/main.c @@ -45,6 +45,12 @@ const char *Home; /* for config */ int BufferLimit = 10 * 1024 * 1024; +int chans_total, chans_done; +int boxes_total, boxes_done; +int new_total[2], new_done[2]; +int flags_total[2], flags_done[2]; +int trash_total[2], trash_done[2]; + static void version( void ) { @@ -123,6 +129,32 @@ crashHandler( int n ) } #endif +void +stats( void ) +{ + char buf[3][64]; + char *cs; + int t, l, ll, cls; + static int cols = -1; + + if (DFlags & QUIET) + return; + + if (cols < 0 && (!(cs = getenv( "COLUMNS" )) || !(cols = atoi( cs )))) + cols = 80; + ll = sprintf( buf[2], "C: %d/%d B: %d/%d", chans_done, chans_total, boxes_done, boxes_total ); + cls = (cols - ll - 10) / 2; + for (t = 0; t < 2; t++) { + l = sprintf( buf[t], "+%d/%d *%d/%d #%d/%d", + new_done[t], new_total[t], + flags_done[t], flags_total[t], + trash_done[t], trash_total[t] ); + if (l > cls) + buf[t][cls - 1] = '~'; + } + infon( "\v\r%s M: %.*s S: %.*s", buf[2], cls, buf[0], cls, buf[1] ); +} + static int matches( const char *t, const char *p ) { @@ -254,6 +286,7 @@ add_channel( chan_ent_t ***chanapp, channel_conf_t *chan, int ops[] ) **chanapp = ce; *chanapp = &ce->next; + chans_total++; return ce; } @@ -297,8 +330,12 @@ add_named_channel( chan_ent_t ***chanapp, char *channame, int ops[] ) mbox->next = 0; *mboxapp = mbox; mboxapp = &mbox->next; + boxes_total++; boxp = nboxp; } while (boxp); + } else { + if (!chan->patterns) + boxes_total++; } ce = add_channel( chanapp, chan, ops ); @@ -315,7 +352,7 @@ typedef struct { chan_ent_t *chanptr; box_ent_t *boxptr; char *names[2]; - int ret, multiple, all, list, state[2]; + int ret, all, list, state[2]; char done, skip, cben; } main_vars_t; @@ -605,8 +642,11 @@ main( int argc, char **argv ) } if (mvars->all) { - for (chan = channels; chan; chan = chan->next) + for (chan = channels; chan; chan = chan->next) { add_channel( &chanapp, chan, ops ); + if (!chan->patterns) + boxes_total++; + } } else { for (; argv[oind]; oind++) { for (group = groups; group; group = group->next) { @@ -627,11 +667,14 @@ main( int argc, char **argv ) return 1; } mvars->chanptr = chans; - mvars->multiple = !!chans->next; + if (!mvars->list) + stats(); mvars->cben = 1; sync_chans( mvars, E_START ); main_loop(); + if (!mvars->list) + flushn(); return mvars->ret; } @@ -723,13 +766,16 @@ sync_chans( main_vars_t *mvars, int ent ) mbox->next = 0; *mboxapp = mbox; mboxapp = &mbox->next; + boxes_total++; } free( boxes[M] ); free( boxes[S] ); + if (!mvars->list) + stats(); } mvars->boxptr = mvars->chanptr->boxes; - if (mvars->list && mvars->multiple) + if (mvars->list && chans_total > 1) printf( "%s:\n", mvars->chan->name ); syncml: mvars->done = mvars->cben = 0; @@ -775,7 +821,10 @@ sync_chans( main_vars_t *mvars, int ent ) mvars->chanptr->boxlist = 0; } next2: - ; + if (!mvars->list) { + chans_done++; + stats(); + } } while ((mvars->chanptr = mvars->chanptr->next)); for (t = 0; t < N_DRIVERS; t++) drivers[t]->cleanup(); @@ -921,6 +970,8 @@ done_sync( int sts, void *aux ) main_vars_t *mvars = (main_vars_t *)aux; mvars->done = 1; + boxes_done++; + stats(); if (sts) { mvars->ret = 1; if (sts & (SYNC_BAD(M) | SYNC_BAD(S))) { diff --git a/src/mbsync.1 b/src/mbsync.1 @@ -591,6 +591,21 @@ absolute limit, as even a single message can consume more memory than this. (Default: \fI10M\fR) .. +.SH CONSOLE OUTPUT +If \fBmbsync\fR's output is connected to a console, it will print progress +counters by default. The output will look like this: +.P +.in +4 +C: 1/2 B: 3/4 M: +13/13 *23/42 #0/0 S: +0/7 *0/0 #0/0 +.in -4 +.P +This represents the cumulative progress over channels, boxes, and messages +affected on master and slave, respectively. +The message counts represent added messages, messages with updated flags, +and trashed messages, respectively. +No attempt is made to calculate the totals in advance, so they grow over +time as more information is gathered. +.. .SH RECOMMENDATIONS Make sure your IMAP server does not auto-expunge deleted messages - it is slow, and semantically somewhat questionable. Specifically, Gmail needs to diff --git a/src/sync.c b/src/sync.c @@ -156,9 +156,7 @@ typedef struct { const char *orig_name[2]; message_t *new_msgs[2]; int state[2], ref_count, nsrecs, ret, lfd, existing, replayed; - int new_total[2], new_done[2]; - int flags_total[2], flags_done[2]; - int trash_total[2], trash_done[2]; + int new_pending[2], flags_pending[2], trash_pending[2]; int maxuid[2]; /* highest UID that was already propagated */ int newmaxuid[2]; /* highest UID that is currently being propagated */ int uidval[2]; /* UID validity value */ @@ -446,30 +444,6 @@ msg_stored( int sts, int uid, void *aux ) } -static void -stats( sync_vars_t *svars ) -{ - char buf[2][64]; - char *cs; - int t, l; - static int cols = -1; - - if (cols < 0 && (!(cs = getenv( "COLUMNS" )) || !(cols = atoi( cs ) / 2))) - cols = 36; - if (!(DFlags & QUIET)) { - for (t = 0; t < 2; t++) { - l = sprintf( buf[t], "+%d/%d *%d/%d #%d/%d", - svars->new_done[t], svars->new_total[t], - svars->flags_done[t], svars->flags_total[t], - svars->trash_done[t], svars->trash_total[t] ); - if (l > cols) - buf[t][cols - 1] = '~'; - } - infon( "\v\rM: %.*s S: %.*s", cols, buf[0], cols, buf[1] ); - } -} - - static void sync_bail( sync_vars_t *svars ); static void sync_bail2( sync_vars_t *svars ); static void sync_bail3( sync_vars_t *svars ); @@ -1697,8 +1671,9 @@ box_loaded( int sts, void *aux ) dflags &= srec->msg[t]->flags; } if (aflags | dflags) { - svars->flags_total[t]++; - stats( svars ); + flags_total[t]++; + stats(); + svars->flags_pending[t]++; fv = nfmalloc( sizeof(*fv) ); fv->aux = AUX; fv->srec = srec; @@ -1756,8 +1731,9 @@ msg_copied( int sts, int uid, copy_vars_t *vars ) return; } free( vars ); - svars->new_done[t]++; - stats( svars ); + new_done[t]++; + stats(); + svars->new_pending[t]--; msgs_copied( svars, t ); } @@ -1812,8 +1788,9 @@ msgs_copied( sync_vars_t *svars, int t ) svars->new_msgs[t] = tmsg; goto out; } - svars->new_total[t]++; - stats( svars ); + new_total[t]++; + stats(); + svars->new_pending[t]++; svars->state[t] |= ST_SENDING_NEW; cv = nfmalloc( sizeof(*cv) ); cv->cb = msg_copied; @@ -1829,7 +1806,7 @@ msgs_copied( sync_vars_t *svars, int t ) svars->state[t] |= ST_SENT_NEW; } - if (svars->new_done[t] < svars->new_total[t]) + if (svars->new_pending[t]) goto out; Fprintf( svars->jfp, "%c %d\n", ")("[t], svars->maxuid[1-t] ); @@ -1885,8 +1862,9 @@ flags_set( int sts, void *aux ) break; } free( vars ); - svars->flags_done[t]++; - stats( svars ); + flags_done[t]++; + stats(); + svars->flags_pending[t]--; msgs_flags_set( svars, t ); } @@ -1930,7 +1908,7 @@ msgs_flags_set( sync_vars_t *svars, int t ) message_t *tmsg; copy_vars_t *cv; - if (!(svars->state[t] & ST_SENT_FLAGS) || svars->flags_done[t] < svars->flags_total[t]) + if (!(svars->state[t] & ST_SENT_FLAGS) || svars->flags_pending[t]) return; sync_ref( svars ); @@ -1943,8 +1921,9 @@ msgs_flags_set( sync_vars_t *svars, int t ) if (svars->ctx[t]->conf->trash) { if (!svars->ctx[t]->conf->trash_only_new || !tmsg->srec || tmsg->srec->uid[1-t] < 0) { debug( "%s: trashing message %d\n", str_ms[t], tmsg->uid ); - svars->trash_total[t]++; - stats( svars ); + trash_total[t]++; + stats(); + svars->trash_pending[t]++; svars->drv[t]->trash_msg( svars->ctx[t], tmsg, msg_trashed, AUX ); if (check_cancel( svars )) goto out; @@ -1954,8 +1933,9 @@ msgs_flags_set( sync_vars_t *svars, int t ) if (!tmsg->srec || tmsg->srec->uid[1-t] < 0) { if (tmsg->size <= svars->ctx[1-t]->conf->max_size) { debug( "%s: remote trashing message %d\n", str_ms[t], tmsg->uid ); - svars->trash_total[t]++; - stats( svars ); + trash_total[t]++; + stats(); + svars->trash_pending[t]++; cv = nfmalloc( sizeof(*cv) ); cv->cb = msg_rtrashed; cv->aux = INV_AUX; @@ -1988,8 +1968,9 @@ msg_trashed( int sts, void *aux ) if (check_ret( sts, aux )) return; INIT_SVARS(aux); - svars->trash_done[t]++; - stats( svars ); + trash_done[t]++; + stats(); + svars->trash_pending[t]--; sync_close( svars, t ); } @@ -2008,8 +1989,9 @@ msg_rtrashed( int sts, int uid ATTR_UNUSED, copy_vars_t *vars ) } free( vars ); t ^= 1; - svars->trash_done[t]++; - stats( svars ); + trash_done[t]++; + stats(); + svars->trash_pending[t]--; sync_close( svars, t ); } @@ -2019,8 +2001,8 @@ static void box_closed_p2( sync_vars_t *svars, int t ); static void sync_close( sync_vars_t *svars, int t ) { - if ((~svars->state[t] & (ST_FOUND_NEW|ST_SENT_TRASH)) || svars->trash_done[t] < svars->trash_total[t] || - !(svars->state[1-t] & ST_SENT_NEW) || svars->new_done[1-t] < svars->new_total[1-t]) + if ((~svars->state[t] & (ST_FOUND_NEW|ST_SENT_TRASH)) || svars->trash_pending[t] || + !(svars->state[1-t] & ST_SENT_NEW) || svars->new_pending[1-t]) return; if (svars->state[t] & ST_CLOSING) @@ -2120,7 +2102,6 @@ sync_bail2( sync_vars_t *svars ) free( svars->nname ); free( svars->jname ); free( svars->dname ); - flushn(); sync_bail3( svars ); }