make the driver model, sync_chans() and sync_boxes() fully async.
async drivers to follow ...
This commit is contained in:
parent
bdcc285403
commit
168e5f3282
181
src/drv_imap.c
181
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,
|
||||||
};
|
};
|
||||||
|
|
|
@ -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
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
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;
|
}
|
||||||
|
mvars->cben = 1;
|
||||||
|
opened:
|
||||||
|
if (mvars->skip)
|
||||||
goto next;
|
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 );
|
||||||
|
}
|
||||||
|
|
1243
src/sync.c
1243
src/sync.c
File diff suppressed because it is too large
Load Diff
12
src/util.c
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…
Reference in New Issue
Block a user