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

async drivers to follow ...
This commit is contained in:
Oswald Buddenhagen 2006-03-21 20:03:21 +00:00
parent bdcc285403
commit 168e5f3282
6 changed files with 1331 additions and 644 deletions

View File

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

View File

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

View File

@ -166,9 +166,13 @@ typedef struct {
} msg_data_t;
#define DRV_OK 0
#define DRV_MSG_BAD -1
#define DRV_BOX_BAD -2
#define DRV_STORE_BAD -3
#define DRV_MSG_BAD 1
#define DRV_BOX_BAD 2
#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
@ -178,21 +182,32 @@ struct driver {
int flags;
int (*parse_store)( conffile_t *cfg, store_conf_t **storep, int *err );
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 );
store_t *(*own_store)( store_conf_t *conf );
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_opts)( store_t *ctx, int opts );
int (*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 );
int (*store_msg)( store_t *ctx, msg_data_t *data, int *uid ); /* if uid is null, store to trash */
int (*find_msg)( store_t *ctx, const char *tuid, int *uid );
int (*set_flags)( store_t *ctx, message_t *msg, int uid, int add, int del ); /* msg can be null, therefore uid as a fallback */
int (*trash_msg)( store_t *ctx, message_t *msg ); /* This may expunge the original message immediately, but it needn't to */
int (*check)( store_t *ctx ); /* IMAP-style: flush */
int (*close)( store_t *ctx ); /* IMAP-style: expunge inclusive */
void (*select)( store_t *ctx, int minuid, int maxuid, int *excs, int nexcs,
void (*cb)( int sts, void *aux ), void *aux );
void (*fetch_msg)( store_t *ctx, message_t *msg, msg_data_t *data,
void (*cb)( int sts, void *aux ), void *aux );
void (*store_msg)( store_t *ctx, msg_data_t *data, int to_trash,
void (*cb)( int sts, int uid, void *aux ), void *aux );
void (*find_msg)( store_t *ctx, const char *tuid,
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 info( const char *, ... );
void infon( const char *, ... );
void infoc( char );
void warn( const char *, ... );
void error( const char *, ... );
@ -248,12 +262,15 @@ unsigned char arc4_getbyte( void );
extern const char *str_ms[2], *str_hl[2];
#define SYNC_OK 0
#define SYNC_FAIL 1
#define SYNC_BAD(ms) (2+(ms))
#define SYNC_NOGOOD 4 /* internal */
#define SYNC_OK 0 /* assumed to be 0 */
#define SYNC_FAIL 1
#define SYNC_BAD(ms) (2<<(ms))
#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 */

View File

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

1297
src/sync.c

File diff suppressed because it is too large Load Diff

View File

@ -43,6 +43,7 @@ debug( const char *msg, ... )
vprintf( msg, va );
va_end( va );
fflush( stdout );
need_nl = 0;
}
}
@ -70,6 +71,7 @@ info( const char *msg, ... )
vprintf( msg, va );
va_end( va );
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
warn( const char *msg, ... )
{