isync

mailbox synchronization program
git clone https://git.code.sf.net/p/isync/isync
Log | Files | Refs | README | LICENSE

commit c3d91ae1e87f8a8b8d6b0e7ecd4b7fc09837d30e
parent bf66f210bd07030045564ff5050bbce5cf5e97e1
Author: Oswald Buddenhagen <ossi@users.sf.net>
Date:   Thu, 17 Dec 2020 15:53:40 +0100

introduce new inheritance model based on C11 anonymous structs

the struct declarations got uglier, but their usage requires a lot fewer
explicit references to the parent struct (though some are added where
using the derived struct is more practical now).

we also use something i'd term "covariant members": derivatives of
store_t also reference derivatives of store_conf_t, etc., which
drastically cuts down the number of casts.
fwiw, to achieve this with "proper" inheritance in C++, we'd use
covariant getter functions which hide the still existing casts.

C11 is almost a decade old now, and compilers supported that feature
even longer than that, so i don't expect this to be a problem.

Diffstat:
Mconfigure.ac | 26++++++++++++++++++++++++--
Msrc/common.h | 16++++++++--------
Msrc/driver.h | 49+++++++++++++++++++++++++++++--------------------
Msrc/drv_imap.c | 409+++++++++++++++++++++++++++++++++++++++++++------------------------------------
Msrc/drv_maildir.c | 214++++++++++++++++++++++++++++++++++++++++---------------------------------------
Msrc/drv_proxy.c | 53+++++++++++++++++++++++++++++++----------------------
6 files changed, 426 insertions(+), 341 deletions(-)

diff --git a/configure.ac b/configure.ac @@ -6,7 +6,7 @@ AC_CANONICAL_TARGET AM_INIT_AUTOMAKE AM_MAINTAINER_MODE -AC_PROG_CC_C99 +AC_PROG_CC if test "$GCC" = yes; then warnings=" -Wall -Wextra @@ -17,9 +17,31 @@ if test "$GCC" = yes; then -Wno-overlength-strings " - CFLAGS="$CFLAGS -pipe -std=c99 -pedantic $(echo $warnings)" + CFLAGS="$CFLAGS -pipe -std=c11 -pedantic $(echo $warnings)" fi +AC_COMPILE_IFELSE([AC_LANG_SOURCE([ +void fkt(void) +{ + int a = 42; // c99 comment + + for (int i = 0; i < a; i++) {} // declaration inside for() + int b; // declaration after code +} + +// c11 anonymous structs/unions +struct base { + int a; +}; +union deriv { + struct base gen; + struct { + int a; + int b; + }; +}; +])], , [AC_MSG_ERROR([compiler does not support required C11 features])]) + CPPFLAGS="$CPPFLAGS -D_GNU_SOURCE" AC_CHECK_PROG(PERL, perl, perl) diff --git a/src/common.h b/src/common.h @@ -186,22 +186,22 @@ int map_name( const char *arg, char **result, uint reserve, const char *in, cons typedef union { \ T##_array_t array; \ struct { \ - T *dummy_data; \ - uint dummy_size; \ + T *data; \ + uint size; \ uint alloc; \ - } extra; \ + }; \ } T##_array_alloc_t; \ static INLINE T *T##_array_append( T##_array_alloc_t *arr ) \ { \ - if (arr->array.size == arr->extra.alloc) { \ - arr->extra.alloc = arr->extra.alloc * 2 + 100; \ - arr->array.data = nfrealloc( arr->array.data, arr->extra.alloc * sizeof(T) ); \ + if (arr->size == arr->alloc) { \ + arr->alloc = arr->alloc * 2 + 100; \ + arr->data = nfrealloc( arr->data, arr->alloc * sizeof(T) ); \ } \ - return &arr->array.data[arr->array.size++]; \ + return &arr->data[arr->size++]; \ } #define ARRAY_INIT(arr) \ - do { (arr)->array.data = NULL; (arr)->array.size = (arr)->extra.alloc = 0; } while (0) + do { (arr)->data = NULL; (arr)->size = (arr)->alloc = 0; } while (0) #define ARRAY_SQUEEZE(arr) \ do { \ diff --git a/src/driver.h b/src/driver.h @@ -31,16 +31,19 @@ typedef struct driver driver_t; #define FAIL_WAIT 1 /* Retry after some time (if at all) */ #define FAIL_FINAL 2 /* Don't retry until store reconfiguration */ -typedef struct store_conf { - struct store_conf *next; - char *name; - driver_t *driver; - const char *path; /* should this be here? its interpretation is driver-specific */ - const char *flat_delim; - const char *map_inbox; - const char *trash; - uint max_size; /* off_t is overkill */ +#define STORE_CONF \ + struct store_conf *next; \ + char *name; \ + driver_t *driver; \ + const char *path; /* should this be here? its interpretation is driver-specific */ \ + const char *flat_delim; \ + const char *map_inbox; \ + const char *trash; \ + uint max_size; /* off_t is overkill */ \ char trash_remote_new, trash_only_new; + +typedef struct store_conf { + STORE_CONF } store_conf_t; /* For message->flags */ @@ -67,15 +70,18 @@ typedef struct store_conf { #define TUIDL 12 -typedef struct message { - struct message *next; - struct sync_rec *srec; - char *msgid; /* owned */ - /* string_list_t *keywords; */ - uint size; /* zero implies "not fetched" */ - uint uid; - uchar flags, status; +#define MESSAGE(message) \ + message *next; \ + struct sync_rec *srec; \ + char *msgid; /* owned */ \ + /* string_list_t *keywords; */ \ + uint size; /* zero implies "not fetched" */ \ + uint uid; \ + uchar flags, status; \ char tuid[TUIDL]; + +typedef struct message { + MESSAGE(struct message) } message_t; // For driver_t->prepare_load_box(), which may amend the passed flags. @@ -94,10 +100,13 @@ typedef struct message { #define UIDVAL_BAD ((uint)-1) +#define STORE(store) \ + store *next; \ + driver_t *driver; \ + store##_conf *conf; /* foreign */ + typedef struct store { - struct store *next; - driver_t *driver; - store_conf_t *conf; /* foreign */ + STORE(struct store) } store_t; typedef struct { diff --git a/src/drv_imap.c b/src/drv_imap.c @@ -69,17 +69,23 @@ typedef struct imap_server_conf { char failed; } imap_server_conf_t; -typedef struct { +typedef union imap_store_conf { store_conf_t gen; - imap_server_conf_t *server; - char delimiter; - char use_namespace; - char use_lsub; + struct { + STORE_CONF + imap_server_conf_t *server; + char delimiter; + char use_namespace; + char use_lsub; + }; } imap_store_conf_t; -typedef struct { +typedef union imap_message { message_t gen; -/* uint seq; will be needed when expunges are tracked */ + struct { + MESSAGE(union imap_message) + // uint seq; will be needed when expunges are tracked + }; } imap_message_t; #define NIL (void*)0x1 @@ -93,7 +99,7 @@ typedef struct _list { #define MAX_LIST_DEPTH 5 -typedef struct imap_store imap_store_t; +typedef union imap_store imap_store_t; typedef struct { list_t *head, **stack[MAX_LIST_DEPTH]; @@ -103,116 +109,142 @@ typedef struct { typedef struct imap_cmd imap_cmd_t; -struct imap_store { +union imap_store { store_t gen; - const char *label; /* foreign */ - const char *prefix; - const char *name; - uint ref_count; - uint opts; - enum { SST_BAD, SST_HALF, SST_GOOD } state; - /* trash folder's existence is not confirmed yet */ - enum { TrashUnknown, TrashChecking, TrashKnown } trashnc; - // What kind of BODY-less FETCH response we're expecting. - enum { FetchNone, FetchMsgs, FetchUidNext } fetch_sts; - uint got_namespace:1; - uint has_forwarded:1; - char delimiter[2]; /* hierarchy delimiter */ - char *ns_prefix, ns_delimiter; /* NAMESPACE info */ - string_list_t *boxes; // _list results - char listed; // was _list already run with these flags? - // note that the message counts do _not_ reflect stats from msgs, - // but mailbox totals. - int total_msgs, recent_msgs; - uint uidvalidity, uidnext; - message_t *msgs; - message_t **msgapp; /* FETCH results */ - uint caps; /* CAPABILITY results */ - string_list_t *auth_mechs; - parse_list_state_t parse_list_sts; - /* command queue */ - imap_cmd_t *pending, **pending_append; - imap_cmd_t *in_progress, **in_progress_append; - imap_cmd_t *wait_check, **wait_check_append; - int nexttag, num_in_progress, num_wait_check; - uint buffer_mem; /* memory currently occupied by buffers in the queue */ - - /* Used during sequential operations like connect */ - enum { GreetingPending = 0, GreetingBad, GreetingOk, GreetingPreauth } greeting; - int expectBYE; /* LOGOUT is in progress */ - int expectEOF; /* received LOGOUT's OK or unsolicited BYE */ - int canceling; /* imap_cancel() is in progress */ - union { - void (*imap_open)( int sts, void *aux ); - void (*imap_cancel)( void *aux ); - } callbacks; - void *callback_aux; + struct { + STORE(union imap_store) + const char *label; // foreign + const char *prefix; + const char *name; + uint ref_count; + uint opts; + enum { SST_BAD, SST_HALF, SST_GOOD } state; + // The trash folder's existence is not confirmed yet + enum { TrashUnknown, TrashChecking, TrashKnown } trashnc; + // What kind of BODY-less FETCH response we're expecting + enum { FetchNone, FetchMsgs, FetchUidNext } fetch_sts; + uint got_namespace:1; + uint has_forwarded:1; + char delimiter[2]; // Hierarchy delimiter + char *ns_prefix, ns_delimiter; // NAMESPACE info + string_list_t *boxes; // _list results + char listed; // was _list already run with these flags? + // note that the message counts do _not_ reflect stats from msgs, + // but mailbox totals. + int total_msgs, recent_msgs; + uint uidvalidity, uidnext; + imap_message_t **msgapp, *msgs; // FETCH results + uint caps; // CAPABILITY results + string_list_t *auth_mechs; + parse_list_state_t parse_list_sts; + // Command queue + imap_cmd_t *pending, **pending_append; + imap_cmd_t *in_progress, **in_progress_append; + imap_cmd_t *wait_check, **wait_check_append; + int nexttag, num_in_progress, num_wait_check; + uint buffer_mem; // Memory currently occupied by buffers in the queue + + // Used during sequential operations like connect + enum { GreetingPending = 0, GreetingBad, GreetingOk, GreetingPreauth } greeting; + int expectBYE; // LOGOUT is in progress + int expectEOF; // received LOGOUT's OK or unsolicited BYE + int canceling; // imap_cancel() is in progress + union { + void (*imap_open)( int sts, void *aux ); + void (*imap_cancel)( void *aux ); + } callbacks; + void *callback_aux; #ifdef HAVE_LIBSASL - sasl_conn_t *sasl; - int sasl_cont; + sasl_conn_t *sasl; + int sasl_cont; #endif - void (*bad_callback)( void *aux ); - void *bad_callback_aux; + void (*bad_callback)( void *aux ); + void *bad_callback_aux; - conn_t conn; /* this is BIG, so put it last */ + conn_t conn; // This is BIG, so put it last + }; }; -struct imap_cmd { - struct imap_cmd *next; - char *cmd; - int tag; - - struct { - /* Will be called on each continuation request until it resets this pointer. - * Needs to invoke bad_callback and return -1 on error, otherwise return 0. */ - int (*cont)( imap_store_t *ctx, imap_cmd_t *cmd, const char *prompt ); - void (*done)( imap_store_t *ctx, imap_cmd_t *cmd, int response ); - char *data; - uint data_len; - uint uid; /* to identify fetch responses */ - char high_prio; /* if command is queued, put it at the front of the queue. */ - char wait_check; // Don't report success until subsequent CHECK success. - char to_trash; /* we are storing to trash, not current. */ - char create; /* create the mailbox if we get an error which suggests so. */ - char failok; /* Don't complain about NO response. */ +#define IMAP_CMD \ + struct imap_cmd *next; \ + char *cmd; \ + int tag; \ + \ + struct { \ + /* Will be called on each continuation request until it resets this pointer. \ + * Needs to invoke bad_callback and return -1 on error, otherwise return 0. */ \ + int (*cont)( imap_store_t *ctx, imap_cmd_t *cmd, const char *prompt ); \ + void (*done)( imap_store_t *ctx, imap_cmd_t *cmd, int response ); \ + char *data; \ + uint data_len; \ + uint uid; /* to identify fetch responses */ \ + char high_prio; /* if command is queued, put it at the front of the queue. */ \ + char wait_check; /* Don't report success until subsequent CHECK success. */ \ + char to_trash; /* we are storing to trash, not current. */ \ + char create; /* create the mailbox if we get an error which suggests so. */ \ + char failok; /* Don't complain about NO response. */ \ } param; + +struct imap_cmd { + IMAP_CMD }; -typedef struct { - imap_cmd_t gen; - void (*callback)( int sts, void *aux ); +#define IMAP_CMD_SIMPLE \ + IMAP_CMD \ + void (*callback)( int sts, void *aux ); \ void *callback_aux; + +typedef union { + imap_cmd_t gen; + struct { + IMAP_CMD_SIMPLE + }; } imap_cmd_simple_t; -typedef struct { +typedef union { imap_cmd_simple_t gen; - msg_data_t *msg_data; + struct { + IMAP_CMD_SIMPLE + msg_data_t *msg_data; + }; } imap_cmd_fetch_msg_t; -typedef struct { +typedef union { imap_cmd_t gen; - void (*callback)( int sts, uint uid, void *aux ); - void *callback_aux; - uint out_uid; + struct { + IMAP_CMD + void (*callback)( int sts, uint uid, void *aux ); + void *callback_aux; + uint out_uid; + }; } imap_cmd_out_uid_t; -typedef struct { +typedef union { imap_cmd_t gen; - void (*callback)( int sts, message_t *msgs, void *aux ); - void *callback_aux; - message_t **out_msgs; - uint uid; + struct { + IMAP_CMD + void (*callback)( int sts, message_t *msgs, void *aux ); + void *callback_aux; + imap_message_t **out_msgs; + uint uid; + }; } imap_cmd_find_new_t; -typedef struct { - uint ref_count; +#define IMAP_CMD_REFCOUNTED_STATE \ + uint ref_count; \ int ret_val; -} imap_cmd_refcounted_state_t; typedef struct { + IMAP_CMD_REFCOUNTED_STATE +} imap_cmd_refcounted_state_t; + +typedef union { imap_cmd_t gen; - imap_cmd_refcounted_state_t *state; + struct { + IMAP_CMD + imap_cmd_refcounted_state_t *state; + }; } imap_cmd_refcounted_t; #define CAP(cap) (ctx->caps & (1 << (cap))) @@ -283,8 +315,8 @@ new_imap_cmd( uint size ) #define INIT_IMAP_CMD_X(type, cmdp, cb, aux) \ cmdp = (type *)new_imap_cmd( sizeof(*cmdp) ); \ - cmdp->gen.callback = cb; \ - cmdp->gen.callback_aux = aux; + cmdp->callback = cb; \ + cmdp->callback_aux = aux; static void done_imap_cmd( imap_store_t *ctx, imap_cmd_t *cmd, int response ) @@ -391,7 +423,7 @@ cmd_sendable( imap_store_t *ctx, imap_cmd_t *cmd ) /* Don't build a queue of MOVE/COPY/APPEND commands that may all fail. */ return 0; } - if (ctx->num_in_progress >= ((imap_store_conf_t *)ctx->gen.conf)->server->max_in_progress) { + if (ctx->num_in_progress >= ctx->conf->server->max_in_progress) { /* Too many commands in flight. */ return 0; } @@ -628,15 +660,15 @@ imap_refcounted_new_cmd( imap_cmd_refcounted_state_t *sts ) } #define DONE_REFCOUNTED_STATE(sts) \ - if (!--sts->gen.ref_count) { \ - sts->callback( sts->gen.ret_val, sts->callback_aux ); \ + if (!--sts->ref_count) { \ + sts->callback( sts->ret_val, sts->callback_aux ); \ free( sts ); \ } #define DONE_REFCOUNTED_STATE_ARGS(sts, finalize, ...) \ - if (!--sts->gen.ref_count) { \ + if (!--sts->ref_count) { \ finalize \ - sts->callback( sts->gen.ret_val, __VA_ARGS__, sts->callback_aux ); \ + sts->callback( sts->ret_val, __VA_ARGS__, sts->callback_aux ); \ free( sts ); \ } @@ -1164,16 +1196,16 @@ parse_fetch_rsp( imap_store_t *ctx, list_t *list, char *s ATTR_UNUSED ) ctx->uidnext = uid + 1; } else if (ctx->fetch_sts == FetchMsgs) { cur = nfcalloc( sizeof(*cur) ); - *ctx->msgapp = &cur->gen; - ctx->msgapp = &cur->gen.next; - cur->gen.uid = uid; - cur->gen.flags = mask; - cur->gen.status = status; - cur->gen.size = size; + *ctx->msgapp = cur; + ctx->msgapp = &cur->next; + cur->uid = uid; + cur->flags = mask; + cur->status = status; + cur->size = size; if (msgid) - cur->gen.msgid = nfstrndup( msgid, msgid_len ); + cur->msgid = nfstrndup( msgid, msgid_len ); if (tuid) - memcpy( cur->gen.tuid, tuid, TUIDL ); + memcpy( cur->tuid, tuid, TUIDL ); status &= ~(M_FLAGS | M_RECENT | M_SIZE | M_HEADER); } else { badrsp: @@ -1207,7 +1239,7 @@ parse_capability( imap_store_t *ctx, char *cmd ) ctx->caps |= 1 << i; } } - ctx->caps &= ~((imap_store_conf_t *)ctx->gen.conf)->server->cap_mask; + ctx->caps &= ~ctx->conf->server->cap_mask; if (!CAP(NOLOGIN)) add_string_list( &ctx->auth_mechs, "LOGIN" ); } @@ -1418,12 +1450,15 @@ prepare_box( char **buf, const imap_store_t *ctx ) static int prepare_trash( char **buf, const imap_store_t *ctx ) { - return prepare_name( buf, ctx, ctx->prefix, ctx->gen.conf->trash ); + return prepare_name( buf, ctx, ctx->prefix, ctx->conf->trash ); } -typedef struct { +typedef union { imap_cmd_t gen; - imap_cmd_t *orig_cmd; + struct { + IMAP_CMD + imap_cmd_t *orig_cmd; + }; } imap_cmd_trycreate_t; static void imap_open_store_greeted( imap_store_t * ); @@ -1589,7 +1624,7 @@ imap_socket_read( void *aux ) imap_cmd_trycreate_t *cmd2 = (imap_cmd_trycreate_t *)new_imap_cmd( sizeof(*cmd2) ); cmd2->orig_cmd = cmdp; - cmd2->gen.param.high_prio = 1; + cmd2->param.high_prio = 1; p = strchr( cmdp->cmd, '"' ); imap_exec( ctx, &cmd2->gen, get_cmd_result_p2, "CREATE %.*s", imap_strchr( p + 1, '"' ) - p + 1, p ); @@ -1669,7 +1704,7 @@ imap_cancel_store( store_t *gctx ) cancel_pending_imap_cmds( ctx ); free( ctx->ns_prefix ); free_string_list( ctx->auth_mechs ); - free_generic_messages( ctx->msgs ); + free_generic_messages( &ctx->msgs->gen ); free_string_list( ctx->boxes ); imap_deref( ctx ); } @@ -1701,12 +1736,12 @@ imap_invoke_bad_callback( imap_store_t *ctx ) /******************* imap_free_store *******************/ -static store_t *unowned; +static imap_store_t *unowned; static void imap_cancel_unowned( void *gctx ) { - store_t *store, **storep; + imap_store_t *store, **storep; for (storep = &unowned; (store = *storep); storep = &store->next) if (store == gctx) { @@ -1723,11 +1758,11 @@ imap_free_store( store_t *gctx ) assert( !ctx->pending && !ctx->in_progress && !ctx->wait_check ); - free_generic_messages( ctx->msgs ); + free_generic_messages( &ctx->msgs->gen ); ctx->msgs = NULL; imap_set_bad_callback( gctx, imap_cancel_unowned, gctx ); - gctx->next = unowned; - unowned = gctx; + ctx->next = unowned; + unowned = ctx; } /******************* imap_cleanup *******************/ @@ -1737,16 +1772,16 @@ static void imap_cleanup_p2( imap_store_t *, imap_cmd_t *, int ); static void imap_cleanup( void ) { - store_t *ctx, *nctx; + imap_store_t *ctx, *nctx; for (ctx = unowned; ctx; ctx = nctx) { nctx = ctx->next; - imap_set_bad_callback( ctx, (void (*)(void *))imap_cancel_store, ctx ); + imap_set_bad_callback( &ctx->gen, (void (*)(void *))imap_cancel_store, ctx ); if (((imap_store_t *)ctx)->state != SST_BAD) { ((imap_store_t *)ctx)->expectBYE = 1; imap_exec( (imap_store_t *)ctx, NULL, imap_cleanup_p2, "LOGOUT" ); } else { - imap_cancel_store( ctx ); + imap_cancel_store( &ctx->gen ); } } } @@ -1794,20 +1829,19 @@ imap_alloc_store( store_conf_t *conf, const char *label ) { imap_store_conf_t *cfg = (imap_store_conf_t *)conf; imap_server_conf_t *srvc = cfg->server; - imap_store_t *ctx; - store_t **ctxp; + imap_store_t *ctx, **ctxp; /* First try to recycle a whole store. */ - for (ctxp = &unowned; (ctx = (imap_store_t *)*ctxp); ctxp = &ctx->gen.next) - if (ctx->state == SST_GOOD && ctx->gen.conf == conf) { - *ctxp = ctx->gen.next; + for (ctxp = &unowned; (ctx = *ctxp); ctxp = &ctx->next) + if (ctx->state == SST_GOOD && ctx->conf == cfg) { + *ctxp = ctx->next; goto gotstore; } /* Then try to recycle a server connection. */ - for (ctxp = &unowned; (ctx = (imap_store_t *)*ctxp); ctxp = &ctx->gen.next) - if (ctx->state != SST_BAD && ((imap_store_conf_t *)ctx->gen.conf)->server == srvc) { - *ctxp = ctx->gen.next; + for (ctxp = &unowned; (ctx = *ctxp); ctxp = &ctx->next) + if (ctx->state != SST_BAD && ctx->conf->server == srvc) { + *ctxp = ctx->next; free_string_list( ctx->boxes ); ctx->boxes = NULL; ctx->listed = 0; @@ -1819,7 +1853,7 @@ imap_alloc_store( store_conf_t *conf, const char *label ) /* Finally, schedule opening a new server connection. */ ctx = nfcalloc( sizeof(*ctx) ); - ctx->gen.driver = &imap_driver; + ctx->driver = &imap_driver; ctx->ref_count = 1; socket_init( &ctx->conn, &srvc->sconf, (void (*)( void * ))imap_invoke_bad_callback, @@ -1829,7 +1863,7 @@ imap_alloc_store( store_conf_t *conf, const char *label ) ctx->wait_check_append = &ctx->wait_check; gotsrv: - ctx->gen.conf = conf; + ctx->conf = cfg; gotstore: ctx->label = label; return &ctx->gen; @@ -1857,15 +1891,11 @@ static void imap_open_store_connected( int ok, void *aux ) { imap_store_t *ctx = (imap_store_t *)aux; -#ifdef HAVE_LIBSSL - imap_store_conf_t *cfg = (imap_store_conf_t *)ctx->gen.conf; - imap_server_conf_t *srvc = cfg->server; -#endif if (!ok) imap_open_store_bail( ctx, FAIL_WAIT ); #ifdef HAVE_LIBSSL - else if (srvc->ssl_type == SSL_IMAPS) + else if (ctx->conf->server->ssl_type == SSL_IMAPS) socket_start_tls( &ctx->conn, imap_open_store_tlsstarted1 ); #endif else @@ -1908,8 +1938,7 @@ static void imap_open_store_authenticate( imap_store_t *ctx ) { #ifdef HAVE_LIBSSL - imap_store_conf_t *cfg = (imap_store_conf_t *)ctx->gen.conf; - imap_server_conf_t *srvc = cfg->server; + imap_server_conf_t *srvc = ctx->conf->server; #endif if (ctx->greeting != GreetingPreauth) { @@ -2108,7 +2137,7 @@ static int process_sasl_step( imap_store_t *ctx, int rc, const char *in, uint in_len, sasl_interact_t *interact, const char **out, uint *out_len ) { - imap_server_conf_t *srvc = ((imap_store_conf_t *)ctx->gen.conf)->server; + imap_server_conf_t *srvc = ctx->conf->server; while (rc == SASL_INTERACT) { if (process_sasl_interact( interact, srvc ) < 0) @@ -2237,8 +2266,7 @@ done_sasl_auth( imap_store_t *ctx, imap_cmd_t *cmd ATTR_UNUSED, int response ) static void imap_open_store_authenticate2( imap_store_t *ctx ) { - imap_store_conf_t *cfg = (imap_store_conf_t *)ctx->gen.conf; - imap_server_conf_t *srvc = cfg->server; + imap_server_conf_t *srvc = ctx->conf->server; string_list_t *mech, *cmech; int auth_login = 0; int skipped_login = 0; @@ -2409,10 +2437,10 @@ imap_open_store_compress_p2( imap_store_t *ctx, imap_cmd_t *cmd ATTR_UNUSED, int static void imap_open_store_namespace( imap_store_t *ctx ) { - imap_store_conf_t *cfg = (imap_store_conf_t *)ctx->gen.conf; + imap_store_conf_t *cfg = ctx->conf; ctx->state = SST_HALF; - ctx->prefix = cfg->gen.path; + ctx->prefix = cfg->path; ctx->delimiter[0] = cfg->delimiter; if (((!ctx->prefix && cfg->use_namespace) || !cfg->delimiter) && CAP(NAMESPACE)) { /* get NAMESPACE info */ @@ -2439,9 +2467,7 @@ imap_open_store_namespace_p2( imap_store_t *ctx, imap_cmd_t *cmd ATTR_UNUSED, in static void imap_open_store_namespace2( imap_store_t *ctx ) { - imap_store_conf_t *cfg = (imap_store_conf_t *)ctx->gen.conf; - - if (!ctx->prefix && cfg->use_namespace) + if (!ctx->prefix && ctx->conf->use_namespace) ctx->prefix = ctx->ns_prefix; if (!ctx->delimiter[0]) ctx->delimiter[0] = ctx->ns_delimiter; @@ -2471,7 +2497,7 @@ imap_open_store_ssl_bail( imap_store_t *ctx ) static void imap_open_store_bail( imap_store_t *ctx, int failed ) { - ((imap_store_conf_t *)ctx->gen.conf)->server->failed = (char)failed; + ctx->conf->server->failed = (char)failed; ctx->callbacks.imap_open( DRV_STORE_BAD, ctx->callback_aux ); } @@ -2484,7 +2510,7 @@ imap_select_box( store_t *gctx, const char *name ) assert( !ctx->pending && !ctx->in_progress && !ctx->wait_check ); - free_generic_messages( ctx->msgs ); + free_generic_messages( &ctx->msgs->gen ); ctx->msgs = NULL; ctx->msgapp = &ctx->msgs; @@ -2498,10 +2524,13 @@ imap_get_box_path( store_t *gctx ATTR_UNUSED ) return NULL; } -typedef struct { +typedef union { imap_cmd_t gen; - void (*callback)( int sts, uint uidvalidity, void *aux ); - void *callback_aux; + struct { + IMAP_CMD + void (*callback)( int sts, uint uidvalidity, void *aux ); + void *callback_aux; + }; } imap_cmd_open_box_t; static void imap_open_box_p2( imap_store_t *, imap_cmd_t *, int ); @@ -2525,7 +2554,7 @@ imap_open_box( store_t *gctx, ctx->uidnext = 0; INIT_IMAP_CMD(imap_cmd_open_box_t, cmd, cb, aux) - cmd->gen.param.failok = 1; + cmd->param.failok = 1; imap_exec( ctx, &cmd->gen, imap_open_box_p2, "SELECT \"%\\s\"", buf ); free( buf ); @@ -2702,10 +2731,13 @@ imap_set_range( imap_range_t *ranges, uint *nranges, int low_flags, int high_fla ranges[r].flags |= (ranges[r].last <= maxlow) ? low_flags : high_flags; } -typedef struct { +typedef union { imap_cmd_refcounted_state_t gen; - void (*callback)( int sts, message_t *msgs, int total_msgs, int recent_msgs, void *aux ); - void *callback_aux; + struct { + IMAP_CMD_REFCOUNTED_STATE + void (*callback)( int sts, message_t *msgs, int total_msgs, int recent_msgs, void *aux ); + void *callback_aux; + }; } imap_load_box_state_t; static void imap_submit_load( imap_store_t *, const char *, int, imap_load_box_state_t * ); @@ -2778,13 +2810,13 @@ imap_sort_msgs_comp( const void *a_, const void *b_ ) static void imap_sort_msgs( imap_store_t *ctx ) { - uint count = count_generic_messages( ctx->msgs ); + uint count = count_generic_messages( &ctx->msgs->gen ); if (count <= 1) return; - message_t **t = nfmalloc( sizeof(*t) * count ); + imap_message_t **t = nfmalloc( sizeof(*t) * count ); - message_t *m = ctx->msgs; + imap_message_t *m = ctx->msgs; for (uint i = 0; i < count; i++) { t[i] = m; m = m->next; @@ -2833,9 +2865,9 @@ imap_submit_load_p3( imap_store_t *ctx, imap_load_box_state_t *sts ) { DONE_REFCOUNTED_STATE_ARGS(sts, { ctx->fetch_sts = FetchNone; - if (sts->gen.ret_val == DRV_OK) + if (sts->ret_val == DRV_OK) imap_sort_msgs( ctx ); - }, ctx->msgs, ctx->total_msgs, ctx->recent_msgs) + }, &ctx->msgs->gen, ctx->total_msgs, ctx->recent_msgs) } /******************* imap_fetch_msg *******************/ @@ -2849,7 +2881,7 @@ imap_fetch_msg( store_t *ctx, message_t *msg, msg_data_t *data, int minimal, imap_cmd_fetch_msg_t *cmd; INIT_IMAP_CMD_X(imap_cmd_fetch_msg_t, cmd, cb, aux) - cmd->gen.gen.param.uid = msg->uid; + cmd->param.uid = msg->uid; cmd->msg_data = data; data->data = NULL; imap_exec( (imap_store_t *)ctx, &cmd->gen.gen, imap_fetch_msg_p2, @@ -2890,10 +2922,13 @@ imap_make_flags( int flags, char *buf ) return d; } -typedef struct { +typedef union { imap_cmd_refcounted_state_t gen; - void (*callback)( int sts, void *aux ); - void *callback_aux; + struct { + IMAP_CMD_REFCOUNTED_STATE + void (*callback)( int sts, void *aux ); + void *callback_aux; + }; } imap_set_msg_flags_state_t; static void imap_set_flags_p2( imap_store_t *, imap_cmd_t *, int ); @@ -2954,10 +2989,13 @@ imap_set_flags_p3( imap_set_msg_flags_state_t *sts ) /******************* imap_close_box *******************/ -typedef struct { +typedef union { imap_cmd_refcounted_state_t gen; - void (*callback)( int sts, void *aux ); - void *callback_aux; + struct { + IMAP_CMD_REFCOUNTED_STATE + void (*callback)( int sts, void *aux ); + void *callback_aux; + }; } imap_expunge_state_t; static void imap_close_box_p2( imap_store_t *, imap_cmd_t *, int ); @@ -2971,9 +3009,9 @@ imap_close_box( store_t *gctx, assert( !ctx->num_wait_check ); - if (ctx->gen.conf->trash && CAP(UIDPLUS)) { + if (ctx->conf->trash && CAP(UIDPLUS)) { INIT_REFCOUNTED_STATE(imap_expunge_state_t, sts, cb, aux) - message_t *msg, *fmsg, *nmsg; + imap_message_t *msg, *fmsg, *nmsg; int bl; char buf[1000]; @@ -3030,8 +3068,8 @@ imap_trash_msg( store_t *gctx, message_t *msg, char *buf; INIT_IMAP_CMD(imap_cmd_simple_t, cmd, cb, aux) - cmd->gen.param.create = 1; - cmd->gen.param.to_trash = 1; + cmd->param.create = 1; + cmd->param.to_trash = 1; if (prepare_trash( &buf, ctx ) < 0) { cb( DRV_BOX_BAD, aux ); return; @@ -3064,13 +3102,13 @@ imap_store_msg( store_t *gctx, msg_data_t *data, int to_trash, INIT_IMAP_CMD(imap_cmd_out_uid_t, cmd, cb, aux) ctx->buffer_mem += data->len; - cmd->gen.param.data_len = data->len; - cmd->gen.param.data = data->data; + cmd->param.data_len = data->len; + cmd->param.data = data->data; cmd->out_uid = 0; if (to_trash) { - cmd->gen.param.create = 1; - cmd->gen.param.to_trash = 1; + cmd->param.create = 1; + cmd->param.to_trash = 1; if (prepare_trash( &buf, ctx ) < 0) { cb( DRV_BOX_BAD, 0, aux ); return; @@ -3185,15 +3223,18 @@ imap_find_new_msgs_p4( imap_store_t *ctx ATTR_UNUSED, imap_cmd_t *gcmd, int resp imap_cmd_find_new_t *cmdp = (imap_cmd_find_new_t *)gcmd; transform_box_response( &response ); - cmdp->callback( response, *cmdp->out_msgs, cmdp->callback_aux ); + cmdp->callback( response, &(*cmdp->out_msgs)->gen, cmdp->callback_aux ); } /******************* imap_list_store *******************/ -typedef struct { +typedef union { imap_cmd_refcounted_state_t gen; - void (*callback)( int sts, string_list_t *, void *aux ); - void *callback_aux; + struct { + IMAP_CMD_REFCOUNTED_STATE + void (*callback)( int sts, string_list_t *, void *aux ); + void *callback_aux; + }; } imap_list_store_state_t; static void imap_list_store_p2( imap_store_t *, imap_cmd_t *, int ); @@ -3204,7 +3245,7 @@ imap_list_store( store_t *gctx, int flags, void (*cb)( int sts, string_list_t *boxes, void *aux ), void *aux ) { imap_store_t *ctx = (imap_store_t *)gctx; - imap_store_conf_t *cfg = (imap_store_conf_t *)ctx->gen.conf; + imap_store_conf_t *cfg = ctx->conf; INIT_REFCOUNTED_STATE(imap_list_store_state_t, sts, cb, aux) // ctx->prefix may be empty, "INBOX.", or something else. @@ -3341,8 +3382,8 @@ imap_parse_store( conffile_t *cfg, store_conf_t **storep ) type = "IMAP account"; } else if (!strcasecmp( "IMAPStore", cfg->cmd )) { store = nfcalloc( sizeof(*store) ); - store->gen.driver = &imap_driver; - name = store->gen.name = nfstrdup( cfg->val ); + store->driver = &imap_driver; + name = store->name = nfstrdup( cfg->val ); store->use_namespace = 1; *storep = &store->gen; memset( &sserver, 0, sizeof(sserver) ); @@ -3522,7 +3563,7 @@ imap_parse_store( conffile_t *cfg, store_conf_t **storep ) else if (!strcasecmp( "SubscribedOnly", cfg->cmd )) store->use_lsub = parse_bool( cfg ); else if (!strcasecmp( "Path", cfg->cmd )) - store->gen.path = nfstrdup( cfg->val ); + store->path = nfstrdup( cfg->val ); else if (!strcasecmp( "PathDelimiter", cfg->cmd )) { if (strlen( cfg->val ) != 1) { error( "%s:%d: Path delimiter must be exactly one character long\n", cfg->file, cfg->line ); @@ -3622,7 +3663,7 @@ imap_parse_store( conffile_t *cfg, store_conf_t **storep ) if (!store->server) { store->server = nfmalloc( sizeof(sserver) ); memcpy( store->server, &sserver, sizeof(sserver) ); - store->server->name = store->gen.name; + store->server->name = store->name; } else if (acc_opt) { error( "%s '%s' has both Account and account-specific options\n", type, name ); cfg->err = 1; diff --git a/src/drv_maildir.c b/src/drv_maildir.c @@ -50,44 +50,53 @@ #define SUB_MAILDIRPP 2 #define SUB_LEGACY 3 -typedef struct { +typedef union maildir_store_conf { store_conf_t gen; - char *inbox; + struct { + STORE_CONF + char *inbox; #ifdef USE_DB - int alt_map; + int alt_map; #endif /* USE_DB */ - char info_delimiter; - char sub_style; - char failed; - char *info_prefix, *info_stop; /* precalculated from info_delimiter */ + char info_delimiter; + char sub_style; + char failed; + char *info_prefix, *info_stop; /* precalculated from info_delimiter */ + }; } maildir_store_conf_t; -typedef struct { +typedef union maildir_message { message_t gen; - char *base; + struct { + MESSAGE(union maildir_message) + char *base; + }; } maildir_message_t; -typedef struct { +typedef union maildir_store { store_t gen; - int uvfd, uvok, is_inbox, fresh[3]; - uint opts, minuid, maxuid, finduid, pairuid, newuid, uidvalidity, nuid; - uint_array_t excs; - char *path; /* own */ - char *trash; + struct { + STORE(union maildir_store) + int uvfd, uvok, is_inbox, fresh[3]; + uint opts, minuid, maxuid, finduid, pairuid, newuid, uidvalidity, nuid; + uint_array_t excs; + char *path; // own + char *trash; #ifdef USE_DB - DB *db; - char *usedb; + DB *db; + char *usedb; #endif /* USE_DB */ - string_list_t *boxes; // _list results - char listed; // was _list already run with these flags? - // note that the message counts do _not_ reflect stats from msgs, - // but mailbox totals. also, don't trust them beyond the initial load. - int total_msgs, recent_msgs; - message_t *msgs; - wakeup_t lcktmr; - - void (*bad_callback)( void *aux ); - void *bad_callback_aux; + string_list_t *boxes; // _list results + char listed; // was _list already run with these flags? + // note that the message counts do _not_ reflect stats from msgs, + // but mailbox totals. also, don't trust them beyond the initial load. + int total_msgs, recent_msgs; + maildir_message_t *msgs; + wakeup_t lcktmr; + + void (*bad_callback)( void *aux ); + void *bad_callback_aux; + }; } maildir_store_t; #ifdef USE_DB @@ -130,8 +139,8 @@ maildir_parse_flags( const char *info_prefix, const char *base ) static int maildir_ensure_path( maildir_store_conf_t *conf ) { - if (!conf->gen.path) { - error( "Maildir error: store '%s' has no Path\n", conf->gen.name ); + if (!conf->path) { + error( "Maildir error: store '%s' has no Path\n", conf->name ); conf->failed = FAIL_FINAL; return -1; } @@ -153,20 +162,20 @@ maildir_join_path( maildir_store_conf_t *conf, int in_inbox, const char *box ) } else { if (maildir_ensure_path( conf ) < 0) return NULL; - prefix = conf->gen.path; + prefix = conf->path; } pl = strlen( prefix ); for (bl = 0, n = 0; (c = box[bl]); bl++) if (c == '/') { if (conf->sub_style == SUB_UNSET) { error( "Maildir error: accessing subfolder '%s', but store '%s' does not specify SubFolders style\n", - box, conf->gen.name ); + box, conf->name ); return NULL; } n++; } else if (c == '.' && conf->sub_style == SUB_MAILDIRPP) { error( "Maildir error: store '%s', folder '%s': SubFolders style Maildir++ does not support dots in mailbox names\n", - conf->gen.name, box ); + conf->name, box ); return NULL; } switch (conf->sub_style) { @@ -212,8 +221,8 @@ maildir_validate_path( maildir_store_conf_t *conf ) { struct stat st; - if (stat( conf->gen.path, &st ) || !S_ISDIR(st.st_mode)) { - error( "Maildir error: cannot open store '%s'\n", conf->gen.path ); + if (stat( conf->path, &st ) || !S_ISDIR(st.st_mode)) { + error( "Maildir error: cannot open store '%s'\n", conf->path ); conf->failed = FAIL_FINAL; return -1; } @@ -228,7 +237,7 @@ maildir_alloc_store( store_conf_t *gconf, const char *label ATTR_UNUSED ) maildir_store_t *ctx; ctx = nfcalloc( sizeof(*ctx) ); - ctx->gen.driver = &maildir_driver; + ctx->driver = &maildir_driver; ctx->gen.conf = gconf; ctx->uvfd = -1; init_wakeup( &ctx->lcktmr, lcktmr_timeout, ctx ); @@ -240,13 +249,13 @@ maildir_connect_store( store_t *gctx, void (*cb)( int sts, void *aux ), void *aux ) { maildir_store_t *ctx = (maildir_store_t *)gctx; - maildir_store_conf_t *conf = (maildir_store_conf_t *)ctx->gen.conf; + maildir_store_conf_t *conf = ctx->conf; - if (conf->gen.path && maildir_validate_path( conf ) < 0) { + if (conf->path && maildir_validate_path( conf ) < 0) { cb( DRV_STORE_BAD, aux ); return; } - if (conf->gen.trash && !(ctx->trash = maildir_join_path( conf, 0, conf->gen.trash ))) { + if (conf->trash && !(ctx->trash = maildir_join_path( conf, 0, conf->trash ))) { cb( DRV_STORE_BAD, aux ); return; } @@ -254,13 +263,11 @@ maildir_connect_store( store_t *gctx, } static void -free_maildir_messages( message_t *msg ) +free_maildir_messages( maildir_message_t *msg ) { - message_t *tmsg; - - for (; (tmsg = msg); msg = tmsg) { + for (maildir_message_t *tmsg; (tmsg = msg); msg = tmsg) { tmsg = msg->next; - free( ((maildir_message_t *)msg)->base ); + free( msg->base ); free( msg ); } } @@ -392,7 +399,7 @@ maildir_list_recurse( maildir_store_t *ctx, int isBox, int flags, char *path, int pathLen, char *name, int nameLen ) { DIR *dir; - int style = ((maildir_store_conf_t *)ctx->gen.conf)->sub_style; + int style = ctx->conf->sub_style; int pl, nl; struct dirent *de; struct stat st; @@ -405,7 +412,7 @@ maildir_list_recurse( maildir_store_t *ctx, int isBox, int flags, } if (isBox > 1 && style == SUB_UNSET) { error( "Maildir error: found subfolder '%.*s', but store '%s' does not specify SubFolders style\n", - nameLen - 1, name, ctx->gen.conf->name ); + nameLen - 1, name, ctx->conf->name ); closedir( dir ); return -1; } @@ -478,7 +485,7 @@ maildir_list_inbox( maildir_store_t *ctx, int flags, const char *basePath ) add_string_list( &ctx->boxes, "INBOX" ); return maildir_list_recurse( ctx, 1, flags, NULL, 0, basePath, basePath ? strlen( basePath ) - 1 : 0, - path, nfsnprintf( path, _POSIX_PATH_MAX, "%s/", ((maildir_store_conf_t *)ctx->gen.conf)->inbox ), + path, nfsnprintf( path, _POSIX_PATH_MAX, "%s/", ctx->conf->inbox ), name, nfsnprintf( name, _POSIX_PATH_MAX, "INBOX/" ) ); } @@ -491,11 +498,11 @@ maildir_list_path( maildir_store_t *ctx, int flags, const char *inbox ) return 0; ctx->listed |= LIST_PATH; - if (maildir_ensure_path( (maildir_store_conf_t *)ctx->gen.conf ) < 0) + if (maildir_ensure_path( ctx->conf ) < 0) return -1; return maildir_list_recurse( ctx, 0, flags, inbox, inbox ? strlen( inbox ) : 0, NULL, 0, - path, nfsnprintf( path, _POSIX_PATH_MAX, "%s", ctx->gen.conf->path ), + path, nfsnprintf( path, _POSIX_PATH_MAX, "%s", ctx->conf->path ), name, 0 ); } @@ -504,14 +511,14 @@ maildir_list_store( store_t *gctx, int flags, void (*cb)( int sts, string_list_t *boxes, void *aux ), void *aux ) { maildir_store_t *ctx = (maildir_store_t *)gctx; - maildir_store_conf_t *conf = (maildir_store_conf_t *)gctx->conf; + maildir_store_conf_t *conf = ctx->conf; if (conf->sub_style == SUB_MAILDIRPP ? maildir_list_maildirpp( ctx, flags, conf->inbox ) < 0 - : ((((flags & LIST_PATH) || ((flags & LIST_PATH_MAYBE) && gctx->conf->path)) + : ((((flags & LIST_PATH) || ((flags & LIST_PATH_MAYBE) && conf->path)) && maildir_list_path( ctx, flags, conf->inbox ) < 0) || ((flags & LIST_INBOX) - && maildir_list_inbox( ctx, flags, gctx->conf->path ) < 0))) { + && maildir_list_inbox( ctx, flags, conf->path ) < 0))) { maildir_invoke_bad_callback( ctx ); cb( DRV_CANCELED, NULL, aux ); } else { @@ -611,7 +618,7 @@ maildir_validate( const char *box, int create, maildir_store_t *ctx ) return DRV_BOX_BAD; if (make_box_dir( buf, bl )) { sys_error( "Maildir error: cannot create mailbox '%s'", box ); - ((maildir_store_conf_t *)ctx->gen.conf)->failed = FAIL_FINAL; + ctx->conf->failed = FAIL_FINAL; maildir_invoke_bad_callback( ctx ); return DRV_CANCELED; } @@ -832,7 +839,7 @@ maildir_set_uid( maildir_store_t *ctx, const char *name, uint *uid ) return ret; *uid = ++ctx->nuid; - make_key( ((maildir_store_conf_t *)ctx->gen.conf)->info_stop, &key, name ); + make_key( ctx->conf->info_stop, &key, name ); value.data = uid; value.size = sizeof(*uid); if ((ret = ctx->db->put( ctx->db, NULL, &key, &value, 0 ))) { @@ -909,7 +916,7 @@ maildir_compare( const void *l, const void *r ) static int maildir_scan( maildir_store_t *ctx, msg_t_array_alloc_t *msglist ) { - maildir_store_conf_t *conf = (maildir_store_conf_t *)ctx->gen.conf; + maildir_store_conf_t *conf = ctx->conf; DIR *d; FILE *f; struct dirent *e; @@ -1218,37 +1225,37 @@ maildir_init_msg( maildir_store_t *ctx, maildir_message_t *msg, msg_t *entry ) { msg->base = entry->base; entry->base = NULL; /* prevent deletion */ - msg->gen.msgid = entry->msgid; + msg->msgid = entry->msgid; entry->msgid = NULL; /* prevent deletion */ - msg->gen.size = entry->size; - msg->gen.srec = NULL; - memcpy( msg->gen.tuid, entry->tuid, TUIDL ); + msg->size = entry->size; + msg->srec = NULL; + memcpy( msg->tuid, entry->tuid, TUIDL ); if (entry->recent) - msg->gen.status |= M_RECENT; + msg->status |= M_RECENT; if (ctx->opts & OPEN_FLAGS) { - msg->gen.status |= M_FLAGS; - msg->gen.flags = maildir_parse_flags( ((maildir_store_conf_t *)ctx->gen.conf)->info_prefix, msg->base ); + msg->status |= M_FLAGS; + msg->flags = maildir_parse_flags( ctx->conf->info_prefix, msg->base ); } else - msg->gen.flags = 0; + msg->flags = 0; } static void -maildir_app_msg( maildir_store_t *ctx, message_t ***msgapp, msg_t *entry ) +maildir_app_msg( maildir_store_t *ctx, maildir_message_t ***msgapp, msg_t *entry ) { maildir_message_t *msg = nfmalloc( sizeof(*msg) ); - msg->gen.next = **msgapp; - **msgapp = &msg->gen; - *msgapp = &msg->gen.next; - msg->gen.uid = entry->uid; - msg->gen.status = 0; + msg->next = **msgapp; + **msgapp = msg; + *msgapp = &msg->next; + msg->uid = entry->uid; + msg->status = 0; maildir_init_msg( ctx, msg, entry ); } static int maildir_select_box( store_t *gctx, const char *name ) { - maildir_store_conf_t *conf = (maildir_store_conf_t *)gctx->conf; maildir_store_t *ctx = (maildir_store_t *)gctx; + maildir_store_conf_t *conf = ctx->conf; maildir_cleanup( gctx ); ctx->msgs = NULL; @@ -1304,7 +1311,7 @@ maildir_open_box( store_t *gctx, if ((ctx->uvfd = open( uvpath, O_RDWR, 0600 )) < 0) { nfsnprintf( uvpath, sizeof(uvpath), "%s/.isyncuidmap.db", ctx->path ); if ((ctx->uvfd = open( uvpath, O_RDWR, 0600 )) < 0) { - if (((maildir_store_conf_t *)gctx->conf)->alt_map) { + if (ctx->conf->alt_map) { if ((ctx->uvfd = open( uvpath, O_RDWR|O_CREAT, 0600 )) >= 0) goto dbok; } else { @@ -1439,7 +1446,7 @@ maildir_load_box( store_t *gctx, uint minuid, uint maxuid, uint finduid, uint pa void (*cb)( int sts, message_t *msgs, int total_msgs, int recent_msgs, void *aux ), void *aux ) { maildir_store_t *ctx = (maildir_store_t *)gctx; - message_t **msgapp; + maildir_message_t **msgapp; msg_t_array_alloc_t msglist; uint i; @@ -1460,23 +1467,20 @@ maildir_load_box( store_t *gctx, uint minuid, uint maxuid, uint finduid, uint pa maildir_app_msg( ctx, &msgapp, msglist.array.data + i ); maildir_free_scan( &msglist ); - cb( DRV_OK, ctx->msgs, ctx->total_msgs, ctx->recent_msgs, aux ); + cb( DRV_OK, &ctx->msgs->gen, ctx->total_msgs, ctx->recent_msgs, aux ); } static int maildir_rescan( maildir_store_t *ctx ) { - message_t **msgapp; - maildir_message_t *msg; + maildir_message_t **msgapp, *msg; msg_t_array_alloc_t msglist; uint i; ctx->fresh[0] = ctx->fresh[1] = 0; if (maildir_scan( ctx, &msglist ) != DRV_OK) return DRV_BOX_BAD; - for (msgapp = &ctx->msgs, i = 0; - (msg = (maildir_message_t *)*msgapp) || i < msglist.array.size; ) - { + for (msgapp = &ctx->msgs, i = 0; (msg = *msgapp) || i < msglist.array.size; ) { if (!msg) { #if 0 debug( "adding new message %u\n", msglist.array.data[i].uid ); @@ -1486,10 +1490,10 @@ maildir_rescan( maildir_store_t *ctx ) #endif i++; } else if (i >= msglist.array.size) { - debug( "purging deleted message %u\n", msg->gen.uid ); - msg->gen.status = M_DEAD; - msgapp = &msg->gen.next; - } else if (msglist.array.data[i].uid < msg->gen.uid) { + debug( "purging deleted message %u\n", msg->uid ); + msg->status = M_DEAD; + msgapp = &msg->next; + } else if (msglist.array.data[i].uid < msg->uid) { /* this should not happen, actually */ #if 0 debug( "adding new message %u\n", msglist.array.data[i].uid ); @@ -1498,17 +1502,17 @@ maildir_rescan( maildir_store_t *ctx ) debug( "ignoring new message %u\n", msglist.array.data[i].uid ); #endif i++; - } else if (msglist.array.data[i].uid > msg->gen.uid) { - debug( "purging deleted message %u\n", msg->gen.uid ); - msg->gen.status = M_DEAD; - msgapp = &msg->gen.next; + } else if (msglist.array.data[i].uid > msg->uid) { + debug( "purging deleted message %u\n", msg->uid ); + msg->status = M_DEAD; + msgapp = &msg->next; } else { - debug( "updating message %u\n", msg->gen.uid ); - msg->gen.status &= ~(M_FLAGS|M_RECENT); + debug( "updating message %u\n", msg->uid ); + msg->status &= ~(M_FLAGS|M_RECENT); free( msg->base ); - free( msg->gen.msgid ); + free( msg->msgid ); maildir_init_msg( ctx, msg, msglist.array.data + i ); - i++, msgapp = &msg->gen.next; + i++, msgapp = &msg->next; } } maildir_free_scan( &msglist ); @@ -1529,7 +1533,7 @@ maildir_again( maildir_store_t *ctx, maildir_message_t *msg, const char *err, .. } if ((ret = maildir_rescan( ctx )) != DRV_OK) return ret; - return (msg->gen.status & M_DEAD) ? DRV_MSG_BAD : DRV_OK; + return (msg->status & M_DEAD) ? DRV_MSG_BAD : DRV_OK; } static void @@ -1564,7 +1568,7 @@ maildir_fetch_msg( store_t *gctx, message_t *gmsg, msg_data_t *data, int minimal } close( fd ); if (!(gmsg->status & M_FLAGS)) - data->flags = maildir_parse_flags( ((maildir_store_conf_t *)gctx->conf)->info_prefix, msg->base ); + data->flags = maildir_parse_flags( ctx->conf->info_prefix, msg->base ); cb( DRV_OK, aux ); } @@ -1618,7 +1622,7 @@ maildir_store_msg( store_t *gctx, msg_data_t *data, int to_trash, box = ctx->trash; } - maildir_make_flags( ((maildir_store_conf_t *)gctx->conf)->info_delimiter, data->flags, fbuf ); + maildir_make_flags( ctx->conf->info_delimiter, data->flags, fbuf ); nfsnprintf( buf, sizeof(buf), "%s/tmp/%s%s", box, base, fbuf ); if ((fd = open( buf, O_WRONLY|O_CREAT|O_EXCL, 0600 )) < 0) { if (errno != ENOENT || !to_trash) { @@ -1682,8 +1686,8 @@ static void maildir_set_msg_flags( store_t *gctx, message_t *gmsg, uint uid ATTR_UNUSED, int add, int del, void (*cb)( int sts, void *aux ), void *aux ) { - maildir_store_conf_t *conf = (maildir_store_conf_t *)gctx->conf; maildir_store_t *ctx = (maildir_store_t *)gctx; + maildir_store_conf_t *conf = ctx->conf; maildir_message_t *msg = (maildir_message_t *)gmsg; char *s, *p; uint i; @@ -1729,8 +1733,8 @@ maildir_set_msg_flags( store_t *gctx, message_t *gmsg, uint uid ATTR_UNUSED, int } free( msg->base ); msg->base = nfstrndup( nbuf + bl, (size_t)tl ); - msg->gen.flags |= add; - msg->gen.flags &= ~del; + msg->flags |= add; + msg->flags &= ~del; gmsg->status &= ~M_RECENT; cb( DRV_OK, aux ); @@ -1744,7 +1748,7 @@ maildir_purge_msg( maildir_store_t *ctx, const char *name ) if ((ret = maildir_uidval_lock( ctx )) != DRV_OK) return ret; - make_key( ((maildir_store_conf_t *)ctx->gen.conf)->info_stop, &key, name ); + make_key( ctx->conf->info_stop, &key, name ); if ((ret = ctx->db->del( ctx->db, NULL, &key, 0 ))) { ctx->db->err( ctx->db, ret, "Maildir error: db->del()" ); return DRV_BOX_BAD; @@ -1766,7 +1770,7 @@ maildir_trash_msg( store_t *gctx, message_t *gmsg, for (;;) { nfsnprintf( buf, sizeof(buf), "%s/%s/%s", ctx->path, subdirs[gmsg->status & M_RECENT], msg->base ); - s = strstr( msg->base, ((maildir_store_conf_t *)gctx->conf)->info_prefix ); + s = strstr( msg->base, ctx->conf->info_prefix ); nfsnprintf( nbuf, sizeof(nbuf), "%s/%s/%lld.%d_%d.%s%s", ctx->trash, subdirs[gmsg->status & M_RECENT], (long long)time( NULL ), Pid, ++MaildirCount, Hostname, s ? s : "" ); if (!rename( buf, nbuf )) @@ -1806,7 +1810,7 @@ maildir_close_box( store_t *gctx, void (*cb)( int sts, void *aux ), void *aux ) { maildir_store_t *ctx = (maildir_store_t *)gctx; - message_t *msg; + maildir_message_t *msg; int basel, retry, ret; char buf[_POSIX_PATH_MAX]; @@ -1815,7 +1819,7 @@ maildir_close_box( store_t *gctx, basel = nfsnprintf( buf, sizeof(buf), "%s/", ctx->path ); for (msg = ctx->msgs; msg; msg = msg->next) if (!(msg->status & M_DEAD) && (msg->flags & F_DELETED)) { - nfsnprintf( buf + basel, _POSIX_PATH_MAX - basel, "%s/%s", subdirs[msg->status & M_RECENT], ((maildir_message_t *)msg)->base ); + nfsnprintf( buf + basel, _POSIX_PATH_MAX - basel, "%s/%s", subdirs[msg->status & M_RECENT], msg->base ); if (unlink( buf )) { if (errno == ENOENT) retry = 1; @@ -1825,7 +1829,7 @@ maildir_close_box( store_t *gctx, msg->status |= M_DEAD; ctx->total_msgs--; #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, msg->base )) != DRV_OK) { cb( ret, aux ); return; } @@ -1877,14 +1881,14 @@ maildir_parse_store( conffile_t *cfg, store_conf_t **storep ) return 0; store = nfcalloc( sizeof(*store) ); store->info_delimiter = FieldDelimiter; - store->gen.driver = &maildir_driver; - store->gen.name = nfstrdup( cfg->val ); + store->driver = &maildir_driver; + store->name = nfstrdup( cfg->val ); while (getcline( cfg ) && cfg->cmd) if (!strcasecmp( "Inbox", cfg->cmd )) store->inbox = expand_strdup( cfg->val ); else if (!strcasecmp( "Path", cfg->cmd )) - store->gen.path = expand_strdup( cfg->val ); + store->path = expand_strdup( cfg->val ); #ifdef USE_DB else if (!strcasecmp( "AltMap", cfg->cmd )) store->alt_map = parse_bool( cfg ); @@ -1916,8 +1920,8 @@ maildir_parse_store( conffile_t *cfg, store_conf_t **storep ) parse_generic_store( &store->gen, cfg, "MaildirStore" ); if (!store->inbox) store->inbox = expand_strdup( "~/Maildir" ); - if (store->sub_style == SUB_MAILDIRPP && store->gen.path) { - error( "Maildir store '%s': Setting Path is incompatible with 'SubFolders Maildir++'\n", store->gen.name ); + if (store->sub_style == SUB_MAILDIRPP && store->path) { + error( "Maildir store '%s': Setting Path is incompatible with 'SubFolders Maildir++'\n", store->name ); cfg->err = 1; } nfasprintf( &store->info_prefix, "%c2,", store->info_delimiter ); diff --git a/src/drv_proxy.c b/src/drv_proxy.c @@ -24,15 +24,18 @@ #include <limits.h> #include <stdlib.h> -typedef struct { +typedef union proxy_store { store_t gen; - const char *label; // foreign - uint ref_count; - driver_t *real_driver; - store_t *real_store; - - void (*bad_callback)( void *aux ); - void *bad_callback_aux; + struct { + STORE(union proxy_store) + const char *label; // foreign + uint ref_count; + driver_t *real_driver; + store_t *real_store; + + void (*bad_callback)( void *aux ); + void *bad_callback_aux; + }; } proxy_store_t; static void ATTR_PRINTFLIKE(1, 2) @@ -81,10 +84,13 @@ proxy_store_deref( proxy_store_t *ctx ) static int curr_tag; -typedef struct { - uint ref_count; - int tag; +#define GEN_CMD \ + uint ref_count; \ + int tag; \ proxy_store_t *ctx; + +typedef struct { + GEN_CMD } gen_cmd_t; static gen_cmd_t * @@ -148,11 +154,14 @@ static @type@proxy_@name@( store_t *gctx@decl_args@ ) //# END //# TEMPLATE CALLBACK -typedef struct { +typedef union { gen_cmd_t gen; - void (*callback)( @decl_cb_args@void *aux ); - void *callback_aux; - @decl_state@ + struct { + GEN_CMD + void (*callback)( @decl_cb_args@void *aux ); + void *callback_aux; + @decl_state@ + }; } @name@_cmd_t; static void @@ -161,10 +170,10 @@ proxy_@name@_cb( @decl_cb_args@void *aux ) @name@_cmd_t *cmd = (@name@_cmd_t *)aux; @pre_print_cb_args@ - debug( "%s[% 2d] Callback enter @name@@print_fmt_cb_args@\n", cmd->gen.ctx->label, cmd->gen.tag@print_pass_cb_args@ ); + debug( "%s[% 2d] Callback enter @name@@print_fmt_cb_args@\n", cmd->ctx->label, cmd->tag@print_pass_cb_args@ ); @print_cb_args@ cmd->callback( @pass_cb_args@cmd->callback_aux ); - debug( "%s[% 2d] Callback leave @name@\n", cmd->gen.ctx->label, cmd->gen.tag ); + debug( "%s[% 2d] Callback leave @name@\n", cmd->ctx->label, cmd->tag ); proxy_cmd_done( &cmd->gen ); } @@ -177,10 +186,10 @@ static @type@proxy_@name@( store_t *gctx@decl_args@, void (*cb)( @decl_cb_args@v cmd->callback_aux = aux; @assign_state@ @pre_print_args@ - debug( "%s[% 2d] Enter @name@@print_fmt_args@\n", ctx->label, cmd->gen.tag@print_pass_args@ ); + debug( "%s[% 2d] Enter @name@@print_fmt_args@\n", ctx->label, cmd->tag@print_pass_args@ ); @print_args@ ctx->real_driver->@name@( ctx->real_store@pass_args@, proxy_@name@_cb, cmd ); - debug( "%s[% 2d] Leave @name@\n", ctx->label, cmd->gen.tag ); + debug( "%s[% 2d] Leave @name@\n", ctx->label, cmd->tag ); proxy_cmd_done( &cmd->gen ); } //# END @@ -245,9 +254,9 @@ static @type@proxy_@name@( store_t *gctx@decl_args@, void (*cb)( @decl_cb_args@v //# DEFINE fetch_msg_print_pass_cb_args , fbuf, (long long)cmd->data->date, cmd->data->len //# DEFINE fetch_msg_print_cb_args if (sts == DRV_OK && (DFlags & DEBUG_DRV_ALL)) { - printf( "%s=========\n", cmd->gen.ctx->label ); + printf( "%s=========\n", cmd->ctx->label ); fwrite( cmd->data->data, cmd->data->len, 1, stdout ); - printf( "%s=========\n", cmd->gen.ctx->label ); + printf( "%s=========\n", cmd->ctx->label ); fflush( stdout ); } //# END @@ -314,7 +323,7 @@ proxy_alloc_store( store_t *real_ctx, const char *label ) proxy_store_t *ctx; ctx = nfcalloc( sizeof(*ctx) ); - ctx->gen.driver = &proxy_driver; + ctx->driver = &proxy_driver; ctx->gen.conf = real_ctx->conf; ctx->ref_count = 1; ctx->label = label;