Browse Source

make the driver model, sync_chans() and sync_boxes() fully async.

async drivers to follow ...
wip/maildir-uid-dupes-test
Oswald Buddenhagen 19 years ago
parent
commit
168e5f3282
  1. 183
      src/drv_imap.c
  2. 198
      src/drv_maildir.c
  3. 53
      src/isync.h
  4. 222
      src/main.c
  5. 1131
      src/sync.c
  6. 12
      src/util.c

183
src/drv_imap.c

@ -1199,8 +1199,9 @@ do_cram_auth( imap_store_t *ctx, struct imap_cmd *cmdp, const char *prompt )
} }
#endif #endif
static store_t * static void
imap_open_store( store_conf_t *conf ) imap_open_store( store_conf_t *conf,
void (*cb)( store_t *srv, void *aux ), void *aux )
{ {
imap_store_conf_t *cfg = (imap_store_conf_t *)conf; imap_store_conf_t *cfg = (imap_store_conf_t *)conf;
imap_server_conf_t *srvc = cfg->server; imap_server_conf_t *srvc = cfg->server;
@ -1367,12 +1368,12 @@ imap_open_store( store_conf_t *conf )
} }
#if HAVE_LIBSSL #if HAVE_LIBSSL
if (CAP(CRAM)) { if (CAP(CRAM)) {
struct imap_cmd_cb cb; struct imap_cmd_cb cbd;
info( "Authenticating with CRAM-MD5\n" ); info( "Authenticating with CRAM-MD5\n" );
memset( &cb, 0, sizeof(cb) ); memset( &cbd, 0, sizeof(cbd) );
cb.cont = do_cram_auth; cbd.cont = do_cram_auth;
if (imap_exec( ctx, &cb, "AUTHENTICATE CRAM-MD5" ) != RESP_OK) if (imap_exec( ctx, &cbd, "AUTHENTICATE CRAM-MD5" ) != RESP_OK)
goto bail; goto bail;
} else if (srvc->require_cram) { } else if (srvc->require_cram) {
error( "IMAP error: CRAM-MD5 authentication is not supported by server\n" ); error( "IMAP error: CRAM-MD5 authentication is not supported by server\n" );
@ -1402,8 +1403,10 @@ imap_open_store( store_conf_t *conf )
else if (cfg->use_namespace && CAP(NAMESPACE)) { else if (cfg->use_namespace && CAP(NAMESPACE)) {
/* get NAMESPACE info */ /* get NAMESPACE info */
if (!ctx->got_namespace) { if (!ctx->got_namespace) {
if (imap_exec( ctx, 0, "NAMESPACE" ) != RESP_OK) if (imap_exec( ctx, 0, "NAMESPACE" ) != RESP_OK) {
goto bail; cb( 0, aux );
return;
}
ctx->got_namespace = 1; ctx->got_namespace = 1;
} }
/* XXX for now assume personal namespace */ /* XXX for now assume personal namespace */
@ -1413,11 +1416,13 @@ imap_open_store( store_conf_t *conf )
ctx->prefix = ctx->ns_personal->child->child->val; ctx->prefix = ctx->ns_personal->child->child->val;
} }
ctx->trashnc = 1; ctx->trashnc = 1;
return &ctx->gen; cb( &ctx->gen, aux );
return;
bail: bail:
imap_cancel_store( &ctx->gen ); imap_cancel_store( &ctx->gen );
return 0; cb( 0, aux );
return;
} }
static void static void
@ -1433,13 +1438,14 @@ imap_prepare_opts( store_t *gctx, int opts )
gctx->opts = opts; gctx->opts = opts;
} }
static int static void
imap_select( store_t *gctx, int minuid, int maxuid, int *excs, int nexcs ) imap_select( store_t *gctx, int minuid, int maxuid, int *excs, int nexcs,
void (*cb)( int sts, void *aux ), void *aux )
{ {
imap_store_t *ctx = (imap_store_t *)gctx; imap_store_t *ctx = (imap_store_t *)gctx;
const char *prefix; const char *prefix;
int ret, i, j, bl; int ret, i, j, bl;
struct imap_cmd_cb cb; struct imap_cmd_cb cbd;
char buf[1000]; char buf[1000];
@ -1451,10 +1457,10 @@ imap_select( store_t *gctx, int minuid, int maxuid, int *excs, int nexcs )
prefix = ctx->prefix; prefix = ctx->prefix;
} }
memset( &cb, 0, sizeof(cb) ); memset( &cbd, 0, sizeof(cbd) );
cb.create = (gctx->opts & OPEN_CREATE) != 0; cbd.create = (gctx->opts & OPEN_CREATE) != 0;
cb.trycreate = 1; cbd.trycreate = 1;
if ((ret = imap_exec_b( ctx, &cb, "SELECT \"%s%s\"", prefix, gctx->name )) != DRV_OK) if ((ret = imap_exec_b( ctx, &cbd, "SELECT \"%s%s\"", prefix, gctx->name )) != DRV_OK)
goto bail; goto bail;
if (gctx->count) { if (gctx->count) {
@ -1489,19 +1495,20 @@ imap_select( store_t *gctx, int minuid, int maxuid, int *excs, int nexcs )
bail: bail:
if (excs) if (excs)
free( excs ); free( excs );
return ret; cb( ret, aux );
} }
static int static void
imap_fetch_msg( store_t *ctx, message_t *msg, msg_data_t *data ) imap_fetch_msg( store_t *ctx, message_t *msg, msg_data_t *data,
void (*cb)( int sts, void *aux ), void *aux )
{ {
struct imap_cmd_cb cb; struct imap_cmd_cb cbd;
memset( &cb, 0, sizeof(cb) ); memset( &cbd, 0, sizeof(cbd) );
cb.uid = msg->uid; cbd.uid = msg->uid;
cb.ctx = data; cbd.ctx = data;
return imap_exec_m( (imap_store_t *)ctx, &cb, "UID FETCH %d (%sBODY.PEEK[])", cb( imap_exec_m( (imap_store_t *)ctx, &cbd, "UID FETCH %d (%sBODY.PEEK[])",
msg->uid, (msg->status & M_FLAGS) ? "" : "FLAGS " ); msg->uid, (msg->status & M_FLAGS) ? "" : "FLAGS " ), aux );
} }
static int static int
@ -1531,8 +1538,9 @@ imap_flags_helper( imap_store_t *ctx, int uid, char what, int flags)
return issue_imap_cmd_w( ctx, 0, "UID STORE %d %cFLAGS.SILENT %s", uid, what, buf ) ? DRV_OK : DRV_STORE_BAD; return issue_imap_cmd_w( ctx, 0, "UID STORE %d %cFLAGS.SILENT %s", uid, what, buf ) ? DRV_OK : DRV_STORE_BAD;
} }
static int static void
imap_set_flags( store_t *gctx, message_t *msg, int uid, int add, int del ) imap_set_flags( store_t *gctx, message_t *msg, int uid, int add, int del,
void (*cb)( int sts, void *aux ), void *aux )
{ {
imap_store_t *ctx = (imap_store_t *)gctx; imap_store_t *ctx = (imap_store_t *)gctx;
int ret; int ret;
@ -1546,35 +1554,38 @@ imap_set_flags( store_t *gctx, message_t *msg, int uid, int add, int del )
} }
if ((!add || (ret = imap_flags_helper( ctx, uid, '+', add )) == DRV_OK) && if ((!add || (ret = imap_flags_helper( ctx, uid, '+', add )) == DRV_OK) &&
(!del || (ret = imap_flags_helper( ctx, uid, '-', del )) == DRV_OK)) (!del || (ret = imap_flags_helper( ctx, uid, '-', del )) == DRV_OK))
return DRV_OK; ret = DRV_OK;
return ret; cb( ret, aux );
} }
static int static void
imap_close( store_t *ctx ) imap_close( store_t *ctx,
void (*cb)( int sts, void *aux ), void *aux )
{ {
return imap_exec_b( (imap_store_t *)ctx, 0, "CLOSE" ); cb( imap_exec_b( (imap_store_t *)ctx, 0, "CLOSE" ), aux );
} }
static int static void
imap_trash_msg( store_t *gctx, message_t *msg ) imap_trash_msg( store_t *gctx, message_t *msg,
void (*cb)( int sts, void *aux ), void *aux )
{ {
imap_store_t *ctx = (imap_store_t *)gctx; imap_store_t *ctx = (imap_store_t *)gctx;
struct imap_cmd_cb cb; struct imap_cmd_cb cbd;
memset( &cb, 0, sizeof(cb) ); memset( &cbd, 0, sizeof(cbd) );
cb.create = 1; cbd.create = 1;
return imap_exec_m( ctx, &cb, "UID COPY %d \"%s%s\"", cb( imap_exec_m( ctx, &cbd, "UID COPY %d \"%s%s\"",
msg->uid, ctx->prefix, gctx->conf->trash ); msg->uid, ctx->prefix, gctx->conf->trash ), aux );
} }
static int static void
imap_store_msg( store_t *gctx, msg_data_t *data, int *uid ) imap_store_msg( store_t *gctx, msg_data_t *data, int to_trash,
void (*cb)( int sts, int uid, void *aux ), void *aux )
{ {
imap_store_t *ctx = (imap_store_t *)gctx; imap_store_t *ctx = (imap_store_t *)gctx;
struct imap_cmd_cb cb; struct imap_cmd_cb cbd;
const char *prefix, *box; const char *prefix, *box;
int ret, d; int ret, d, uid;
char flagstr[128]; char flagstr[128];
d = 0; d = 0;
@ -1584,71 +1595,82 @@ imap_store_msg( store_t *gctx, msg_data_t *data, int *uid )
} }
flagstr[d] = 0; flagstr[d] = 0;
memset( &cb, 0, sizeof(cb) ); memset( &cbd, 0, sizeof(cbd) );
cb.dlen = data->len; cbd.dlen = data->len;
cb.data = data->data; cbd.data = data->data;
if (!uid) { cbd.ctx = &uid;
uid = -2;
if (to_trash) {
box = gctx->conf->trash; box = gctx->conf->trash;
prefix = ctx->prefix; prefix = ctx->prefix;
cb.create = 1; cbd.create = 1;
if (ctx->trashnc) if (ctx->trashnc)
ctx->caps = ctx->rcaps & ~(1 << LITERALPLUS); ctx->caps = ctx->rcaps & ~(1 << LITERALPLUS);
} else { } else {
box = gctx->name; box = gctx->name;
prefix = !strcmp( box, "INBOX" ) ? "" : ctx->prefix; prefix = !strcmp( box, "INBOX" ) ? "" : ctx->prefix;
cb.create = (gctx->opts & OPEN_CREATE) != 0; cbd.create = (gctx->opts & OPEN_CREATE) != 0;
/*if (ctx->currentnc) /*if (ctx->currentnc)
ctx->caps = ctx->rcaps & ~(1 << LITERALPLUS);*/ ctx->caps = ctx->rcaps & ~(1 << LITERALPLUS);*/
*uid = -2;
} }
cb.ctx = uid; ret = imap_exec_m( ctx, &cbd, "APPEND \"%s%s\" %s", prefix, box, flagstr );
ret = imap_exec_m( ctx, &cb, "APPEND \"%s%s\" %s", prefix, box, flagstr );
ctx->caps = ctx->rcaps; ctx->caps = ctx->rcaps;
if (ret != DRV_OK) if (ret != DRV_OK) {
return ret; cb( ret, -1, aux );
if (!uid) return;
}
if (to_trash)
ctx->trashnc = 0; ctx->trashnc = 0;
else { else {
/*ctx->currentnc = 0;*/ /*ctx->currentnc = 0;*/
gctx->count++;
} }
return DRV_OK; cb( DRV_OK, uid, aux );
} }
static int static void
imap_find_msg( store_t *gctx, const char *tuid, int *uid ) imap_find_msg( store_t *gctx, const char *tuid,
void (*cb)( int sts, int uid, void *aux ), void *aux )
{ {
imap_store_t *ctx = (imap_store_t *)gctx; imap_store_t *ctx = (imap_store_t *)gctx;
struct imap_cmd_cb cb; struct imap_cmd_cb cbd;
int ret; int ret, uid;
memset( &cb, 0, sizeof(cb) ); memset( &cbd, 0, sizeof(cbd) );
cb.ctx = uid; cbd.uid = -1; /* we're looking for a UID */
cb.uid = -1; /* we're looking for a UID */ cbd.ctx = &uid;
*uid = -1; /* in case we get no SEARCH response at all */ uid = -1; /* in case we get no SEARCH response at all */
if ((ret = imap_exec_m( ctx, &cb, "UID SEARCH HEADER X-TUID %." stringify(TUIDL) "s", tuid )) != DRV_OK) if ((ret = imap_exec_m( ctx, &cbd, "UID SEARCH HEADER X-TUID %." stringify(TUIDL) "s", tuid )) != DRV_OK)
return ret; cb( ret, -1, aux );
return *uid < 0 ? DRV_MSG_BAD : DRV_OK; else
cb( uid <= 0 ? DRV_MSG_BAD : DRV_OK, uid, aux );
} }
static int static void
imap_list( store_t *gctx ) imap_list( store_t *gctx,
void (*cb)( int sts, void *aux ), void *aux )
{ {
imap_store_t *ctx = (imap_store_t *)gctx; imap_store_t *ctx = (imap_store_t *)gctx;
int ret; int ret;
if ((ret = imap_exec_b( ctx, 0, "LIST \"\" \"%s%%\"", ctx->prefix )) == DRV_OK) if ((ret = imap_exec_b( ctx, 0, "LIST \"\" \"%s%%\"", ctx->prefix )) == DRV_OK)
gctx->listed = 1; gctx->listed = 1;
return ret; cb( ret, aux );
} }
static int static void
imap_check( store_t *gctx ) imap_cancel( store_t *gctx,
void (*cb)( int sts, void *aux ), void *aux )
{ {
(void) gctx; (void)gctx;
/* flush queue here */ cb( DRV_OK, aux );
return DRV_OK; }
static void
imap_commit( store_t *gctx )
{
(void)gctx;
} }
imap_server_conf_t *servers, **serverapp = &servers; imap_server_conf_t *servers, **serverapp = &servers;
@ -1797,6 +1819,7 @@ struct driver imap_driver = {
imap_find_msg, imap_find_msg,
imap_set_flags, imap_set_flags,
imap_trash_msg, imap_trash_msg,
imap_check, imap_close,
imap_close imap_cancel,
imap_commit,
}; };

198
src/drv_maildir.c

@ -93,20 +93,22 @@ maildir_parse_flags( const char *base )
return flags; return flags;
} }
static store_t * static void
maildir_open_store( store_conf_t *conf ) maildir_open_store( store_conf_t *conf,
void (*cb)( store_t *ctx, void *aux ), void *aux )
{ {
maildir_store_t *ctx; maildir_store_t *ctx;
struct stat st; struct stat st;
if (stat( conf->path, &st ) || !S_ISDIR(st.st_mode)) { if (stat( conf->path, &st ) || !S_ISDIR(st.st_mode)) {
error( "Maildir error: cannot open store %s\n", conf->path ); error( "Maildir error: cannot open store %s\n", conf->path );
return 0; cb( 0, aux );
return;
} }
ctx = nfcalloc( sizeof(*ctx) ); ctx = nfcalloc( sizeof(*ctx) );
ctx->gen.conf = conf; ctx->gen.conf = conf;
ctx->uvfd = -1; ctx->uvfd = -1;
return &ctx->gen; cb( &ctx->gen, aux );
} }
static void static void
@ -159,15 +161,17 @@ maildir_cleanup_drv( void )
{ {
} }
static int static void
maildir_list( store_t *gctx ) maildir_list( store_t *gctx,
void (*cb)( int sts, void *aux ), void *aux )
{ {
DIR *dir; DIR *dir;
struct dirent *de; struct dirent *de;
if (!(dir = opendir( gctx->conf->path ))) { if (!(dir = opendir( gctx->conf->path ))) {
error( "%s: %s\n", gctx->conf->path, strerror(errno) ); error( "%s: %s\n", gctx->conf->path, strerror(errno) );
return DRV_STORE_BAD; cb( DRV_STORE_BAD, aux );
return;
} }
while ((de = readdir( dir ))) { while ((de = readdir( dir ))) {
struct stat st; struct stat st;
@ -183,7 +187,7 @@ maildir_list( store_t *gctx )
closedir (dir); closedir (dir);
gctx->listed = 1; gctx->listed = 1;
return DRV_OK; cb( DRV_OK, aux );
} }
static const char *subdirs[] = { "cur", "new", "tmp" }; static const char *subdirs[] = { "cur", "new", "tmp" };
@ -760,8 +764,9 @@ maildir_prepare_opts( store_t *gctx, int opts )
gctx->opts = opts; gctx->opts = opts;
} }
static int static void
maildir_select( store_t *gctx, int minuid, int maxuid, int *excs, int nexcs ) maildir_select( store_t *gctx, int minuid, int maxuid, int *excs, int nexcs,
void (*cb)( int sts, void *aux ), void *aux )
{ {
maildir_store_t *ctx = (maildir_store_t *)gctx; maildir_store_t *ctx = (maildir_store_t *)gctx;
message_t **msgapp; message_t **msgapp;
@ -777,14 +782,17 @@ maildir_select( store_t *gctx, int minuid, int maxuid, int *excs, int nexcs )
ctx->excs = nfrealloc( excs, nexcs * sizeof(int) ); ctx->excs = nfrealloc( excs, nexcs * sizeof(int) );
ctx->nexcs = nexcs; ctx->nexcs = nexcs;
if (maildir_validate( gctx->path, "", ctx->gen.opts & OPEN_CREATE ) != DRV_OK) if (maildir_validate( gctx->path, "", ctx->gen.opts & OPEN_CREATE ) != DRV_OK) {
return DRV_BOX_BAD; cb( DRV_BOX_BAD, aux );
return;
}
nfsnprintf( uvpath, sizeof(uvpath), "%s/.uidvalidity", gctx->path ); nfsnprintf( uvpath, sizeof(uvpath), "%s/.uidvalidity", gctx->path );
#ifndef USE_DB #ifndef USE_DB
if ((ctx->uvfd = open( uvpath, O_RDWR|O_CREAT, 0600 )) < 0) { if ((ctx->uvfd = open( uvpath, O_RDWR|O_CREAT, 0600 )) < 0) {
perror( uvpath ); perror( uvpath );
return DRV_BOX_BAD; cb( DRV_BOX_BAD, aux );
return;
} }
#else #else
if ((ctx->uvfd = open( uvpath, O_RDWR, 0600 )) < 0) { if ((ctx->uvfd = open( uvpath, O_RDWR, 0600 )) < 0) {
@ -799,7 +807,8 @@ maildir_select( store_t *gctx, int minuid, int maxuid, int *excs, int nexcs )
goto fnok; goto fnok;
} }
perror( uvpath ); perror( uvpath );
return DRV_BOX_BAD; cb( DRV_BOX_BAD, aux );
return;
} }
dbok: dbok:
#if SEEK_SET != 0 #if SEEK_SET != 0
@ -811,7 +820,8 @@ maildir_select( store_t *gctx, int minuid, int maxuid, int *excs, int nexcs )
bork: bork:
close( ctx->uvfd ); close( ctx->uvfd );
ctx->uvfd = -1; ctx->uvfd = -1;
return DRV_BOX_BAD; cb( DRV_BOX_BAD, aux );
return;
} }
if (db_create( &ctx->db, 0, 0 )) { if (db_create( &ctx->db, 0, 0 )) {
fputs( "Maildir error: db_create() failed\n", stderr ); fputs( "Maildir error: db_create() failed\n", stderr );
@ -841,14 +851,16 @@ maildir_select( store_t *gctx, int minuid, int maxuid, int *excs, int nexcs )
fnok: fnok:
#endif /* USE_DB */ #endif /* USE_DB */
if (maildir_scan( ctx, &msglist ) != DRV_OK) if (maildir_scan( ctx, &msglist ) != DRV_OK) {
return DRV_BOX_BAD; cb( DRV_BOX_BAD, aux );
return;
}
msgapp = &ctx->gen.msgs; msgapp = &ctx->gen.msgs;
for (i = 0; i < msglist.nents; i++) for (i = 0; i < msglist.nents; i++)
maildir_app_msg( ctx, &msgapp, msglist.ents + i ); maildir_app_msg( ctx, &msgapp, msglist.ents + i );
maildir_free_scan( &msglist ); maildir_free_scan( &msglist );
return DRV_OK; cb( DRV_OK, aux );
} }
static int static int
@ -916,8 +928,9 @@ maildir_again( maildir_store_t *ctx, maildir_message_t *msg, const char *fn )
return (msg->gen.status & M_DEAD) ? DRV_MSG_BAD : DRV_OK; return (msg->gen.status & M_DEAD) ? DRV_MSG_BAD : DRV_OK;
} }
static int static void
maildir_fetch_msg( store_t *gctx, message_t *gmsg, msg_data_t *data ) maildir_fetch_msg( store_t *gctx, message_t *gmsg, msg_data_t *data,
void (*cb)( int sts, void *aux ), void *aux )
{ {
maildir_store_t *ctx = (maildir_store_t *)gctx; maildir_store_t *ctx = (maildir_store_t *)gctx;
maildir_message_t *msg = (maildir_message_t *)gmsg; maildir_message_t *msg = (maildir_message_t *)gmsg;
@ -929,8 +942,10 @@ maildir_fetch_msg( store_t *gctx, message_t *gmsg, msg_data_t *data )
nfsnprintf( buf, sizeof(buf), "%s/%s/%s", gctx->path, subdirs[gmsg->status & M_RECENT], msg->base ); nfsnprintf( buf, sizeof(buf), "%s/%s/%s", gctx->path, subdirs[gmsg->status & M_RECENT], msg->base );
if ((fd = open( buf, O_RDONLY )) >= 0) if ((fd = open( buf, O_RDONLY )) >= 0)
break; break;
if ((ret = maildir_again( ctx, msg, buf )) != DRV_OK) if ((ret = maildir_again( ctx, msg, buf )) != DRV_OK) {
return ret; cb( ret, aux );
return;
}
} }
fstat( fd, &st ); fstat( fd, &st );
data->len = st.st_size; data->len = st.st_size;
@ -938,12 +953,13 @@ maildir_fetch_msg( store_t *gctx, message_t *gmsg, msg_data_t *data )
if (read( fd, data->data, data->len ) != data->len) { if (read( fd, data->data, data->len ) != data->len) {
perror( buf ); perror( buf );
close( fd ); close( fd );
return DRV_MSG_BAD; cb( DRV_MSG_BAD, aux );
return;
} }
close( fd ); close( fd );
if (!(gmsg->status & M_FLAGS)) if (!(gmsg->status & M_FLAGS))
data->flags = maildir_parse_flags( msg->base ); data->flags = maildir_parse_flags( msg->base );
return DRV_OK; cb( DRV_OK, aux );
} }
static int static int
@ -961,30 +977,34 @@ maildir_make_flags( int flags, char *buf )
return d; return d;
} }
static int static void
maildir_store_msg( store_t *gctx, msg_data_t *data, int *uid ) maildir_store_msg( store_t *gctx, msg_data_t *data, int to_trash,
void (*cb)( int sts, int uid, void *aux ), void *aux )
{ {
maildir_store_t *ctx = (maildir_store_t *)gctx; maildir_store_t *ctx = (maildir_store_t *)gctx;
const char *prefix, *box; const char *prefix, *box;
int ret, fd, bl; int ret, fd, bl, uid;
char buf[_POSIX_PATH_MAX], nbuf[_POSIX_PATH_MAX], fbuf[NUM_FLAGS + 3], base[128]; char buf[_POSIX_PATH_MAX], nbuf[_POSIX_PATH_MAX], fbuf[NUM_FLAGS + 3], base[128];
bl = nfsnprintf( base, sizeof(base), "%ld.%d_%d.%s", time( 0 ), Pid, ++MaildirCount, Hostname ); bl = nfsnprintf( base, sizeof(base), "%ld.%d_%d.%s", time( 0 ), Pid, ++MaildirCount, Hostname );
if (uid) { if (!to_trash) {
#ifdef USE_DB #ifdef USE_DB
if (ctx->db) { if (ctx->db) {
if ((ret = maildir_set_uid( ctx, base, uid )) != DRV_OK) { if ((ret = maildir_set_uid( ctx, base, &uid )) != DRV_OK) {
free( data->data ); free( data->data );
return ret; cb( ret, 0, aux );
return;
} }
} else } else
#endif /* USE_DB */ #endif /* USE_DB */
{ {
if ((ret = maildir_uidval_lock( ctx )) != DRV_OK || if ((ret = maildir_uidval_lock( ctx )) != DRV_OK ||
(ret = maildir_obtain_uid( ctx, uid )) != DRV_OK) (ret = maildir_obtain_uid( ctx, &uid )) != DRV_OK) {
return ret; cb( ret, 0, aux );
return;
}
maildir_uidval_unlock( ctx ); maildir_uidval_unlock( ctx );
nfsnprintf( base + bl, sizeof(base) - bl, ",U=%d", *uid ); nfsnprintf( base + bl, sizeof(base) - bl, ",U=%d", uid );
} }
prefix = gctx->path; prefix = gctx->path;
box = ""; box = "";
@ -999,16 +1019,19 @@ maildir_store_msg( store_t *gctx, msg_data_t *data, int *uid )
if (errno != ENOENT) { if (errno != ENOENT) {
perror( buf ); perror( buf );
free( data->data ); free( data->data );
return DRV_BOX_BAD; 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 )) != DRV_OK) {
free( data->data ); free( data->data );
return ret; cb( ret, 0, aux );
return;
} }
if ((fd = open( buf, O_WRONLY|O_CREAT|O_EXCL, 0600 )) < 0) { if ((fd = open( buf, O_WRONLY|O_CREAT|O_EXCL, 0600 )) < 0) {
perror( buf ); perror( buf );
free( data->data ); free( data->data );
return DRV_BOX_BAD; cb( DRV_BOX_BAD, 0, aux );
return;
} }
} }
ret = write( fd, data->data, data->len ); ret = write( fd, data->data, data->len );
@ -1019,35 +1042,37 @@ maildir_store_msg( store_t *gctx, msg_data_t *data, int *uid )
else else
error( "Maildir error: %s: partial write\n", buf ); error( "Maildir error: %s: partial write\n", buf );
close( fd ); close( fd );
return DRV_BOX_BAD; cb( DRV_BOX_BAD, 0, aux );
return;
} }
close( fd ); close( fd );
nfsnprintf( nbuf, sizeof(nbuf), "%s%s/%s/%s%s", prefix, box, subdirs[!(data->flags & F_SEEN)], base, fbuf ); nfsnprintf( nbuf, sizeof(nbuf), "%s%s/%s/%s%s", prefix, box, subdirs[!(data->flags & F_SEEN)], base, fbuf );
if (rename( buf, nbuf )) { if (rename( buf, nbuf )) {
perror( nbuf ); perror( nbuf );
return DRV_BOX_BAD; cb( DRV_BOX_BAD, 0, aux );
return;
} }
if (uid) cb( DRV_OK, uid, aux );
gctx->count++;
return DRV_OK;
} }
static int static void
maildir_find_msg( store_t *gctx, const char *tuid, int *uid ) maildir_find_msg( store_t *gctx, const char *tuid,
void (*cb)( int sts, int uid, void *aux ), void *aux )
{ {
message_t *msg; message_t *msg;
/* using a hash table might turn out to be more appropriate ... */ /* using a hash table might turn out to be more appropriate ... */
for (msg = gctx->msgs; msg; msg = msg->next) for (msg = gctx->msgs; msg; msg = msg->next)
if (!(msg->status & M_DEAD) && !memcmp( ((maildir_message_t *)msg)->tuid, tuid, TUIDL )) { if (!(msg->status & M_DEAD) && !memcmp( ((maildir_message_t *)msg)->tuid, tuid, TUIDL )) {
*uid = msg->uid; cb( DRV_OK, msg->uid, aux );
return DRV_OK; return;
} }
return DRV_MSG_BAD; cb( DRV_MSG_BAD, -1, aux );
} }
static int static void
maildir_set_flags( store_t *gctx, message_t *gmsg, int uid, int add, int del ) maildir_set_flags( store_t *gctx, message_t *gmsg, int uid, int add, int del,
void (*cb)( int sts, void *aux ), void *aux )
{ {
maildir_store_t *ctx = (maildir_store_t *)gctx; maildir_store_t *ctx = (maildir_store_t *)gctx;
maildir_message_t *msg = (maildir_message_t *)gmsg; maildir_message_t *msg = (maildir_message_t *)gmsg;
@ -1089,8 +1114,10 @@ maildir_set_flags( store_t *gctx, message_t *gmsg, int uid, int add, int del )
} }
if (!rename( buf, nbuf )) if (!rename( buf, nbuf ))
break; break;
if ((ret = maildir_again( ctx, msg, buf )) != DRV_OK) if ((ret = maildir_again( ctx, msg, buf )) != DRV_OK) {
return ret; cb( ret, aux );
return;
}
} }
free( msg->base ); free( msg->base );
msg->base = nfmalloc( tl + 1 ); msg->base = nfmalloc( tl + 1 );
@ -1099,7 +1126,7 @@ maildir_set_flags( store_t *gctx, message_t *gmsg, int uid, int add, int del )
msg->gen.flags &= ~del; msg->gen.flags &= ~del;
gmsg->status &= ~M_RECENT; gmsg->status &= ~M_RECENT;
return DRV_OK; cb( DRV_OK, aux );
} }
#ifdef USE_DB #ifdef USE_DB
@ -1119,8 +1146,9 @@ maildir_purge_msg( maildir_store_t *ctx, const char *name )
} }
#endif /* USE_DB */ #endif /* USE_DB */
static int static void
maildir_trash_msg( store_t *gctx, message_t *gmsg ) maildir_trash_msg( store_t *gctx, message_t *gmsg,
void (*cb)( int sts, void *aux ), void *aux )
{ {
maildir_store_t *ctx = (maildir_store_t *)gctx; maildir_store_t *ctx = (maildir_store_t *)gctx;
maildir_message_t *msg = (maildir_message_t *)gmsg; maildir_message_t *msg = (maildir_message_t *)gmsg;
@ -1137,30 +1165,38 @@ maildir_trash_msg( store_t *gctx, message_t *gmsg )
if (!rename( buf, nbuf )) if (!rename( buf, nbuf ))
break; break;
if (!stat( buf, &st )) { 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 )) != DRV_OK) {
return ret; cb( ret, aux );
return;
}
if (!rename( buf, nbuf )) if (!rename( buf, nbuf ))
break; break;
if (errno != ENOENT) { if (errno != ENOENT) {
perror( nbuf ); perror( nbuf );
return DRV_BOX_BAD; cb( DRV_BOX_BAD, aux );
return;
} }
} }
if ((ret = maildir_again( ctx, msg, buf )) != DRV_OK) if ((ret = maildir_again( ctx, msg, buf )) != DRV_OK) {
return ret; cb( ret, aux );
return;
}
} }
gmsg->status |= M_DEAD; gmsg->status |= M_DEAD;
gctx->count--; gctx->count--;
#ifdef USE_DB #ifdef USE_DB
if (ctx->db) if (ctx->db) {
return maildir_purge_msg( ctx, msg->base ); cb( maildir_purge_msg( ctx, msg->base ), aux );
return;
}
#endif /* USE_DB */ #endif /* USE_DB */
return DRV_OK; cb( DRV_OK, aux );
} }
static int static void
maildir_close( store_t *gctx ) maildir_close( store_t *gctx,
void (*cb)( int sts, void *aux ), void *aux )
{ {
#ifdef USE_DB #ifdef USE_DB
maildir_store_t *ctx = (maildir_store_t *)gctx; maildir_store_t *ctx = (maildir_store_t *)gctx;
@ -1184,23 +1220,36 @@ maildir_close( store_t *gctx )
msg->status |= M_DEAD; msg->status |= M_DEAD;
gctx->count--; gctx->count--;
#ifdef USE_DB #ifdef USE_DB
if (ctx->db && (ret = maildir_purge_msg( ctx, ((maildir_message_t *)msg)->base )) != DRV_OK) if (ctx->db && (ret = maildir_purge_msg( ctx, ((maildir_message_t *)msg)->base )) != DRV_OK) {
return ret; cb( ret, aux );
return;
}
#endif /* USE_DB */ #endif /* USE_DB */
} }
} }
if (!retry) if (!retry) {
return DRV_OK; cb( DRV_OK, aux );
if ((ret = maildir_rescan( (maildir_store_t *)gctx )) != DRV_OK) return;
return ret; }
if ((ret = maildir_rescan( (maildir_store_t *)gctx )) != DRV_OK) {
cb( ret, aux );
return;
}
} }
} }
static int static void
maildir_check( store_t *gctx ) maildir_cancel( store_t *gctx,
void (*cb)( int sts, void *aux ), void *aux )
{
(void)gctx;
cb( DRV_OK, aux );
}
static void
maildir_commit( store_t *gctx )
{ {
(void) gctx; (void) gctx;
return DRV_OK;
} }
static int static int
@ -1248,6 +1297,7 @@ struct driver maildir_driver = {
maildir_find_msg, maildir_find_msg,
maildir_set_flags, maildir_set_flags,
maildir_trash_msg, maildir_trash_msg,
maildir_check, maildir_close,
maildir_close maildir_cancel,
maildir_commit,
}; };

53
src/isync.h

@ -166,9 +166,13 @@ typedef struct {
} msg_data_t; } msg_data_t;
#define DRV_OK 0 #define DRV_OK 0
#define DRV_MSG_BAD -1 #define DRV_MSG_BAD 1
#define DRV_BOX_BAD -2 #define DRV_BOX_BAD 2
#define DRV_STORE_BAD -3 #define DRV_STORE_BAD 3
#define DRV_SERVER_BAD 4
#define DRV_CANCELED 5
/* All memory belongs to the driver's user. */
#define DRV_CRLF 1 #define DRV_CRLF 1
@ -178,21 +182,32 @@ struct driver {
int flags; int flags;
int (*parse_store)( conffile_t *cfg, store_conf_t **storep, int *err ); int (*parse_store)( conffile_t *cfg, store_conf_t **storep, int *err );
void (*cleanup)( void ); void (*cleanup)( void );
store_t *(*open_store)( store_conf_t *conf ); void (*open_store)( store_conf_t *conf,
void (*cb)( store_t *ctx, void *aux ), void *aux );
void (*disown_store)( store_t *ctx ); void (*disown_store)( store_t *ctx );
store_t *(*own_store)( store_conf_t *conf ); store_t *(*own_store)( store_conf_t *conf );
void (*cancel_store)( store_t *ctx ); void (*cancel_store)( store_t *ctx );
int (*list)( store_t *ctx ); void (*list)( store_t *ctx,
void (*cb)( int sts, void *aux ), void *aux );
void (*prepare_paths)( store_t *ctx ); void (*prepare_paths)( store_t *ctx );
void (*prepare_opts)( store_t *ctx, int opts ); void (*prepare_opts)( store_t *ctx, int opts );
int (*select)( store_t *ctx, int minuid, int maxuid, int *excs, int nexcs ); void (*select)( store_t *ctx, int minuid, int maxuid, int *excs, int nexcs,
int (*fetch_msg)( store_t *ctx, message_t *msg, msg_data_t *data ); void (*cb)( int sts, void *aux ), void *aux );
int (*store_msg)( store_t *ctx, msg_data_t *data, int *uid ); /* if uid is null, store to trash */ void (*fetch_msg)( store_t *ctx, message_t *msg, msg_data_t *data,
int (*find_msg)( store_t *ctx, const char *tuid, int *uid ); void (*cb)( int sts, void *aux ), void *aux );
int (*set_flags)( store_t *ctx, message_t *msg, int uid, int add, int del ); /* msg can be null, therefore uid as a fallback */ void (*store_msg)( store_t *ctx, msg_data_t *data, int to_trash,
int (*trash_msg)( store_t *ctx, message_t *msg ); /* This may expunge the original message immediately, but it needn't to */ void (*cb)( int sts, int uid, void *aux ), void *aux );
int (*check)( store_t *ctx ); /* IMAP-style: flush */ void (*find_msg)( store_t *ctx, const char *tuid,
int (*close)( store_t *ctx ); /* IMAP-style: expunge inclusive */ void (*cb)( int sts, int uid, void *aux ), void *aux );
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 );
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 );
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 */
void (*cb)( int sts, void *aux ), void *aux );
void (*commit)( store_t *ctx );
}; };
@ -217,7 +232,6 @@ void debug( const char *, ... );
void debugn( const char *, ... ); void debugn( const char *, ... );
void info( const char *, ... ); void info( const char *, ... );
void infon( const char *, ... ); void infon( const char *, ... );
void infoc( char );
void warn( const char *, ... ); void warn( const char *, ... );
void error( const char *, ... ); void error( const char *, ... );
@ -248,12 +262,15 @@ unsigned char arc4_getbyte( void );
extern const char *str_ms[2], *str_hl[2]; extern const char *str_ms[2], *str_hl[2];
#define SYNC_OK 0 #define SYNC_OK 0 /* assumed to be 0 */
#define SYNC_FAIL 1 #define SYNC_FAIL 1
#define SYNC_BAD(ms) (2+(ms)) #define SYNC_BAD(ms) (2<<(ms))
#define SYNC_NOGOOD 4 /* internal */ #define SYNC_NOGOOD 8 /* internal */
#define SYNC_CANCELED 16 /* internal */
int sync_boxes( store_t *ctx[], const char *names[], channel_conf_t * ); /* All passed pointers must stay alive until cb is called. */
void sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan,
void (*cb)( int sts, void *aux ), void *aux );
/* config.c */ /* config.c */

222
src/main.c

@ -24,6 +24,7 @@
#include "isync.h" #include "isync.h"
#include <stdlib.h> #include <stdlib.h>
#include <stddef.h>
#include <unistd.h> #include <unistd.h>
#include <string.h> #include <string.h>
#include <fcntl.h> #include <fcntl.h>
@ -198,7 +199,16 @@ typedef struct {
unsigned done:1, skip:1, cben:1; unsigned done:1, skip:1, cben:1;
} main_vars_t; } main_vars_t;
static void sync_chans( main_vars_t *mvars ); #define AUX &mvars->t[t]
#define MVARS(aux) \
int t = *(int *)aux; \
main_vars_t *mvars = (main_vars_t *)(((char *)(&((int *)aux)[-t])) - offsetof(main_vars_t, t));
#define E_START 0
#define E_OPEN 1
#define E_SYNC 2
static void sync_chans( main_vars_t *mvars, int ent );
int int
main( int argc, char **argv ) main( int argc, char **argv )
@ -460,19 +470,36 @@ main( int argc, char **argv )
break; break;
} }
mvars->argv = argv; mvars->argv = argv;
sync_chans( mvars ); mvars->cben = 1;
sync_chans( mvars, E_START );
return mvars->ret; return mvars->ret;
} }
#define ST_FRESH 0
#define ST_OPEN 1
#define ST_CLOSED 2
static void store_opened( store_t *ctx, void *aux );
static void store_listed( int sts, void *aux );
static void done_sync_dyn( int sts, void *aux );
static void done_sync( int sts, void *aux );
static void static void
sync_chans( main_vars_t *mvars ) sync_chans( main_vars_t *mvars, int ent )
{ {
group_conf_t *group; group_conf_t *group;
channel_conf_t *chan; channel_conf_t *chan;
store_t *store;
string_list_t *mbox, *sbox, **mboxp, **sboxp; string_list_t *mbox, *sbox, **mboxp, **sboxp;
char *channame; char *channame;
int t; int t;
if (!mvars->cben)
return;
switch (ent) {
case E_OPEN: goto opened;
case E_SYNC: goto syncone;
}
for (;;) { for (;;) {
mvars->boxlist = 0; mvars->boxlist = 0;
if (!mvars->all) { if (!mvars->all) {
@ -503,36 +530,32 @@ sync_chans( main_vars_t *mvars )
merge_actions( mvars->chan, mvars->ops, XOP_HAVE_CREATE, OP_CREATE, 0 ); merge_actions( mvars->chan, mvars->ops, XOP_HAVE_CREATE, OP_CREATE, 0 );
merge_actions( mvars->chan, mvars->ops, XOP_HAVE_EXPUNGE, OP_EXPUNGE, 0 ); merge_actions( mvars->chan, mvars->ops, XOP_HAVE_EXPUNGE, OP_EXPUNGE, 0 );
mvars->state[M] = mvars->state[S] = ST_FRESH;
info( "Channel %s\n", mvars->chan->name ); info( "Channel %s\n", mvars->chan->name );
mvars->boxes[M] = mvars->boxes[S] = mvars->cboxes = 0; mvars->boxes[M] = mvars->boxes[S] = mvars->cboxes = 0;
mvars->skip = mvars->cben = 0;
for (t = 0; t < 2; t++) { for (t = 0; t < 2; t++) {
mvars->drv[t] = mvars->chan->stores[t]->driver; mvars->drv[t] = mvars->chan->stores[t]->driver;
mvars->ctx[t] = mvars->drv[t]->own_store( mvars->chan->stores[t] ); if ((store = mvars->drv[t]->own_store( mvars->chan->stores[t] )))
store_opened( store, AUX );
} }
for (t = 0; t < 2; t++) for (t = 0; t < 2 && !mvars->skip; t++)
if (!mvars->ctx[t]) { if (mvars->state[t] == ST_FRESH) {
info( "Opening %s %s...\n", str_ms[t], mvars->chan->stores[t]->name ); info( "Opening %s %s...\n", str_ms[t], mvars->chan->stores[t]->name );
if (!(mvars->ctx[t] = mvars->drv[t]->open_store( mvars->chan->stores[t] ))) { mvars->drv[t]->open_store( mvars->chan->stores[t], store_opened, AUX );
mvars->ret = 1;
goto next;
}
} }
mvars->cben = 1;
opened:
if (mvars->skip)
goto next;
if (mvars->state[M] != ST_OPEN || mvars->state[S] != ST_OPEN)
return;
if (mvars->boxlist) if (mvars->boxlist)
mvars->boxp = mvars->boxlist; mvars->boxp = mvars->boxlist;
else if (mvars->chan->patterns) { else if (mvars->chan->patterns) {
for (t = 0; t < 2; t++) { mvars->boxes[M] = filter_boxes( mvars->ctx[M]->boxes, mvars->chan->patterns );
if (!mvars->ctx[t]->listed) { mvars->boxes[S] = filter_boxes( mvars->ctx[S]->boxes, mvars->chan->patterns );
if (mvars->drv[t]->list( mvars->ctx[t] ) != DRV_OK) {
screwt:
mvars->drv[t]->cancel_store( mvars->ctx[t] );
mvars->ctx[t] = 0;
mvars->ret = 1;
goto next;
} else if (mvars->ctx[t]->conf->map_inbox)
add_string_list( &mvars->ctx[t]->boxes, mvars->ctx[t]->conf->map_inbox );
}
mvars->boxes[t] = filter_boxes( mvars->ctx[t]->boxes, mvars->chan->patterns );
}
for (mboxp = &mvars->boxes[M]; (mbox = *mboxp); ) { for (mboxp = &mvars->boxes[M]; (mbox = *mboxp); ) {
for (sboxp = &mvars->boxes[S]; (sbox = *sboxp); sboxp = &sbox->next) for (sboxp = &mvars->boxes[S]; (sbox = *sboxp); sboxp = &sbox->next)
if (!strcmp( sbox->string, mbox->string )) { if (!strcmp( sbox->string, mbox->string )) {
@ -550,60 +573,70 @@ sync_chans( main_vars_t *mvars )
if (mvars->list && mvars->multiple) if (mvars->list && mvars->multiple)
printf( "%s:\n", mvars->chan->name ); printf( "%s:\n", mvars->chan->name );
syncml:
mvars->done = mvars->cben = 0;
syncmlx:
if (mvars->boxlist) { if (mvars->boxlist) {
while ((mvars->names[S] = strsep( &mvars->boxp, ",\n" ))) { if ((mvars->names[S] = strsep( &mvars->boxp, ",\n" ))) {
if (mvars->list) if (!mvars->list) {
puts( mvars->names[S] );
else {
mvars->names[M] = mvars->names[S]; mvars->names[M] = mvars->names[S];
switch (sync_boxes( mvars->ctx, mvars->names, mvars->chan )) { sync_boxes( mvars->ctx, mvars->names, mvars->chan, done_sync, mvars );
case SYNC_BAD(M): t = M; goto screwt; goto syncw;
case SYNC_BAD(S): t = S; goto screwt;
case SYNC_FAIL: mvars->ret = 1;
}
} }
puts( mvars->names[S] );
goto syncmlx;
} }
} else if (mvars->chan->patterns) { } else if (mvars->chan->patterns) {
for (mbox = mvars->cboxes; mbox; mbox = mbox->next) if ((mbox = mvars->cboxes)) {
if (mvars->list) mvars->cboxes = mbox->next;
puts( mbox->string ); if (!mvars->list) {
else {
mvars->names[M] = mvars->names[S] = mbox->string; mvars->names[M] = mvars->names[S] = mbox->string;
switch (sync_boxes( mvars->ctx, mvars->names, mvars->chan )) { sync_boxes( mvars->ctx, mvars->names, mvars->chan, done_sync_dyn, mvars );
case SYNC_BAD(M): t = M; goto screwt; goto syncw;
case SYNC_BAD(S): t = S; goto screwt;
case SYNC_FAIL: mvars->ret = 1;
} }
puts( mbox->string );
free( mbox );
goto syncmlx;
} }
for (t = 0; t < 2; t++) for (t = 0; t < 2; t++)
if ((mbox = mvars->boxes[t])) {
mvars->boxes[t] = mbox->next;
if ((mvars->chan->ops[1-t] & OP_MASK_TYPE) && (mvars->chan->ops[1-t] & OP_CREATE)) { if ((mvars->chan->ops[1-t] & OP_MASK_TYPE) && (mvars->chan->ops[1-t] & OP_CREATE)) {
for (mbox = mvars->boxes[t]; mbox; mbox = mbox->next) if (!mvars->list) {
if (mvars->list)
puts( mbox->string );
else {
mvars->names[M] = mvars->names[S] = mbox->string; mvars->names[M] = mvars->names[S] = mbox->string;
switch (sync_boxes( mvars->ctx, mvars->names, mvars->chan )) { sync_boxes( mvars->ctx, mvars->names, mvars->chan, done_sync_dyn, mvars );
case SYNC_BAD(M): t = M; goto screwt; goto syncw;
case SYNC_BAD(S): t = S; goto screwt;
case SYNC_FAIL: mvars->ret = 1;
} }
puts( mbox->string );
} }
free( mbox );
goto syncmlx;
} }
} else {
if (!mvars->list) {
sync_boxes( mvars->ctx, mvars->chan->boxes, mvars->chan, done_sync, mvars );
mvars->skip = 1;
syncw:
mvars->cben = 1;
if (!mvars->done)
return;
syncone:
if (!mvars->skip)
goto syncml;
} else } else
if (mvars->list)
printf( "%s <=> %s\n", mvars->chan->boxes[M], mvars->chan->boxes[S] ); printf( "%s <=> %s\n", mvars->chan->boxes[M], mvars->chan->boxes[S] );
else
switch (sync_boxes( mvars->ctx, mvars->chan->boxes, mvars->chan )) {
case SYNC_BAD(M): t = M; goto screwt;
case SYNC_BAD(S): t = S; goto screwt;
case SYNC_FAIL: mvars->ret = 1;
} }
next: next:
if (mvars->ctx[M]) for (t = 0; t < 2; t++)
mvars->drv[M]->disown_store( mvars->ctx[M] ); if (mvars->state[t] == ST_OPEN) {
if (mvars->ctx[S]) mvars->drv[t]->disown_store( mvars->ctx[t] );
mvars->drv[S]->disown_store( mvars->ctx[S] ); mvars->state[t] = ST_CLOSED;
}
if (mvars->state[M] != ST_CLOSED || mvars->state[S] != ST_CLOSED) {
mvars->skip = mvars->cben = 1;
return;
}
free_string_list( mvars->cboxes ); free_string_list( mvars->cboxes );
free_string_list( mvars->boxes[M] ); free_string_list( mvars->boxes[M] );
free_string_list( mvars->boxes[S] ); free_string_list( mvars->boxes[S] );
@ -621,3 +654,76 @@ sync_chans( main_vars_t *mvars )
for (t = 0; t < N_DRIVERS; t++) for (t = 0; t < N_DRIVERS; t++)
drivers[t]->cleanup(); drivers[t]->cleanup();
} }
static void
store_opened( store_t *ctx, void *aux )
{
MVARS(aux)
if (!ctx) {
mvars->state[t] = ST_CLOSED;
mvars->ret = mvars->skip = 1;
return;
}
mvars->ctx[t] = ctx;
if (mvars->skip) {
mvars->state[t] = ST_OPEN;
sync_chans( mvars, E_OPEN );
return;
}
if (!mvars->boxlist && mvars->chan->patterns && !ctx->listed)
mvars->drv[t]->list( ctx, store_listed, AUX );
else {
mvars->state[t] = ST_OPEN;
sync_chans( mvars, E_OPEN );
}
}
static void
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;
}
sync_chans( mvars, E_OPEN );
}
static void
done_sync_dyn( int sts, void *aux )
{
main_vars_t *mvars = (main_vars_t *)aux;
free( ((char *)mvars->names[S]) - offsetof(string_list_t, string) );
done_sync( sts, aux );
}
static void
done_sync( int sts, void *aux )
{
main_vars_t *mvars = (main_vars_t *)aux;
mvars->done = 1;
if (sts) {
mvars->ret = 1;
if (sts & (SYNC_BAD(M) | SYNC_BAD(S))) {
mvars->skip = 1;
if (sts & SYNC_BAD(M))
mvars->state[M] = ST_CLOSED;
if (sts & SYNC_BAD(S))
mvars->state[S] = ST_CLOSED;
}
}
sync_chans( mvars, E_SYNC );
}

1131
src/sync.c

File diff suppressed because it is too large Load Diff

12
src/util.c

@ -43,6 +43,7 @@ debug( const char *msg, ... )
vprintf( msg, va ); vprintf( msg, va );
va_end( va ); va_end( va );
fflush( stdout ); fflush( stdout );
need_nl = 0;
} }
} }
@ -70,6 +71,7 @@ info( const char *msg, ... )
vprintf( msg, va ); vprintf( msg, va );
va_end( va ); va_end( va );
fflush( stdout ); fflush( stdout );
need_nl = 0;
} }
} }
@ -87,16 +89,6 @@ infon( const char *msg, ... )
} }
} }
void
infoc( char c )
{
if (!(DFlags & QUIET)) {
putchar( c );
fflush( stdout );
need_nl = Ontty;
}
}
void void
warn( const char *msg, ... ) warn( const char *msg, ... )
{ {

Loading…
Cancel
Save