From 7f9ece8e7e834201c247f7c2eca8fc84322f4b71 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Mon, 20 Mar 2006 19:38:20 +0000 Subject: [PATCH] move whole responsibility for recycling open stores/server connections to the drivers. --- src/drv_imap.c | 63 ++++++++++++++++++++++++++++++++++++++--------- src/drv_maildir.c | 25 +++++++++++++------ src/isync.h | 8 ++++-- src/main.c | 34 +++++++++---------------- 4 files changed, 87 insertions(+), 43 deletions(-) diff --git a/src/drv_imap.c b/src/drv_imap.c index 86642b2..3a086ad 100644 --- a/src/drv_imap.c +++ b/src/drv_imap.c @@ -1036,16 +1036,14 @@ get_cmd_result( imap_store_t *ctx, struct imap_cmd *tcmd ) } static void -imap_close_store( store_t *gctx ) +imap_cancel_store( store_t *gctx ) { imap_store_t *ctx = (imap_store_t *)gctx; free_generic_messages( gctx->msgs ); free_string_list( ctx->gen.boxes ); - if (ctx->buf.sock.fd != -1) { - imap_exec( ctx, 0, "LOGOUT" ); + if (ctx->buf.sock.fd >= 0) close( ctx->buf.sock.fd ); - } #ifdef HAVE_LIBSSL if (ctx->SSLContext) SSL_CTX_free( ctx->SSLContext ); @@ -1056,6 +1054,42 @@ imap_close_store( store_t *gctx ) free( ctx ); } +static store_t *unowned; + +static void +imap_disown_store( store_t *gctx ) +{ + free_generic_messages( gctx->msgs ); + gctx->msgs = 0; + gctx->next = unowned; + unowned = gctx; +} + +static store_t * +imap_own_store( store_conf_t *conf ) +{ + store_t *store, **storep; + + for (storep = &unowned; (store = *storep); storep = &store->next) + if (store->conf == conf) { + *storep = store->next; + return store; + } + return 0; +} + +static void +imap_cleanup( void ) +{ + store_t *ctx, *nctx; + + for (ctx = unowned; ctx; ctx = nctx) { + nctx = ctx->next; + imap_exec( (imap_store_t *)ctx, 0, "LOGOUT" ); + imap_cancel_store( ctx ); + } +} + #ifdef HAVE_LIBSSL static int start_tls( imap_store_t *ctx ) @@ -1165,11 +1199,12 @@ do_cram_auth( imap_store_t *ctx, struct imap_cmd *cmdp, const char *prompt ) #endif static store_t * -imap_open_store( store_conf_t *conf, store_t *oldctx ) +imap_open_store( store_conf_t *conf ) { imap_store_conf_t *cfg = (imap_store_conf_t *)conf; imap_server_conf_t *srvc = cfg->server; - imap_store_t *ctx = (imap_store_t *)oldctx; + imap_store_t *ctx; + store_t **ctxp; char *arg, *rsp; struct hostent *he; struct sockaddr_in addr; @@ -1178,16 +1213,17 @@ imap_open_store( store_conf_t *conf, store_t *oldctx ) int use_ssl; #endif - if (ctx) { - if (((imap_store_conf_t *)(ctx->gen.conf))->server == cfg->server) { + for (ctxp = &unowned; (ctx = (imap_store_t *)*ctxp); ctxp = &ctx->gen.next) + if (((imap_store_conf_t *)ctx->gen.conf)->server == srvc) { + *ctxp = ctx->gen.next; + /* One could ping the server here, but given that the idle timeout + * is at least 30 minutes, this sounds pretty pointless. */ free_string_list( ctx->gen.boxes ); ctx->gen.boxes = 0; ctx->gen.listed = 0; ctx->gen.conf = conf; goto final; } - imap_close_store( &ctx->gen ); - } ctx = nfcalloc( sizeof(*ctx) ); ctx->gen.conf = conf; @@ -1372,7 +1408,7 @@ imap_open_store( store_conf_t *conf, store_t *oldctx ) return &ctx->gen; bail: - imap_close_store( &ctx->gen ); + imap_cancel_store( &ctx->gen ); return 0; } @@ -1739,8 +1775,11 @@ imap_parse_store( conffile_t *cfg, store_conf_t **storep, int *err ) struct driver imap_driver = { DRV_CRLF, imap_parse_store, + imap_cleanup, imap_open_store, - imap_close_store, + imap_disown_store, + imap_own_store, + imap_cancel_store, imap_list, imap_prepare_paths, imap_prepare_opts, diff --git a/src/drv_maildir.c b/src/drv_maildir.c index d3b0b3e..0783da1 100644 --- a/src/drv_maildir.c +++ b/src/drv_maildir.c @@ -93,16 +93,12 @@ maildir_parse_flags( const char *base ) return flags; } -static void maildir_close_store( store_t *gctx ); - static store_t * -maildir_open_store( store_conf_t *conf, store_t *oldctx ) +maildir_open_store( store_conf_t *conf ) { maildir_store_t *ctx; struct stat st; - if (oldctx) - maildir_close_store( oldctx ); if (stat( conf->path, &st ) || !S_ISDIR(st.st_mode)) { error( "Maildir error: cannot open store %s\n", conf->path ); return 0; @@ -144,13 +140,25 @@ maildir_cleanup( store_t *gctx ) } static void -maildir_close_store( store_t *gctx ) +maildir_disown_store( store_t *gctx ) { maildir_cleanup( gctx ); free_string_list( gctx->boxes ); free( gctx ); } +static store_t * +maildir_own_store( store_conf_t *conf ) +{ + (void)conf; + return 0; +} + +static void +maildir_cleanup_drv( void ) +{ +} + static int maildir_list( store_t *gctx ) { @@ -1226,8 +1234,11 @@ maildir_parse_store( conffile_t *cfg, store_conf_t **storep, int *err ) struct driver maildir_driver = { 0, maildir_parse_store, + maildir_cleanup_drv, maildir_open_store, - maildir_close_store, + maildir_disown_store, + maildir_own_store, + maildir_disown_store, /* _cancel_, but it's the same */ maildir_list, maildir_prepare_paths, maildir_prepare_opts, diff --git a/src/isync.h b/src/isync.h index 7a06fe2..16bad49 100644 --- a/src/isync.h +++ b/src/isync.h @@ -143,6 +143,7 @@ typedef struct message { #define OPEN_FIND (1<<8) typedef struct store { + struct store *next; store_conf_t *conf; /* foreign */ string_list_t *boxes; /* _list results - own */ unsigned listed:1; /* was _list already run? */ @@ -176,8 +177,11 @@ typedef struct { struct driver { int flags; int (*parse_store)( conffile_t *cfg, store_conf_t **storep, int *err ); - store_t *(*open_store)( store_conf_t *conf, store_t *oldctx ); - void (*close_store)( store_t *ctx ); + void (*cleanup)( void ); + store_t *(*open_store)( store_conf_t *conf ); + void (*disown_store)( store_t *ctx ); + store_t *(*own_store)( store_conf_t *conf ); + void (*cancel_store)( store_t *ctx ); int (*list)( store_t *ctx ); void (*prepare_paths)( store_t *ctx ); void (*prepare_opts)( store_t *ctx, int opts ); diff --git a/src/main.c b/src/main.c index 8cf09cd..4c86fe9 100644 --- a/src/main.c +++ b/src/main.c @@ -190,7 +190,6 @@ int main( int argc, char **argv ) { channel_conf_t *chan; - store_conf_t *conf[2]; group_conf_t *group; driver_t *driver[2]; store_t *ctx[2]; @@ -441,9 +440,6 @@ main( int argc, char **argv ) ret = 0; chan = channels; chanptr = 0; - ctx[M] = ctx[S] = 0; - conf[M] = conf[S] = 0; /* make-gcc-happy */ - driver[M] = driver[S] = 0; /* make-gcc-happy */ if (all) multiple = channels->next != 0; else if (argv[oind + 1]) @@ -486,23 +482,15 @@ main( int argc, char **argv ) merge_actions( chan, ops, XOP_HAVE_EXPUNGE, OP_EXPUNGE, 0 ); boxes[M] = boxes[S] = cboxes = 0; - /* possible todo: handle master <-> slave swaps */ for (t = 0; t < 2; t++) { - if (ctx[t]) { - if (conf[t] == chan->stores[t]) - continue; - if (conf[t]->driver != chan->stores[t]->driver) { - driver[t]->close_store( ctx[t] ); - ctx[t] = 0; - } - } - conf[t] = chan->stores[t]; - driver[t] = conf[t]->driver; - if (!(ctx[t] = driver[t]->open_store( chan->stores[t], ctx[t] ))) { + driver[t] = chan->stores[t]->driver; + ctx[t] = driver[t]->own_store( chan->stores[t] ); + } + for (t = 0; t < 2; t++) + if (!ctx[t] && !(ctx[t] = driver[t]->open_store( chan->stores[t] ))) { ret = 1; goto next; } - } info( "Channel %s\n", chan->name ); if (list && multiple) printf( "%s:\n", chan->name ); @@ -523,7 +511,7 @@ main( int argc, char **argv ) if (!ctx[t]->listed) { if (driver[t]->list( ctx[t] ) != DRV_OK) { screwt: - driver[t]->close_store( ctx[t] ); + driver[t]->cancel_store( ctx[t] ); ctx[t] = 0; ret = 1; goto next; @@ -584,6 +572,10 @@ main( int argc, char **argv ) free_string_list( cboxes ); free_string_list( boxes[M] ); free_string_list( boxes[S] ); + if (ctx[M]) + driver[M]->disown_store( ctx[M] ); + if (ctx[S]) + driver[S]->disown_store( ctx[S] ); if (all) { if (!(chan = chan->next)) break; @@ -595,10 +587,8 @@ main( int argc, char **argv ) break; } } - if (ctx[S]) - driver[S]->close_store( ctx[S] ); - if (ctx[M]) - driver[M]->close_store( ctx[M] ); + for (t = 0; t < N_DRIVERS; t++) + drivers[t]->cleanup(); return ret; }