commit eaa44a9a7e37547ca6eb8ac9b5f133612eb9b3c7
Author: Oswald Buddenhagen <[email protected]>
Date: Sun Mar 13 15:53:23 2011 +0100
replace DRV_STORE_BAD with a separate bad_callback()
that way we don't have to piggy-back (possibly asynchronous) fatal
errors to particular commands.
src/drv_imap.c | 71 ++++++++++++++-------------------------------
src/drv_maildir.c | 16 ++++++----
src/isync.h | 19 +++++++++++-
src/main.c | 21 +++++++++----
src/sync.c | 48 ++++++++++++++----------------
5 files changed, 86 insertions(+), 89 deletions(-)
diff --git a/src/drv_imap.c b/src/drv_imap.c
index 9602260..5f9450d 100644
--- a/src/drv_imap.c
+++ b/src/drv_imap.c
@@ -214,8 +214,7 @@ static const char *cap_list[] = {
#define RESP_OK 0
#define RESP_NO 1
-#define RESP_BAD 2
-#define RESP_CANCEL 3
+#define RESP_CANCEL 2
static void get_cmd_result( imap_store_t *ctx, struct imap_cmd *tcmd );
@@ -561,6 +560,7 @@ v_submit_imap_cmd( imap_store_t *ctx, struct imap_cmd *cmd,
char buf[1024];
assert( ctx );
+ assert( ctx->gen.bad_callback );
assert( cmd );
assert( cmd->param.done );
@@ -568,11 +568,8 @@ v_submit_imap_cmd( imap_store_t *ctx, struct imap_cmd *cmd,
while (ctx->literal_pending) {
get_cmd_result( ctx, 0 );
- if (ctx->store_canceled) {
- /* ctx (and thus the queue) is invalid by now. */
- cmd->param.done( 0, cmd, RESP_CANCEL );
+ if (ctx->store_canceled)
goto bail2;
- }
}
if (ctx->buf.sock.fd < 0)
@@ -622,8 +619,9 @@ v_submit_imap_cmd( imap_store_t *ctx, struct imap_cmd *cmd,
return cmd;
bail:
- cmd->param.done( ctx, cmd, RESP_BAD );
+ ctx->gen.bad_callback( ctx->gen.bad_callback_aux );
bail2:
+ cmd->param.done( ctx, cmd, RESP_CANCEL );
free( cmd->cmd );
free( cmd );
deref_store( ctx );
@@ -666,7 +664,6 @@ transform_box_response( int *response )
{
switch (*response) {
case RESP_CANCEL: *response = DRV_CANCELED; break;
- case RESP_BAD: *response = DRV_STORE_BAD; break;
case RESP_NO: *response = DRV_BOX_BAD; break;
default: *response = DRV_OK; break;
}
@@ -687,7 +684,6 @@ transform_msg_response( int *response )
{
switch (*response) {
case RESP_CANCEL: *response = DRV_CANCELED; break;
- case RESP_BAD: *response = DRV_STORE_BAD; break;
case RESP_NO: *response = DRV_MSG_BAD; break;
default: *response = DRV_OK; break;
}
@@ -1000,7 +996,7 @@ parse_response_code( imap_store_t *ctx, struct imap_cmd
*cmd, char *s )
s++;
if (!(p = strchr( s, ']' ))) {
error( "IMAP error: malformed response code\n" );
- return RESP_BAD;
+ return RESP_CANCEL;
}
*p++ = 0;
arg = next_arg( &s );
@@ -1009,12 +1005,12 @@ parse_response_code( imap_store_t *ctx, struct imap_cmd
*cmd, char *s )
(ctx->gen.uidvalidity = strtoll( arg, &earg, 10 ), *earg))
{
error( "IMAP error: malformed UIDVALIDITY status\n" );
- return RESP_BAD;
+ return RESP_CANCEL;
}
} else if (!strcmp( "UIDNEXT", arg )) {
if (!(arg = next_arg( &s )) || (ctx->uidnext = strtol( arg, &p,
10 ), *p)) {
error( "IMAP error: malformed NEXTUID status\n" );
- return RESP_BAD;
+ return RESP_CANCEL;
}
} else if (!strcmp( "CAPABILITY", arg )) {
parse_capability( ctx, s );
@@ -1031,7 +1027,7 @@ parse_response_code( imap_store_t *ctx, struct imap_cmd
*cmd, char *s )
!(((struct imap_cmd_out_uid *)cmd)->out_uid = atoi( arg )))
{
error( "IMAP error: malformed APPENDUID status\n" );
- return RESP_BAD;
+ return RESP_CANCEL;
}
}
return RESP_OK;
@@ -1210,13 +1206,15 @@ get_cmd_result( imap_store_t *ctx, struct imap_cmd
*tcmd )
}
resp = RESP_NO;
} else /*if (!strcmp( "BAD", arg ))*/
- resp = RESP_BAD;
+ resp = RESP_CANCEL;
error( "IMAP command '%s' returned an error: %s
%s\n",
memcmp( cmdp->cmd, "LOGIN", 5 ) ?
cmdp->cmd : "LOGIN <user> <pass>",
arg, cmd ? cmd : "" );
}
if ((resp2 = parse_response_code( ctx, cmdp, cmd )) >
resp)
resp = resp2;
+ if (resp == RESP_CANCEL)
+ ctx->gen.bad_callback(
ctx->gen.bad_callback_aux );
cmdp->param.done( ctx, cmdp, resp );
free( cmdp->param.data );
free( cmdp->cmd );
@@ -1228,22 +1226,7 @@ get_cmd_result( imap_store_t *ctx, struct imap_cmd *tcmd
)
return;
}
}
- /* Piggy-back the stream error on the next pending command. */
- if ((cmdp = ctx->in_progress)) {
- ctx->in_progress = cmdp->next; /* We're dead, so don't update
in_progress_append */
- ctx->num_in_progress--;
- cmdp->param.done( ctx, cmdp, RESP_BAD );
- free( cmdp->param.data );
- free( cmdp->cmd );
- free( cmdp );
- deref_store( ctx );
- return;
- }
- /* Made no callback, so let the next command submission fail. */
- if (ctx->buf.sock.fd != -1) {
- close( ctx->buf.sock.fd );
- ctx->buf.sock.fd = -1;
- }
+ ctx->gen.bad_callback( ctx->gen.bad_callback_aux );
}
static void
@@ -1324,6 +1307,7 @@ imap_cleanup( void )
for (ctx = unowned; ctx; ctx = nctx) {
nctx = ctx->next;
+ set_bad_callback( ctx, (void (*)(void *))imap_cancel_store, ctx
);
imap_exec( (imap_store_t *)ctx, 0, imap_cleanup_p2, "LOGOUT" );
}
}
@@ -1480,6 +1464,7 @@ imap_open_store( store_conf_t *conf,
ctx->gen.conf = conf;
ctx->callbacks.imap_open = cb;
ctx->callback_aux = aux;
+ set_bad_callback( &ctx->gen, (void (*)(void
*))imap_open_store_bail, ctx );
imap_open_store_namespace( ctx );
return;
}
@@ -1490,6 +1475,7 @@ imap_open_store( store_conf_t *conf,
ctx->buf.sock.fd = -1;
ctx->callbacks.imap_open = cb;
ctx->callback_aux = aux;
+ set_bad_callback( &ctx->gen, (void (*)(void *))imap_open_store_bail,
ctx );
ctx->in_progress_append = &ctx->in_progress;
/* open connection to IMAP server */
@@ -1759,6 +1745,7 @@ imap_open_store_namespace2( imap_store_t *ctx )
static void
imap_open_store_finalize( imap_store_t *ctx )
{
+ set_bad_callback( &ctx->gen, 0, 0 );
ctx->trashnc = 1;
ctx->callbacks.imap_open( &ctx->gen, ctx->callback_aux );
}
@@ -1914,16 +1901,11 @@ imap_select2_p2( imap_store_t *ctx ATTR_UNUSED, struct
imap_cmd *cmd, int respon
switch (response) {
case RESP_CANCEL:
- /* sts was already free()d by the BAD callback. We can do that,
because we know
- * that our fetches are the only commands in flight, so nothing
else can cause a
- * cancelation. */
- return;
- case RESP_BAD:
- sts->ret_val = DRV_STORE_BAD;
- imap_refcounted_done( sts );
- return;
+ sts->ret_val = DRV_CANCELED;
+ break;
case RESP_NO:
- sts->ret_val = DRV_BOX_BAD;
+ if (sts->ret_val == DRV_OK) /* Don't override cancelation. */
+ sts->ret_val = DRV_BOX_BAD;
break;
}
if (!--sts->ref_count)
@@ -2024,17 +2006,8 @@ imap_set_flags_p2( imap_store_t *ctx ATTR_UNUSED, struct
imap_cmd *cmd, int resp
struct imap_cmd_refcounted_state *sts = ((struct imap_cmd_refcounted
*)cmd)->state;
switch (response) {
case RESP_CANCEL:
- if (sts->ret_val == DRV_STORE_BAD)
- goto badout; /* Our own command's bad-store callback
caused cancelation. */
- sts->ret_val = DRV_CANCELED; /* Unrelated command caused
cancelation. */
+ sts->ret_val = DRV_CANCELED;
break;
- case RESP_BAD:
- sts->ret_val = DRV_STORE_BAD;
- sts->callback( sts->ret_val, sts->callback_aux );
- badout:
- if (!--sts->ref_count)
- free( sts );
- return;
case RESP_NO:
if (sts->ret_val == DRV_OK) /* Don't override cancelation. */
sts->ret_val = DRV_MSG_BAD;
diff --git a/src/drv_maildir.c b/src/drv_maildir.c
index d157be7..301c6a4 100644
--- a/src/drv_maildir.c
+++ b/src/drv_maildir.c
@@ -168,7 +168,8 @@ maildir_list( store_t *gctx,
if (!(dir = opendir( gctx->conf->path ))) {
error( "%s: %s\n", gctx->conf->path, strerror(errno) );
- cb( DRV_STORE_BAD, aux );
+ gctx->bad_callback( gctx->bad_callback_aux );
+ cb( DRV_CANCELED, aux );
return;
}
while ((de = readdir( dir ))) {
@@ -220,7 +221,7 @@ maildir_free_scan( msglist_t *msglist )
#define _24_HOURS (3600 * 24)
static int
-maildir_validate( const char *prefix, const char *box, int create )
+maildir_validate( const char *prefix, const char *box, int create,
maildir_store_t *ctx )
{
DIR *dirp;
struct dirent *entry;
@@ -236,7 +237,8 @@ maildir_validate( const char *prefix, const char *box, int
create )
if (mkdir( buf, 0700 )) {
error( "Maildir error: mkdir %s: %s
(errno %d)\n",
buf, strerror(errno), errno );
- return DRV_STORE_BAD;
+ ctx->gen.bad_callback(
ctx->gen.bad_callback_aux );
+ return DRV_CANCELED;
}
mkdirs:
for (i = 0; i < 3; i++) {
@@ -782,8 +784,8 @@ maildir_select( store_t *gctx, int minuid, int maxuid, int
*excs, int nexcs,
ctx->excs = nfrealloc( excs, nexcs * sizeof(int) );
ctx->nexcs = nexcs;
- if (maildir_validate( gctx->path, "", ctx->gen.opts & OPEN_CREATE ) !=
DRV_OK) {
- cb( DRV_BOX_BAD, aux );
+ if ((ret = maildir_validate( gctx->path, "", ctx->gen.opts &
OPEN_CREATE, ctx )) != DRV_OK) {
+ cb( ret, aux );
return;
}
@@ -1022,7 +1024,7 @@ maildir_store_msg( store_t *gctx, msg_data_t *data, int
to_trash,
cb( DRV_BOX_BAD, 0, aux );
return;
}
- if ((ret = maildir_validate( gctx->conf->path,
gctx->conf->trash, gctx->opts & OPEN_CREATE )) != DRV_OK) {
+ if ((ret = maildir_validate( gctx->conf->path,
gctx->conf->trash, gctx->opts & OPEN_CREATE, ctx )) != DRV_OK) {
free( data->data );
cb( ret, 0, aux );
return;
@@ -1166,7 +1168,7 @@ maildir_trash_msg( store_t *gctx, message_t *gmsg,
if (!rename( buf, nbuf ))
break;
if (!stat( buf, &st )) {
- if ((ret = maildir_validate( gctx->conf->path,
gctx->conf->trash, 1 )) != DRV_OK) {
+ if ((ret = maildir_validate( gctx->conf->path,
gctx->conf->trash, 1, ctx )) != DRV_OK) {
cb( ret, aux );
return;
}
diff --git a/src/isync.h b/src/isync.h
index 8dc60d1..b34f08c 100644
--- a/src/isync.h
+++ b/src/isync.h
@@ -44,6 +44,12 @@
# define ATTR_PRINTFLIKE(fmt,var)
#endif
+#ifdef __GNUC__
+# define INLINE __inline__
+#else
+# define INLINE
+#endif
+
#define EXE "mbsync"
typedef struct {
@@ -148,6 +154,9 @@ typedef struct store {
string_list_t *boxes; /* _list results - own */
unsigned listed:1; /* was _list already run? */
+ void (*bad_callback)( void *aux );
+ void *bad_callback_aux;
+
/* currently open mailbox */
const char *name; /* foreign! maybe preset? */
char *path; /* own */
@@ -159,6 +168,13 @@ typedef struct store {
int recent; /* # of recent messages - don't trust this beyond the
initial read */
} store_t;
+static INLINE void
+set_bad_callback( store_t *ctx, void (*cb)( void *aux ), void *aux )
+{
+ ctx->bad_callback = cb;
+ ctx->bad_callback_aux = aux;
+}
+
typedef struct {
char *data;
int len;
@@ -168,8 +184,7 @@ typedef struct {
#define DRV_OK 0
#define DRV_MSG_BAD 1
#define DRV_BOX_BAD 2
-#define DRV_STORE_BAD 3
-#define DRV_CANCELED 4
+#define DRV_CANCELED 3
/* All memory belongs to the driver's user. */
diff --git a/src/main.c b/src/main.c
index 4776fc7..afe365d 100644
--- a/src/main.c
+++ b/src/main.c
@@ -673,6 +673,17 @@ sync_chans( main_vars_t *mvars, int ent )
}
static void
+store_bad( void *aux )
+{
+ MVARS(aux)
+
+ mvars->drv[t]->cancel_store( mvars->ctx[t] );
+ mvars->ret = mvars->skip = 1;
+ mvars->state[t] = ST_CLOSED;
+ sync_chans( mvars, E_OPEN );
+}
+
+static void
store_opened( store_t *ctx, void *aux )
{
MVARS(aux)
@@ -689,9 +700,10 @@ store_opened( store_t *ctx, void *aux )
sync_chans( mvars, E_OPEN );
return;
}
- if (!mvars->boxlist && mvars->chan->patterns && !ctx->listed)
+ if (!mvars->boxlist && mvars->chan->patterns && !ctx->listed) {
+ set_bad_callback( ctx, store_bad, AUX );
mvars->drv[t]->list( ctx, store_listed, AUX );
- else {
+ } else {
mvars->state[t] = ST_OPEN;
sync_chans( mvars, E_OPEN );
}
@@ -702,19 +714,16 @@ store_listed( int sts, void *aux )
{
MVARS(aux)
- mvars->state[t] = ST_OPEN;
switch (sts) {
case DRV_OK:
if (mvars->ctx[t]->conf->map_inbox)
add_string_list( &mvars->ctx[t]->boxes,
mvars->ctx[t]->conf->map_inbox );
break;
- case DRV_STORE_BAD:
- mvars->drv[t]->cancel_store( mvars->ctx[t] );
- mvars->state[t] = ST_CLOSED;
default:
mvars->ret = mvars->skip = 1;
break;
}
+ mvars->state[t] = ST_OPEN;
sync_chans( mvars, E_OPEN );
}
diff --git a/src/sync.c b/src/sync.c
index b3f57cd..9e73b98 100644
--- a/src/sync.c
+++ b/src/sync.c
@@ -328,9 +328,6 @@ msg_fetched( int sts, void *aux )
case DRV_MSG_BAD:
vars->cb( SYNC_NOGOOD, 0, vars );
break;
- case DRV_STORE_BAD:
- vars->cb( SYNC_BAD(1-t), 0, vars );
- break;
default:
vars->cb( SYNC_FAIL, 0, vars );
break;
@@ -356,9 +353,6 @@ msg_stored( int sts, int uid, void *aux )
str_ms[t], vars->msg->uid, str_ms[1-t] );
vars->cb( SYNC_NOGOOD, 0, vars );
break;
- case DRV_STORE_BAD:
- vars->cb( SYNC_BAD(t), 0, vars );
- break;
default:
vars->cb( SYNC_FAIL, 0, vars );
break;
@@ -405,11 +399,6 @@ cancel_sync( sync_vars_t *svars )
svars->cancel = 1;
for (t = 0; t < 2; t++)
if (svars->ret & SYNC_BAD(t)) {
- if (svars->ctx[t]) {
- /* this should never recurse into cancel_sync()
*/
- svars->drv[t]->cancel_store( svars->ctx[t] );
- svars->ctx[t] = 0;
- }
cancel_done( AUX );
} else if (!(svars->state[t] & ST_SENT_CANCEL)) {
/* ignore subsequent failures from in-flight commands */
@@ -431,17 +420,22 @@ cancel_done( void *aux )
}
}
+static void
+store_bad( void *aux )
+{
+ SVARS(aux)
+
+ svars->ret |= SYNC_BAD(t);
+ svars->drv[t]->cancel_store( svars->ctx[t] );
+ cancel_sync( svars );
+}
static int
-check_ret( int sts, sync_vars_t *svars, int t )
+check_ret( int sts, sync_vars_t *svars )
{
switch (sts) {
case DRV_CANCELED:
return 1;
- case DRV_STORE_BAD:
- svars->ret |= SYNC_BAD(t);
- cancel_sync( svars );
- return 1;
case DRV_BOX_BAD:
svars->ret |= SYNC_FAIL;
cancel_sync( svars );
@@ -451,9 +445,9 @@ check_ret( int sts, sync_vars_t *svars, int t )
}
static int
-check_ret_aux( int sts, sync_vars_t *svars, int t, void *aux )
+check_ret_aux( int sts, sync_vars_t *svars, void *aux )
{
- if (!check_ret( sts, svars, t ))
+ if (!check_ret( sts, svars ))
return 0;
free( aux );
return 1;
@@ -507,6 +501,7 @@ sync_boxes( store_t *ctx[], const char *names[],
channel_conf_t *chan,
(!names[t] || (ctx[t]->conf->map_inbox && !strcmp(
ctx[t]->conf->map_inbox, names[t] ))) ?
"INBOX" : names[t];
ctx[t]->uidvalidity = -1;
+ set_bad_callback( ctx[t], store_bad, AUX );
svars->drv[t] = ctx[t]->conf->driver;
svars->drv[t]->prepare_paths( ctx[t] );
}
@@ -891,7 +886,7 @@ box_selected( int sts, void *aux )
find_vars_t *fv;
sync_rec_t *srec;
- if (check_ret( sts, svars, t ))
+ if (check_ret( sts, svars ))
return;
if (svars->uidval[t] >= 0 && svars->uidval[t] !=
svars->ctx[t]->uidvalidity) {
error( "Error: UIDVALIDITY of %s changed (got %d, expected
%d)\n",
@@ -937,7 +932,7 @@ msg_found_sel( int sts, int uid, void *aux )
find_vars_t *vars = (find_vars_t *)aux;
SVARS(vars->aux)
- if (check_ret_aux( sts, svars, t, vars ))
+ if (check_ret_aux( sts, svars, vars ))
return;
switch (sts) {
case DRV_OK:
@@ -1409,7 +1404,7 @@ msg_found_new( int sts, int uid, void *aux )
find_vars_t *vars = (find_vars_t *)aux;
SVARS(vars->aux)
- if (check_ret_aux( sts, svars, t, vars ))
+ if (check_ret_aux( sts, svars, vars ))
return;
switch (sts) {
case DRV_OK:
@@ -1435,7 +1430,7 @@ flags_set_del( int sts, void *aux )
flag_vars_t *vars = (flag_vars_t *)aux;
SVARS(vars->aux)
- if (check_ret_aux( sts, svars, t, vars ))
+ if (check_ret_aux( sts, svars, vars ))
return;
switch (sts) {
case DRV_OK:
@@ -1456,7 +1451,7 @@ flags_set_sync( int sts, void *aux )
flag_vars_t *vars = (flag_vars_t *)aux;
SVARS(vars->aux)
- if (check_ret_aux( sts, svars, t, vars ))
+ if (check_ret_aux( sts, svars, vars ))
return;
switch (sts) {
case DRV_OK:
@@ -1559,7 +1554,7 @@ msg_trashed( int sts, void *aux )
if (sts == DRV_MSG_BAD)
sts = DRV_BOX_BAD;
- if (check_ret( sts, svars, t ))
+ if (check_ret( sts, svars ))
return;
svars->trash_done[t]++;
stats( svars );
@@ -1613,7 +1608,7 @@ box_closed( int sts, void *aux )
{
SVARS(aux)
- if (check_ret( sts, svars, t ))
+ if (check_ret( sts, svars ))
return;
svars->state[t] |= ST_DID_EXPUNGE;
box_closed_p2( svars, t );
@@ -1717,6 +1712,9 @@ sync_bail2( sync_vars_t *svars )
void *aux = svars->aux;
int ret = svars->ret;
+ set_bad_callback( svars->ctx[0], 0, 0 );
+ set_bad_callback( svars->ctx[1], 0, 0 );
+
free( svars->lname );
free( svars->nname );
free( svars->jname );
------------------------------------------------------------------------------
Colocation vs. Managed Hosting
A question and answer guide to determining the best fit
for your organization - today and in the future.
http://p.sf.net/sfu/internap-sfd2d
_______________________________________________
isync-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/isync-devel