isync

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

commit 74e936812183f6c1c3c82ad676b6805bbf8aa149
parent 6e32b88f3dd37f4160f55de66f817625c8ec9fd8
Author: Oswald Buddenhagen <ossi@users.sf.net>
Date:   Fri, 24 Mar 2017 18:09:40 +0100

let driver_t::load_box() return the list of messages

... and make 'msgs', 'count', and 'recent' private to the drivers.

Diffstat:
Msrc/driver.h | 9+++------
Msrc/drv_imap.c | 48++++++++++++++++++++++++++++--------------------
Msrc/drv_maildir.c | 32++++++++++++++++++--------------
Msrc/sync.c | 27++++++++++++++-------------
4 files changed, 63 insertions(+), 53 deletions(-)

diff --git a/src/driver.h b/src/driver.h @@ -88,12 +88,8 @@ typedef struct store { store_conf_t *conf; /* foreign */ /* currently open mailbox */ - message_t *msgs; /* own */ int uidvalidity; int uidnext; /* from SELECT responses */ - /* note that the following do _not_ reflect stats from msgs, but mailbox totals */ - int count; /* # of messages */ - int recent; /* # of recent messages - don't trust this beyond the initial read */ } store_t; typedef struct { @@ -204,9 +200,10 @@ struct driver { * Messages starting with newuid need to have the TUID populated when OPEN_FIND is set. * Messages up to seenuid need to have the Message-Id populated when OPEN_OLD_IDS is set. * Messages up to seenuid need to have the size populated when OPEN_OLD_SIZE is set; - * likewise messages above seenuid when OPEN_NEW_SIZE is set. */ + * likewise messages above seenuid when OPEN_NEW_SIZE is set. + * The returned message list remains owned by the driver. */ void (*load_box)( store_t *ctx, int minuid, int maxuid, int newuid, int seenuid, int_array_t excs, - void (*cb)( int sts, void *aux ), void *aux ); + void (*cb)( int sts, message_t *msgs, int total_msgs, int recent_msgs, void *aux ), void *aux ); /* Fetch the contents and flags of the given message from the current mailbox. */ void (*fetch_msg)( store_t *ctx, message_t *msg, msg_data_t *data, diff --git a/src/drv_imap.c b/src/drv_imap.c @@ -109,6 +109,10 @@ struct imap_store { list_t *ns_personal, *ns_other, *ns_shared; /* NAMESPACE info */ string_list_t *boxes; // _list results char listed; // was _list already run with these flags? + // note that the message counts do _not_ reflect stats from msgs, + // but mailbox totals. also, don't trust them beyond the initial load. + int total_msgs, recent_msgs; + message_t *msgs; message_t **msgapp; /* FETCH results */ uint caps; /* CAPABILITY results */ string_list_t *auth_mechs; @@ -1391,9 +1395,9 @@ imap_socket_read( void *aux ) goto listret; } else if ((arg1 = next_arg( &cmd ))) { if (!strcmp( "EXISTS", arg1 )) - ctx->gen.count = atoi( arg ); + ctx->total_msgs = atoi( arg ); else if (!strcmp( "RECENT", arg1 )) - ctx->gen.recent = atoi( arg ); + ctx->recent_msgs = atoi( arg ); else if(!strcmp ( "FETCH", arg1 )) { resp = parse_list( ctx, cmd, parse_fetch_rsp ); goto listret; @@ -1528,7 +1532,7 @@ get_cmd_result_p2( imap_store_t *ctx, imap_cmd_t *cmd, int response ) static void imap_cleanup_store( imap_store_t *ctx ) { - free_generic_messages( ctx->gen.msgs ); + free_generic_messages( ctx->msgs ); free_string_list( ctx->boxes ); } @@ -1596,8 +1600,10 @@ imap_cancel_unowned( void *gctx ) static void imap_free_store( store_t *gctx ) { - free_generic_messages( gctx->msgs ); - gctx->msgs = 0; + imap_store_t *ctx = (imap_store_t *)gctx; + + free_generic_messages( ctx->msgs ); + ctx->msgs = 0; imap_set_bad_callback( gctx, imap_cancel_unowned, gctx ); gctx->next = unowned; unowned = gctx; @@ -2316,9 +2322,9 @@ imap_select_box( store_t *gctx, const char *name ) { imap_store_t *ctx = (imap_store_t *)gctx; - free_generic_messages( gctx->msgs ); - gctx->msgs = 0; - ctx->msgapp = &gctx->msgs; + free_generic_messages( ctx->msgs ); + ctx->msgs = 0; + ctx->msgapp = &ctx->msgs; ctx->name = name; return DRV_OK; @@ -2408,7 +2414,9 @@ imap_create_box( store_t *gctx, static int imap_confirm_box_empty( store_t *gctx ) { - return gctx->count ? DRV_BOX_BAD : DRV_OK; + imap_store_t *ctx = (imap_store_t *)gctx; + + return ctx->total_msgs ? DRV_BOX_BAD : DRV_OK; } static void imap_delete_box_p2( imap_store_t *, imap_cmd_t *, int ); @@ -2492,24 +2500,24 @@ imap_set_range( imap_range_t *ranges, int *nranges, int low_flags, int high_flag typedef struct { imap_cmd_refcounted_state_t gen; - void (*callback)( int sts, void *aux ); + void (*callback)( int sts, message_t *msgs, int total_msgs, int recent_msgs, void *aux ); void *callback_aux; } imap_load_box_state_t; static void imap_submit_load( imap_store_t *, const char *, int, imap_load_box_state_t * ); -static void imap_submit_load_p3( imap_load_box_state_t * ); +static void imap_submit_load_p3( imap_store_t *ctx, imap_load_box_state_t * ); static void imap_load_box( store_t *gctx, int minuid, int maxuid, int newuid, int seenuid, int_array_t excs, - void (*cb)( int sts, void *aux ), void *aux ) + void (*cb)( int sts, message_t *msgs, int total_msgs, int recent_msgs, void *aux ), void *aux ) { imap_store_t *ctx = (imap_store_t *)gctx; int i, j, bl; char buf[1000]; - if (!ctx->gen.count) { + if (!ctx->total_msgs) { free( excs.data ); - cb( DRV_OK, aux ); + cb( DRV_OK, 0, 0, 0, aux ); } else { INIT_REFCOUNTED_STATE(imap_load_box_state_t, sts, cb, aux) for (i = 0; i < excs.size; ) { @@ -2545,7 +2553,7 @@ imap_load_box( store_t *gctx, int minuid, int maxuid, int newuid, int seenuid, i } } free( excs.data ); - imap_submit_load_p3( sts ); + imap_submit_load_p3( ctx, sts ); } } @@ -2566,18 +2574,18 @@ imap_submit_load( imap_store_t *ctx, const char *buf, int flags, imap_load_box_s } static void -imap_submit_load_p2( imap_store_t *ctx ATTR_UNUSED, imap_cmd_t *cmd, int response ) +imap_submit_load_p2( imap_store_t *ctx, imap_cmd_t *cmd, int response ) { imap_load_box_state_t *sts = (imap_load_box_state_t *)((imap_cmd_refcounted_t *)cmd)->state; transform_refcounted_box_response( &sts->gen, response ); - imap_submit_load_p3( sts ); + imap_submit_load_p3( ctx, sts ); } static void -imap_submit_load_p3( imap_load_box_state_t *sts ) +imap_submit_load_p3( imap_store_t *ctx, imap_load_box_state_t *sts ) { - DONE_REFCOUNTED_STATE(sts) + DONE_REFCOUNTED_STATE_ARGS(sts, ctx->msgs, ctx->total_msgs, ctx->recent_msgs) } /******************* imap_fetch_msg *******************/ @@ -2715,7 +2723,7 @@ imap_close_box( store_t *gctx, int bl; char buf[1000]; - for (msg = ctx->gen.msgs; ; ) { + for (msg = ctx->msgs; ; ) { for (bl = 0; msg && bl < 960; msg = msg->next) { if (!(msg->flags & F_DELETED)) continue; diff --git a/src/drv_maildir.c b/src/drv_maildir.c @@ -81,6 +81,10 @@ typedef struct { #endif /* USE_DB */ string_list_t *boxes; // _list results char listed; // was _list already run with these flags? + // note that the message counts do _not_ reflect stats from msgs, + // but mailbox totals. also, don't trust them beyond the initial load. + int total_msgs, recent_msgs; + message_t *msgs; wakeup_t lcktmr; void (*bad_callback)( void *aux ); @@ -263,7 +267,7 @@ maildir_cleanup( store_t *gctx ) { maildir_store_t *ctx = (maildir_store_t *)gctx; - free_maildir_messages( gctx->msgs ); + free_maildir_messages( ctx->msgs ); #ifdef USE_DB if (ctx->db) ctx->db->close( ctx->db, 0 ); @@ -908,7 +912,7 @@ maildir_scan( maildir_store_t *ctx, msg_t_array_alloc_t *msglist ) again: ARRAY_INIT( msglist ); - ctx->gen.count = ctx->gen.recent = 0; + ctx->total_msgs = ctx->recent_msgs = 0; if (ctx->uvok || ctx->maxuid == INT_MAX) { #ifdef USE_DB if (ctx->usedb) { @@ -960,8 +964,8 @@ maildir_scan( maildir_store_t *ctx, msg_t_array_alloc_t *msglist ) while ((e = readdir( d ))) { if (*e->d_name == '.') continue; - ctx->gen.count++; - ctx->gen.recent += i; + ctx->total_msgs++; + ctx->recent_msgs += i; #ifdef USE_DB if (ctx->usedb) { if (maildir_uidval_lock( ctx ) != DRV_OK) @@ -1230,7 +1234,7 @@ maildir_select_box( store_t *gctx, const char *name ) maildir_store_t *ctx = (maildir_store_t *)gctx; maildir_cleanup( gctx ); - gctx->msgs = 0; + ctx->msgs = 0; ctx->excs.data = 0; ctx->uvfd = -1; #ifdef USE_DB @@ -1327,7 +1331,7 @@ maildir_confirm_box_empty( store_t *gctx ) if (maildir_scan( ctx, &msglist ) != DRV_OK) return DRV_BOX_BAD; maildir_free_scan( &msglist ); - return gctx->count ? DRV_BOX_BAD : DRV_OK; + return ctx->total_msgs ? DRV_BOX_BAD : DRV_OK; } static void @@ -1401,7 +1405,7 @@ maildir_prepare_load_box( store_t *gctx, int opts ) static void maildir_load_box( store_t *gctx, int minuid, int maxuid, int newuid, int seenuid, int_array_t excs, - void (*cb)( int sts, void *aux ), void *aux ) + void (*cb)( int sts, message_t *msgs, int total_msgs, int recent_msgs, void *aux ), void *aux ) { maildir_store_t *ctx = (maildir_store_t *)gctx; message_t **msgapp; @@ -1416,15 +1420,15 @@ maildir_load_box( store_t *gctx, int minuid, int maxuid, int newuid, int seenuid ctx->excs = excs; if (maildir_scan( ctx, &msglist ) != DRV_OK) { - cb( DRV_BOX_BAD, aux ); + cb( DRV_BOX_BAD, 0, 0, 0, aux ); return; } - msgapp = &ctx->gen.msgs; + msgapp = &ctx->msgs; for (i = 0; i < msglist.array.size; i++) maildir_app_msg( ctx, &msgapp, msglist.array.data + i ); maildir_free_scan( &msglist ); - cb( DRV_OK, aux ); + cb( DRV_OK, ctx->msgs, ctx->total_msgs, ctx->recent_msgs, aux ); } static int @@ -1438,7 +1442,7 @@ maildir_rescan( maildir_store_t *ctx ) ctx->fresh[0] = ctx->fresh[1] = 0; if (maildir_scan( ctx, &msglist ) != DRV_OK) return DRV_BOX_BAD; - for (msgapp = &ctx->gen.msgs, i = 0; + for (msgapp = &ctx->msgs, i = 0; (msg = (maildir_message_t *)*msgapp) || i < msglist.array.size; ) { if (!msg) { @@ -1758,7 +1762,7 @@ maildir_trash_msg( store_t *gctx, message_t *gmsg, } } gmsg->status |= M_DEAD; - gctx->count--; + ctx->total_msgs--; #ifdef USE_DB if (ctx->usedb) { @@ -1783,7 +1787,7 @@ maildir_close_box( store_t *gctx, for (;;) { retry = 0; basel = nfsnprintf( buf, sizeof(buf), "%s/", ctx->path ); - for (msg = gctx->msgs; msg; msg = msg->next) + for (msg = ctx->msgs; msg; msg = msg->next) if (!(msg->status & M_DEAD) && (msg->flags & F_DELETED)) { nfsnprintf( buf + basel, sizeof(buf) - basel, "%s/%s", subdirs[msg->status & M_RECENT], ((maildir_message_t *)msg)->base ); if (unlink( buf )) { @@ -1793,7 +1797,7 @@ maildir_close_box( store_t *gctx, sys_error( "Maildir error: cannot remove %s", buf ); } else { msg->status |= M_DEAD; - gctx->count--; + ctx->total_msgs--; #ifdef USE_DB if (ctx->db && (ret = maildir_purge_msg( ctx, ((maildir_message_t *)msg)->base )) != DRV_OK) { cb( ret, aux ); diff --git a/src/sync.c b/src/sync.c @@ -151,7 +151,7 @@ typedef struct { store_t *ctx[2]; driver_t *drv[2]; const char *orig_name[2]; - message_t *new_msgs[2]; + message_t *msgs[2], *new_msgs[2]; int_array_alloc_t trashed_msgs[2]; int state[2], opts[2], ref_count, nsrecs, ret, lfd, existing, replayed; int new_pending[2], flags_pending[2], trash_pending[2]; @@ -237,7 +237,7 @@ match_tuids( sync_vars_t *svars, int t ) goto mfound; } } - for (tmsg = svars->ctx[t]->msgs; tmsg != ntmsg; tmsg = tmsg->next) { + for (tmsg = svars->msgs[t]; tmsg != ntmsg; tmsg = tmsg->next) { if (tmsg->status & M_DEAD) continue; if (tmsg->tuid[0] && !memcmp( tmsg->tuid, srec->tuid, TUIDL )) { @@ -1308,7 +1308,7 @@ get_seenuid( sync_vars_t *svars, int t ) return seenuid; } -static void box_loaded( int sts, void *aux ); +static void box_loaded( int sts, message_t *msgs, int total_msgs, int recent_msgs, void *aux ); static void load_box( sync_vars_t *svars, int t, int minwuid, int_array_t mexcs ) @@ -1359,7 +1359,7 @@ static void msg_copied_p2( sync_vars_t *svars, sync_rec_t *srec, int t, int uid static void msgs_copied( sync_vars_t *svars, int t ); static void -box_loaded( int sts, void *aux ) +box_loaded( int sts, message_t *msgs, int total_msgs, int recent_msgs, void *aux ) { DECL_SVARS; sync_rec_t *srec; @@ -1375,7 +1375,8 @@ box_loaded( int sts, void *aux ) return; INIT_SVARS(aux); svars->state[t] |= ST_LOADED; - info( "%s: %d messages, %d recent\n", str_ms[t], svars->ctx[t]->count, svars->ctx[t]->recent ); + svars->msgs[t] = msgs; + info( "%s: %d messages, %d recent\n", str_ms[t], total_msgs, recent_msgs ); if (svars->state[t] & ST_FIND_OLD) { debug( "matching previously copied messages on %s\n", str_ms[t] ); @@ -1398,7 +1399,7 @@ box_loaded( int sts, void *aux ) srecmap[idx].uid = uid; srecmap[idx].srec = srec; } - for (tmsg = svars->ctx[t]->msgs; tmsg; tmsg = tmsg->next) { + for (tmsg = svars->msgs[t]; tmsg; tmsg = tmsg->next) { if (tmsg->srec) /* found by TUID */ continue; uid = tmsg->uid; @@ -1556,7 +1557,7 @@ box_loaded( int sts, void *aux ) debug( "synchronizing new entries\n" ); for (t = 0; t < 2; t++) { - for (tmsg = svars->ctx[1-t]->msgs; tmsg; tmsg = tmsg->next) { + for (tmsg = svars->msgs[1-t]; tmsg; tmsg = tmsg->next) { // If new have no srec, the message is always New. If we have a srec: // - message is old (> 0) or expired (0) => ignore // - message was skipped (-1) => ReNew @@ -1633,7 +1634,7 @@ box_loaded( int sts, void *aux ) * older than the first not expired message are not counted towards the total. */ debug( "preparing message expiration\n" ); alive = 0; - for (tmsg = svars->ctx[S]->msgs; tmsg; tmsg = tmsg->next) { + for (tmsg = svars->msgs[S]; tmsg; tmsg = tmsg->next) { if (tmsg->status & M_DEAD) continue; if ((srec = tmsg->srec) && srec->uid[M] > 0 && @@ -1644,14 +1645,14 @@ box_loaded( int sts, void *aux ) alive++; } } - for (tmsg = svars->ctx[M]->msgs; tmsg; tmsg = tmsg->next) { + for (tmsg = svars->msgs[M]; tmsg; tmsg = tmsg->next) { if ((srec = tmsg->srec) && srec->tuid[0] && !(tmsg->flags & F_DELETED)) alive++; } todel = alive - svars->chan->max_messages; debug( "%d alive messages, %d excess - expiring\n", alive, todel ); alive = 0; - for (tmsg = svars->ctx[S]->msgs; tmsg; tmsg = tmsg->next) { + for (tmsg = svars->msgs[S]; tmsg; tmsg = tmsg->next) { if (tmsg->status & M_DEAD) continue; if (!(srec = tmsg->srec) || srec->uid[M] <= 0) { @@ -1679,7 +1680,7 @@ box_loaded( int sts, void *aux ) } } } - for (tmsg = svars->ctx[M]->msgs; tmsg; tmsg = tmsg->next) { + for (tmsg = svars->msgs[M]; tmsg; tmsg = tmsg->next) { if ((srec = tmsg->srec) && srec->tuid[0]) { nflags = tmsg->flags; if (!(nflags & F_DELETED)) { @@ -1808,7 +1809,7 @@ box_loaded( int sts, void *aux ) for (t = 0; t < 2; t++) { svars->newuid[t] = svars->ctx[t]->uidnext; jFprintf( svars, "F %d %d\n", t, svars->newuid[t] ); - svars->new_msgs[t] = svars->ctx[1-t]->msgs; + svars->new_msgs[t] = svars->msgs[1-t]; msgs_copied( svars, t ); if (check_cancel( svars )) goto out; @@ -2021,7 +2022,7 @@ msgs_flags_set( sync_vars_t *svars, int t ) if ((svars->chan->ops[t] & OP_EXPUNGE) && (svars->ctx[t]->conf->trash || (svars->ctx[1-t]->conf->trash && svars->ctx[1-t]->conf->trash_remote_new))) { debug( "trashing in %s\n", str_ms[t] ); - for (tmsg = svars->ctx[t]->msgs; tmsg; tmsg = tmsg->next) + for (tmsg = svars->msgs[t]; tmsg; tmsg = tmsg->next) if ((tmsg->flags & F_DELETED) && !find_int_array( svars->trashed_msgs[t].array, tmsg->uid ) && (t == M || !tmsg->srec || !(tmsg->srec->status & (S_EXPIRE|S_EXPIRED)))) { if (svars->ctx[t]->conf->trash) {