isync

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

commit 584e51ed7d0d44c9d6b4b966047667bf44bf982b
parent 2ab689b3df07367b975a316e961fc953b1fa0903
Author: Oswald Buddenhagen <ossi@users.sf.net>
Date:   Sun,  3 Apr 2011 18:21:46 +0200

docs

- insert "separator comments" between driver entry points
- document driver API
- document sync_vars_t parts that are stored in the sync state header

Diffstat:
Msrc/drv_imap.c | 36++++++++++++++++++++++++++++++++++++
Msrc/isync.h | 62++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
Msrc/sync.c | 6++++--
3 files changed, 100 insertions(+), 4 deletions(-)

diff --git a/src/drv_imap.c b/src/drv_imap.c @@ -144,6 +144,8 @@ struct imap_cmd { int tag; struct { + /* Will be called on each continuation request until it resets this pointer. + * Needs to invoke bad_callback and return -1 on error, otherwise return 0. */ int (*cont)( imap_store_t *ctx, struct imap_cmd *cmd, const char *prompt ); void (*done)( imap_store_t *ctx, struct imap_cmd *cmd, int response ); char *data; @@ -1248,6 +1250,8 @@ get_cmd_result_p2( imap_store_t *ctx, struct imap_cmd *cmd, int response ) } } +/******************* imap_cancel_store *******************/ + static void imap_cancel_store( store_t *gctx ) { @@ -1285,6 +1289,8 @@ imap_invoke_bad_callback( imap_store_t *ctx ) ctx->gen.bad_callback( ctx->gen.bad_callback_aux ); } +/******************* imap_disown_store & imap_own_store *******************/ + static store_t *unowned; static void @@ -1323,6 +1329,8 @@ imap_own_store( store_conf_t *conf ) return 0; } +/******************* imap_cleanup *******************/ + static void imap_cleanup_p2( imap_store_t *, struct imap_cmd *, int ); static void @@ -1345,6 +1353,8 @@ imap_cleanup_p2( imap_store_t *ctx, imap_cancel_store( &ctx->gen ); } +/******************* imap_open_store *******************/ + #ifdef HAVE_LIBSSL static int start_tls( imap_store_t *ctx ) @@ -1794,12 +1804,16 @@ imap_open_store_bail( imap_store_t *ctx ) cb( 0, aux ); } +/******************* imap_prepare_opts *******************/ + static void imap_prepare_opts( store_t *gctx, int opts ) { gctx->opts = opts; } +/******************* imap_select *******************/ + static void imap_select( store_t *gctx, int create, void (*cb)( int sts, void *aux ), void *aux ) @@ -1826,6 +1840,8 @@ imap_select( store_t *gctx, int create, "SELECT \"%s%s\"", prefix, gctx->name ); } +/******************* imap_load *******************/ + static int imap_submit_load( imap_store_t *, const char *, struct imap_cmd_refcounted_state *, struct imap_cmd ** ); static void imap_load_p2( imap_store_t *, struct imap_cmd *, int ); @@ -1906,6 +1922,8 @@ imap_load_p2( imap_store_t *ctx ATTR_UNUSED, struct imap_cmd *cmd, int response imap_refcounted_done( sts ); } +/******************* imap_fetch_msg *******************/ + static void imap_fetch_msg( store_t *ctx, message_t *msg, msg_data_t *data, void (*cb)( int sts, void *aux ), void *aux ) @@ -1920,6 +1938,8 @@ imap_fetch_msg( store_t *ctx, message_t *msg, msg_data_t *data, msg->uid, (msg->status & M_FLAGS) ? "" : "FLAGS " ); } +/******************* imap_set_flags *******************/ + static void imap_set_flags_p2( imap_store_t *, struct imap_cmd *, int ); static int @@ -1995,6 +2015,8 @@ imap_set_flags_p2( imap_store_t *ctx ATTR_UNUSED, struct imap_cmd *cmd, int resp imap_refcounted_done( sts ); } +/******************* imap_close *******************/ + static void imap_close( store_t *ctx, void (*cb)( int sts, void *aux ), void *aux ) @@ -2005,6 +2027,8 @@ imap_close( store_t *ctx, imap_exec( (imap_store_t *)ctx, &cmd->gen, imap_done_simple_box, "CLOSE" ); } +/******************* imap_trash_msg *******************/ + static void imap_trash_msg( store_t *gctx, message_t *msg, void (*cb)( int sts, void *aux ), void *aux ) @@ -2020,6 +2044,8 @@ imap_trash_msg( store_t *gctx, message_t *msg, msg->uid, ctx->prefix, gctx->conf->trash ); } +/******************* imap_store_msg *******************/ + static void imap_store_msg_p2( imap_store_t *, struct imap_cmd *, int ); static void @@ -2066,6 +2092,8 @@ imap_store_msg_p2( imap_store_t *ctx ATTR_UNUSED, struct imap_cmd *cmd, int resp cmdp->callback( response, cmdp->out_uid, cmdp->callback_aux ); } +/******************* imap_find_msg *******************/ + static void imap_find_msg_p2( imap_store_t *, struct imap_cmd *, int ); static void @@ -2095,6 +2123,8 @@ imap_find_msg_p2( imap_store_t *ctx ATTR_UNUSED, struct imap_cmd *cmd, int respo cmdp->out_uid, cmdp->callback_aux ); } +/******************* imap_list *******************/ + static void imap_list( store_t *gctx, void (*cb)( int sts, void *aux ), void *aux ) @@ -2107,6 +2137,8 @@ imap_list( store_t *gctx, "LIST \"\" \"%s%%\"", ctx->prefix ); } +/******************* imap_cancel *******************/ + static void imap_cancel( store_t *gctx, void (*cb)( void *aux ), void *aux ) @@ -2115,12 +2147,16 @@ imap_cancel( store_t *gctx, cb( aux ); } +/******************* imap_commit *******************/ + static void imap_commit( store_t *gctx ) { (void)gctx; } +/******************* imap_parse_store *******************/ + imap_server_conf_t *servers, **serverapp = &servers; static int diff --git a/src/isync.h b/src/isync.h @@ -167,6 +167,8 @@ typedef struct store { int recent; /* # of recent messages - don't trust this beyond the initial read */ } store_t; +/* When the callback is invoked (at most once per store), the store is fubar; + * call the driver's cancel_store() to dispose of it. */ static INLINE void set_bad_callback( store_t *ctx, void (*cb)( void *aux ), void *aux ) { @@ -181,11 +183,14 @@ typedef struct { } msg_data_t; #define DRV_OK 0 +/* Message went missing, or mailbox is full, etc. */ #define DRV_MSG_BAD 1 +/* Something is wrong with the current mailbox - probably it is somehow inaccessible. */ #define DRV_BOX_BAD 2 +/* The command has been cancel()ed or cancel_store()d. */ #define DRV_CANCELED 3 -/* All memory belongs to the driver's user. */ +/* All memory belongs to the driver's user, unless stated otherwise. */ /* This flag says that the driver CAN store messages with CRLFs, @@ -198,34 +203,87 @@ typedef struct { struct driver { int flags; + + /* Parse configuration. */ int (*parse_store)( conffile_t *cfg, store_conf_t **storep, int *err ); + + /* Close remaining server connections. All stores must be disowned first. */ void (*cleanup)( void ); + + /* Open a store with the given configuration. This may recycle existing + * server connections. Upon failure, a null store is passed to the callback. */ void (*open_store)( store_conf_t *conf, void (*cb)( store_t *ctx, void *aux ), void *aux ); + + /* Mark the store as available for recycling. Server connection may be kept alive. */ void (*disown_store)( store_t *ctx ); + + /* Try to recycle a store with the given configuration. */ store_t *(*own_store)( store_conf_t *conf ); + + /* Discard the store after a bad_callback. The server connections will be closed. + * Pending commands will have their callbacks synchronously invoked with DRV_CANCELED. */ void (*cancel_store)( store_t *ctx ); + + /* List the mailboxes in this store. */ void (*list)( store_t *ctx, void (*cb)( int sts, void *aux ), void *aux ); + + /* Invoked before select(), this informs the driver which operations (OP_*) + * will be performed on the mailbox. The driver may extend the set by implicitly + * needed or available operations. */ void (*prepare_opts)( store_t *ctx, int opts ); + + /* Open the mailbox ctx->name. Optionally create missing boxes. + * As a side effect, this should resolve ctx->path if applicable. */ void (*select)( store_t *ctx, int create, void (*cb)( int sts, void *aux ), void *aux ); + + /* Load the message attributes needed to perform the requested operations. + * Consider only messages with UIDs between minuid and maxuid (inclusive) + * and those named in the excs array (smaller than minuid). + * The driver takes ownership of the excs array. */ void (*load)( store_t *ctx, int minuid, int maxuid, int *excs, int nexcs, void (*cb)( int sts, 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, void (*cb)( int sts, void *aux ), void *aux ); + + /* Store the given message to either the current mailbox or the trash folder. + * If the new copy's UID can be immediately determined, return it, otherwise -1. */ void (*store_msg)( store_t *ctx, msg_data_t *data, int to_trash, void (*cb)( int sts, int uid, void *aux ), void *aux ); + + /* Find a message by its temporary UID header to determine its real UID. */ void (*find_msg)( store_t *ctx, const char *tuid, void (*cb)( int sts, int uid, void *aux ), void *aux ); + + /* Add/remove the named flags to/from the given message. The message may be either + * a pre-fetched one (in which case the in-memory representation is updated), + * or it may be identifed by UID only. The operation may be delayed until commit() + * is called. */ void (*set_flags)( store_t *ctx, message_t *msg, int uid, int add, int del, /* msg can be null, therefore uid as a fallback */ void (*cb)( int sts, void *aux ), void *aux ); + + /* Move the given message from the current mailbox to the trash folder. + * This may expunge the original message immediately, but it needn't to. */ void (*trash_msg)( store_t *ctx, message_t *msg, /* This may expunge the original message immediately, but it needn't to */ void (*cb)( int sts, void *aux ), void *aux ); + + /* Expunge deleted messages from the current mailbox and close it. + * There is no need to explicitly close a mailbox if no expunge is needed. */ void (*close)( store_t *ctx, /* IMAP-style: expunge inclusive */ void (*cb)( int sts, void *aux ), void *aux ); - void (*cancel)( store_t *ctx, /* only not yet sent commands */ + + /* Cancel queued commands which are not in flight yet; they will have their + * callbacks invoked with DRV_CANCELED. Afterwards, wait for the completion of + * the in-flight commands. If the store is canceled before this command completes, + * the callback will *not* be invoked. */ + void (*cancel)( store_t *ctx, void (*cb)( void *aux ), void *aux ); + + /* Commit any pending set_flags() commands. */ void (*commit)( store_t *ctx ); }; diff --git a/src/sync.c b/src/sync.c @@ -145,13 +145,15 @@ typedef struct { channel_conf_t *chan; store_t *ctx[2]; driver_t *drv[2]; - int state[2], ref_count, ret; + int state[2], ref_count, ret, lfd; int find_old_total[2], find_old_done[2]; int new_total[2], new_done[2]; int find_new_total[2], find_new_done[2]; int flags_total[2], flags_done[2]; int trash_total[2], trash_done[2]; - int maxuid[2], uidval[2], smaxxuid, lfd; + int maxuid[2]; /* highest UID that was already propagated */ + int uidval[2]; /* UID validity value */ + int smaxxuid; /* highest expired UID on slave */ unsigned find:1; } sync_vars_t;