|
@@ -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,
|
|
|
};
|