introduce driver call debugging
do that by wrapping the actual stores into proxies. the proxy driver's code is auto-generated from function templates, some parameters, and the declarations of the driver functions themselves. attempts to do it with CPP macros turned out to be a nightmare.
This commit is contained in:
parent
bbe4567bce
commit
4cc5ad5a1a
1
src/.gitignore
vendored
1
src/.gitignore
vendored
|
@ -1,3 +1,4 @@
|
||||||
|
/drv_proxy.inc
|
||||||
/mbsync
|
/mbsync
|
||||||
/mdconvert
|
/mdconvert
|
||||||
/tst_timers
|
/tst_timers
|
||||||
|
|
|
@ -3,10 +3,14 @@ compat_dir = compat
|
||||||
endif
|
endif
|
||||||
SUBDIRS = $(compat_dir)
|
SUBDIRS = $(compat_dir)
|
||||||
|
|
||||||
mbsync_SOURCES = main.c sync.c config.c util.c socket.c driver.c drv_imap.c drv_maildir.c
|
mbsync_SOURCES = main.c sync.c config.c util.c socket.c driver.c drv_imap.c drv_maildir.c drv_proxy.c
|
||||||
mbsync_LDADD = $(DB_LIBS) $(SSL_LIBS) $(SOCK_LIBS) $(SASL_LIBS) $(Z_LIBS)
|
mbsync_LDADD = $(DB_LIBS) $(SSL_LIBS) $(SOCK_LIBS) $(SASL_LIBS) $(Z_LIBS)
|
||||||
noinst_HEADERS = common.h config.h driver.h sync.h socket.h
|
noinst_HEADERS = common.h config.h driver.h sync.h socket.h
|
||||||
|
|
||||||
|
drv_proxy.$(OBJEXT): drv_proxy.inc
|
||||||
|
drv_proxy.inc: $(srcdir)/driver.h $(srcdir)/drv_proxy.c $(srcdir)/drv_proxy_gen.pl
|
||||||
|
perl $(srcdir)/drv_proxy_gen.pl $(srcdir)/driver.h $(srcdir)/drv_proxy.c drv_proxy.inc
|
||||||
|
|
||||||
mdconvert_SOURCES = mdconvert.c
|
mdconvert_SOURCES = mdconvert.c
|
||||||
mdconvert_LDADD = $(DB_LIBS)
|
mdconvert_LDADD = $(DB_LIBS)
|
||||||
if with_mdconvert
|
if with_mdconvert
|
||||||
|
@ -24,4 +28,6 @@ man_MANS = mbsync.1 $(mdconvert_man)
|
||||||
exampledir = $(docdir)/examples
|
exampledir = $(docdir)/examples
|
||||||
example_DATA = mbsyncrc.sample
|
example_DATA = mbsyncrc.sample
|
||||||
|
|
||||||
EXTRA_DIST = run-tests.pl $(example_DATA) $(man_MANS)
|
EXTRA_DIST = drv_proxy_gen.pl run-tests.pl $(example_DATA) $(man_MANS)
|
||||||
|
|
||||||
|
CLEANFILES = drv_proxy.inc
|
||||||
|
|
|
@ -70,7 +70,9 @@ typedef unsigned int uint;
|
||||||
#define DEBUG_NET_ALL 0x08
|
#define DEBUG_NET_ALL 0x08
|
||||||
#define DEBUG_SYNC 0x10
|
#define DEBUG_SYNC 0x10
|
||||||
#define DEBUG_MAIN 0x20
|
#define DEBUG_MAIN 0x20
|
||||||
#define DEBUG_ALL (0xFF & ~DEBUG_NET_ALL)
|
#define DEBUG_DRV 0x40
|
||||||
|
#define DEBUG_DRV_ALL 0x80
|
||||||
|
#define DEBUG_ALL (0xFF & ~(DEBUG_NET_ALL | DEBUG_DRV_ALL))
|
||||||
#define QUIET 0x100
|
#define QUIET 0x100
|
||||||
#define VERYQUIET 0x200
|
#define VERYQUIET 0x200
|
||||||
#define PROGRESS 0x400
|
#define PROGRESS 0x400
|
||||||
|
|
11
src/driver.h
11
src/driver.h
|
@ -87,6 +87,7 @@ typedef struct message {
|
||||||
|
|
||||||
typedef struct store {
|
typedef struct store {
|
||||||
struct store *next;
|
struct store *next;
|
||||||
|
driver_t *driver;
|
||||||
store_conf_t *conf; /* foreign */
|
store_conf_t *conf; /* foreign */
|
||||||
} store_t;
|
} store_t;
|
||||||
|
|
||||||
|
@ -124,9 +125,11 @@ typedef struct {
|
||||||
#define LIST_PATH 2
|
#define LIST_PATH 2
|
||||||
#define LIST_PATH_MAYBE 4
|
#define LIST_PATH_MAYBE 4
|
||||||
|
|
||||||
|
#define xint int // For auto-generation of appropriate printf() formats.
|
||||||
|
|
||||||
struct driver {
|
struct driver {
|
||||||
/* Return driver capabilities. */
|
/* Return driver capabilities. */
|
||||||
int (*get_caps)( store_t *ctx );
|
xint (*get_caps)( store_t *ctx );
|
||||||
|
|
||||||
/* Parse configuration. */
|
/* Parse configuration. */
|
||||||
int (*parse_store)( conffile_t *cfg, store_conf_t **storep );
|
int (*parse_store)( conffile_t *cfg, store_conf_t **storep );
|
||||||
|
@ -192,7 +195,7 @@ struct driver {
|
||||||
/* Invoked before load_box(), this informs the driver which operations (OP_*)
|
/* Invoked before load_box(), this informs the driver which operations (OP_*)
|
||||||
* will be performed on the mailbox. The driver may extend the set by implicitly
|
* will be performed on the mailbox. The driver may extend the set by implicitly
|
||||||
* needed or available operations. Returns this possibly extended set. */
|
* needed or available operations. Returns this possibly extended set. */
|
||||||
int (*prepare_load_box)( store_t *ctx, int opts );
|
xint (*prepare_load_box)( store_t *ctx, xint opts );
|
||||||
|
|
||||||
/* Load the message attributes needed to perform the requested operations.
|
/* Load the message attributes needed to perform the requested operations.
|
||||||
* Consider only messages with UIDs between minuid and maxuid (inclusive)
|
* Consider only messages with UIDs between minuid and maxuid (inclusive)
|
||||||
|
@ -260,8 +263,10 @@ void free_generic_messages( message_t * );
|
||||||
|
|
||||||
void parse_generic_store( store_conf_t *store, conffile_t *cfg );
|
void parse_generic_store( store_conf_t *store, conffile_t *cfg );
|
||||||
|
|
||||||
|
store_t *proxy_alloc_store( store_t *real_ctx, const char *label );
|
||||||
|
|
||||||
#define N_DRIVERS 2
|
#define N_DRIVERS 2
|
||||||
extern driver_t *drivers[N_DRIVERS];
|
extern driver_t *drivers[N_DRIVERS];
|
||||||
extern driver_t maildir_driver, imap_driver;
|
extern driver_t maildir_driver, imap_driver, proxy_driver;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1708,6 +1708,7 @@ imap_alloc_store( store_conf_t *conf, const char *label )
|
||||||
ctx->pending_append = &ctx->pending;
|
ctx->pending_append = &ctx->pending;
|
||||||
|
|
||||||
gotsrv:
|
gotsrv:
|
||||||
|
ctx->gen.driver = &imap_driver;
|
||||||
ctx->gen.conf = conf;
|
ctx->gen.conf = conf;
|
||||||
ctx->label = label;
|
ctx->label = label;
|
||||||
ctx->ref_count = 1;
|
ctx->ref_count = 1;
|
||||||
|
|
|
@ -226,6 +226,7 @@ maildir_alloc_store( store_conf_t *gconf, const char *label ATTR_UNUSED )
|
||||||
maildir_store_t *ctx;
|
maildir_store_t *ctx;
|
||||||
|
|
||||||
ctx = nfcalloc( sizeof(*ctx) );
|
ctx = nfcalloc( sizeof(*ctx) );
|
||||||
|
ctx->gen.driver = &maildir_driver;
|
||||||
ctx->gen.conf = gconf;
|
ctx->gen.conf = gconf;
|
||||||
ctx->uvfd = -1;
|
ctx->uvfd = -1;
|
||||||
init_wakeup( &ctx->lcktmr, lcktmr_timeout, ctx );
|
init_wakeup( &ctx->lcktmr, lcktmr_timeout, ctx );
|
||||||
|
|
335
src/drv_proxy.c
335
src/drv_proxy.c
|
@ -0,0 +1,335 @@
|
||||||
|
/*
|
||||||
|
* mbsync - mailbox synchronizer
|
||||||
|
* Copyright (C) 2017 Oswald Buddenhagen <ossi@users.sf.net>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* As a special exception, mbsync may be linked with the OpenSSL library,
|
||||||
|
* despite that library's more restrictive license.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "driver.h"
|
||||||
|
|
||||||
|
#include <limits.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
store_t gen;
|
||||||
|
const char *label; // foreign
|
||||||
|
int 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)
|
||||||
|
debug( const char *msg, ... )
|
||||||
|
{
|
||||||
|
va_list va;
|
||||||
|
|
||||||
|
va_start( va, msg );
|
||||||
|
vdebug( DEBUG_DRV, msg, va );
|
||||||
|
va_end( va );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ATTR_PRINTFLIKE(1, 2)
|
||||||
|
debugn( const char *msg, ... )
|
||||||
|
{
|
||||||
|
va_list va;
|
||||||
|
|
||||||
|
va_start( va, msg );
|
||||||
|
vdebugn( DEBUG_DRV, msg, va );
|
||||||
|
va_end( va );
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char Flags[] = { 'D', 'F', 'R', 'S', 'T' };
|
||||||
|
|
||||||
|
static char *
|
||||||
|
proxy_make_flags( int flags, char *buf )
|
||||||
|
{
|
||||||
|
uint i, d;
|
||||||
|
|
||||||
|
for (d = 0, i = 0; i < as(Flags); i++)
|
||||||
|
if (flags & (1 << i))
|
||||||
|
buf[d++] = Flags[i];
|
||||||
|
buf[d] = 0;
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
proxy_store_deref( proxy_store_t *ctx )
|
||||||
|
{
|
||||||
|
if (!--ctx->ref_count)
|
||||||
|
free( ctx );
|
||||||
|
}
|
||||||
|
|
||||||
|
static int curr_tag;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int ref_count;
|
||||||
|
int tag;
|
||||||
|
proxy_store_t *ctx;
|
||||||
|
} gen_cmd_t;
|
||||||
|
|
||||||
|
static gen_cmd_t *
|
||||||
|
proxy_cmd_new( proxy_store_t *ctx, int sz )
|
||||||
|
{
|
||||||
|
gen_cmd_t *cmd = nfmalloc( sz );
|
||||||
|
cmd->ref_count = 2;
|
||||||
|
cmd->tag = ++curr_tag;
|
||||||
|
cmd->ctx = ctx;
|
||||||
|
ctx->ref_count++;
|
||||||
|
return cmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
proxy_cmd_done( gen_cmd_t *cmd )
|
||||||
|
{
|
||||||
|
if (!--cmd->ref_count) {
|
||||||
|
proxy_store_deref( cmd->ctx );
|
||||||
|
free( cmd );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
//# TEMPLATE GETTER
|
||||||
|
static @type@proxy_@name@( store_t *gctx )
|
||||||
|
{
|
||||||
|
proxy_store_t *ctx = (proxy_store_t *)gctx;
|
||||||
|
|
||||||
|
@type@rv = ctx->real_driver->@name@( ctx->real_store );
|
||||||
|
debug( "%sCalled @name@, ret=@fmt@\n", ctx->label, rv );
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
//# END
|
||||||
|
|
||||||
|
//# TEMPLATE REGULAR
|
||||||
|
static @type@proxy_@name@( store_t *gctx@decl_args@ )
|
||||||
|
{
|
||||||
|
proxy_store_t *ctx = (proxy_store_t *)gctx;
|
||||||
|
|
||||||
|
@pre_print_args@
|
||||||
|
debug( "%sEnter @name@@print_fmt_args@\n", ctx->label@print_pass_args@ );
|
||||||
|
@print_args@
|
||||||
|
@type@rv = ctx->real_driver->@name@( ctx->real_store@pass_args@ );
|
||||||
|
debug( "%sLeave @name@, ret=@fmt@\n", ctx->label, rv );
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
//# END
|
||||||
|
|
||||||
|
//# TEMPLATE REGULAR_VOID
|
||||||
|
static void proxy_@name@( store_t *gctx@decl_args@ )
|
||||||
|
{
|
||||||
|
proxy_store_t *ctx = (proxy_store_t *)gctx;
|
||||||
|
|
||||||
|
@pre_print_args@
|
||||||
|
debug( "%sEnter @name@@print_fmt_args@\n", ctx->label@print_pass_args@ );
|
||||||
|
@print_args@
|
||||||
|
ctx->real_driver->@name@( ctx->real_store@pass_args@ );
|
||||||
|
debug( "%sLeave @name@\n", ctx->label );
|
||||||
|
@action@
|
||||||
|
}
|
||||||
|
//# END
|
||||||
|
|
||||||
|
//# TEMPLATE CALLBACK
|
||||||
|
typedef struct {
|
||||||
|
gen_cmd_t gen;
|
||||||
|
void (*callback)( @decl_cb_args@void *aux );
|
||||||
|
void *callback_aux;
|
||||||
|
@decl_state@
|
||||||
|
} @name@_cmd_t;
|
||||||
|
|
||||||
|
static void
|
||||||
|
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@ );
|
||||||
|
@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 );
|
||||||
|
proxy_cmd_done( &cmd->gen );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
proxy_@name@( store_t *gctx@decl_args@, void (*cb)( @decl_cb_args@void *aux ), void *aux )
|
||||||
|
{
|
||||||
|
proxy_store_t *ctx = (proxy_store_t *)gctx;
|
||||||
|
|
||||||
|
@name@_cmd_t *cmd = (@name@_cmd_t *)proxy_cmd_new( ctx, sizeof(@name@_cmd_t) );
|
||||||
|
cmd->callback = cb;
|
||||||
|
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@ );
|
||||||
|
@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 );
|
||||||
|
proxy_cmd_done( &cmd->gen );
|
||||||
|
}
|
||||||
|
//# END
|
||||||
|
|
||||||
|
//# UNDEFINE list_store_print_fmt_cb_args
|
||||||
|
//# UNDEFINE list_store_print_pass_cb_args
|
||||||
|
//# DEFINE list_store_print_cb_args
|
||||||
|
if (sts == DRV_OK) {
|
||||||
|
for (string_list_t *box = boxes; box; box = box->next)
|
||||||
|
debug( " %s\n", box->string );
|
||||||
|
}
|
||||||
|
//# END
|
||||||
|
|
||||||
|
//# DEFINE load_box_pre_print_args
|
||||||
|
static char ubuf[12];
|
||||||
|
//# END
|
||||||
|
//# DEFINE load_box_print_fmt_args , [%d,%s] (new >= %d, seen <= %d)
|
||||||
|
//# DEFINE load_box_print_pass_args , minuid, (maxuid == INT_MAX) ? "inf" : (nfsnprintf( ubuf, sizeof(ubuf), "%d", maxuid ), ubuf), newuid, seenuid
|
||||||
|
//# DEFINE load_box_print_args
|
||||||
|
if (excs.size) {
|
||||||
|
debugn( " excs:" );
|
||||||
|
for (int t = 0; t < excs.size; t++)
|
||||||
|
debugn( " %d", excs.data[t] );
|
||||||
|
debug( "\n" );
|
||||||
|
}
|
||||||
|
//# END
|
||||||
|
//# DEFINE load_box_pre_print_cb_args
|
||||||
|
static char fbuf[as(Flags) + 1];
|
||||||
|
//# END
|
||||||
|
//# DEFINE load_box_print_fmt_cb_args , sts=%d, total=%d, recent=%d
|
||||||
|
//# DEFINE load_box_print_pass_cb_args , sts, total_msgs, recent_msgs
|
||||||
|
//# DEFINE load_box_print_cb_args
|
||||||
|
if (sts == DRV_OK) {
|
||||||
|
for (message_t *msg = msgs; msg; msg = msg->next)
|
||||||
|
debug( " uid=%5d, flags=%4s, size=%6d, tuid=%." stringify(TUIDL) "s\n",
|
||||||
|
msg->uid, (msg->status & M_FLAGS) ? (proxy_make_flags( msg->flags, fbuf ), fbuf) : "?", msg->size, *msg->tuid ? msg->tuid : "?" );
|
||||||
|
}
|
||||||
|
//# END
|
||||||
|
|
||||||
|
//# DEFINE find_new_msgs_print_fmt_cb_args , sts=%d
|
||||||
|
//# DEFINE find_new_msgs_print_pass_cb_args , sts
|
||||||
|
//# DEFINE find_new_msgs_print_cb_args
|
||||||
|
if (sts == DRV_OK) {
|
||||||
|
for (message_t *msg = msgs; msg; msg = msg->next)
|
||||||
|
debug( " uid=%5d, tuid=%." stringify(TUIDL) "s\n", msg->uid, msg->tuid );
|
||||||
|
}
|
||||||
|
//# END
|
||||||
|
|
||||||
|
//# DEFINE fetch_msg_decl_state
|
||||||
|
msg_data_t *data;
|
||||||
|
//# END
|
||||||
|
//# DEFINE fetch_msg_assign_state
|
||||||
|
cmd->data = data;
|
||||||
|
//# END
|
||||||
|
//# DEFINE fetch_msg_print_fmt_args , uid=%d, want_flags=%s, want_date=%s
|
||||||
|
//# DEFINE fetch_msg_print_pass_args , msg->uid, !(msg->status & M_FLAGS) ? "yes" : "no", data->date ? "yes" : "no"
|
||||||
|
//# DEFINE fetch_msg_pre_print_cb_args
|
||||||
|
static char fbuf[as(Flags) + 1];
|
||||||
|
proxy_make_flags( cmd->data->flags, fbuf );
|
||||||
|
//# END
|
||||||
|
//# DEFINE fetch_msg_print_fmt_cb_args , flags=%s, date=%ld, size=%d
|
||||||
|
//# DEFINE fetch_msg_print_pass_cb_args , fbuf, 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 );
|
||||||
|
fwrite( cmd->data->data, cmd->data->len, 1, stdout );
|
||||||
|
printf( "%s=========\n", cmd->gen.ctx->label );
|
||||||
|
fflush( stdout );
|
||||||
|
}
|
||||||
|
//# END
|
||||||
|
|
||||||
|
//# DEFINE store_msg_pre_print_args
|
||||||
|
static char fbuf[as(Flags) + 1];
|
||||||
|
proxy_make_flags( data->flags, fbuf );
|
||||||
|
//# END
|
||||||
|
//# DEFINE store_msg_print_fmt_args , flags=%s, date=%ld, size=%d, to_trash=%s
|
||||||
|
//# DEFINE store_msg_print_pass_args , fbuf, data->date, data->len, to_trash ? "yes" : "no"
|
||||||
|
//# DEFINE store_msg_print_args
|
||||||
|
if (DFlags & DEBUG_DRV_ALL) {
|
||||||
|
printf( "%s>>>>>>>>>\n", ctx->label );
|
||||||
|
fwrite( data->data, data->len, 1, stdout );
|
||||||
|
printf( "%s>>>>>>>>>\n", ctx->label );
|
||||||
|
fflush( stdout );
|
||||||
|
}
|
||||||
|
//# END
|
||||||
|
|
||||||
|
//# DEFINE set_msg_flags_pre_print_args
|
||||||
|
static char fbuf1[as(Flags) + 1], fbuf2[as(Flags) + 1];
|
||||||
|
proxy_make_flags( add, fbuf1 );
|
||||||
|
proxy_make_flags( del, fbuf2 );
|
||||||
|
//# END
|
||||||
|
//# DEFINE set_msg_flags_print_fmt_args , uid=%d, add=%s, del=%s
|
||||||
|
//# DEFINE set_msg_flags_print_pass_args , uid, fbuf1, fbuf2
|
||||||
|
|
||||||
|
//# DEFINE trash_msg_print_fmt_args , uid=%d
|
||||||
|
//# DEFINE trash_msg_print_pass_args , msg->uid
|
||||||
|
|
||||||
|
//# DEFINE free_store_action
|
||||||
|
proxy_store_deref( ctx );
|
||||||
|
//# END
|
||||||
|
|
||||||
|
//# DEFINE cancel_store_action
|
||||||
|
proxy_store_deref( ctx );
|
||||||
|
//# END
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//# SPECIAL commit_cmds
|
||||||
|
static void
|
||||||
|
proxy_commit_cmds( store_t *gctx )
|
||||||
|
{
|
||||||
|
// Currently a dummy in all real drivers.
|
||||||
|
(void) gctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
//# SPECIAL set_bad_callback
|
||||||
|
static void
|
||||||
|
proxy_set_bad_callback( store_t *gctx, void (*cb)( void *aux ), void *aux )
|
||||||
|
{
|
||||||
|
proxy_store_t *ctx = (proxy_store_t *)gctx;
|
||||||
|
|
||||||
|
ctx->bad_callback = cb;
|
||||||
|
ctx->bad_callback_aux = aux;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
proxy_invoke_bad_callback( proxy_store_t *ctx )
|
||||||
|
{
|
||||||
|
debug( "%sCallback enter bad store\n", ctx->label );
|
||||||
|
ctx->bad_callback( ctx->bad_callback_aux );
|
||||||
|
debug( "%sCallback leave bad store\n", ctx->label ); \
|
||||||
|
}
|
||||||
|
|
||||||
|
//# EXCLUDE alloc_store
|
||||||
|
store_t *
|
||||||
|
proxy_alloc_store( store_t *real_ctx, const char *label )
|
||||||
|
{
|
||||||
|
proxy_store_t *ctx;
|
||||||
|
|
||||||
|
ctx = nfcalloc( sizeof(*ctx) );
|
||||||
|
ctx->gen.driver = &proxy_driver;
|
||||||
|
ctx->gen.conf = real_ctx->conf;
|
||||||
|
ctx->ref_count = 1;
|
||||||
|
ctx->label = label;
|
||||||
|
ctx->real_driver = real_ctx->driver;
|
||||||
|
ctx->real_store = real_ctx;
|
||||||
|
ctx->real_driver->set_bad_callback( ctx->real_store, (void (*)(void *))proxy_invoke_bad_callback, ctx );
|
||||||
|
return &ctx->gen;
|
||||||
|
}
|
||||||
|
|
||||||
|
//# EXCLUDE parse_store
|
||||||
|
//# EXCLUDE cleanup
|
||||||
|
//# EXCLUDE get_fail_state
|
||||||
|
|
||||||
|
#include "drv_proxy.inc"
|
169
src/drv_proxy_gen.pl
Executable file
169
src/drv_proxy_gen.pl
Executable file
|
@ -0,0 +1,169 @@
|
||||||
|
#!/usr/bin/perl
|
||||||
|
#
|
||||||
|
# mbsync - mailbox synchronizer
|
||||||
|
# Copyright (C) 2017 Oswald Buddenhagen <ossi@users.sf.net>
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
# As a special exception, mbsync may be linked with the OpenSSL library,
|
||||||
|
# despite that library's more restrictive license.
|
||||||
|
#
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
die("Usage: $0 driver.h drv_proxy.c drv_proxy.inc\n")
|
||||||
|
if ($#ARGV != 2);
|
||||||
|
|
||||||
|
my ($in_header, $in_source, $out_source) = @ARGV;
|
||||||
|
|
||||||
|
my %templates;
|
||||||
|
my %defines;
|
||||||
|
my %excluded;
|
||||||
|
my %special;
|
||||||
|
|
||||||
|
open(my $ins, $in_source) or die("Cannot open $in_source: $!\n");
|
||||||
|
my $template;
|
||||||
|
my $define;
|
||||||
|
my $conts;
|
||||||
|
while (<$ins>) {
|
||||||
|
if ($template) {
|
||||||
|
if (/^\/\/\# END$/) {
|
||||||
|
$templates{$template} = $conts;
|
||||||
|
$template = undef;
|
||||||
|
} else {
|
||||||
|
$conts .= $_;
|
||||||
|
}
|
||||||
|
} elsif ($define) {
|
||||||
|
if (/^\/\/\# END$/) {
|
||||||
|
$defines{$define} = $conts;
|
||||||
|
$define = undef;
|
||||||
|
} else {
|
||||||
|
$conts .= $_;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (/^\/\/\# TEMPLATE (\w+)$/) {
|
||||||
|
$template = $1;
|
||||||
|
$conts = "";
|
||||||
|
} elsif (/^\/\/\# DEFINE (\w+)$/) {
|
||||||
|
$define = $1;
|
||||||
|
$conts = "";
|
||||||
|
} elsif (/^\/\/\# DEFINE (\w+) (.*)$/) {
|
||||||
|
$defines{$1} = $2;
|
||||||
|
} elsif (/^\/\/\# UNDEFINE (\w+)$/) {
|
||||||
|
$defines{$1} = "";
|
||||||
|
} elsif (/^\/\/\# EXCLUDE (\w+)$/) {
|
||||||
|
$excluded{$1} = 1;
|
||||||
|
} elsif (/^\/\/\# SPECIAL (\w+)$/) {
|
||||||
|
$special{$1} = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
close($ins);
|
||||||
|
|
||||||
|
open(my $inh, $in_header) or die("Cannot open $in_header: $!\n");
|
||||||
|
my $sts = 0;
|
||||||
|
my $cont = "";
|
||||||
|
while (<$inh>) {
|
||||||
|
if ($sts == 0) {
|
||||||
|
if (/^struct driver \{$/) {
|
||||||
|
$sts = 1;
|
||||||
|
}
|
||||||
|
} elsif ($sts == 1) {
|
||||||
|
if (/^\};$/) {
|
||||||
|
$sts = 0;
|
||||||
|
} else {
|
||||||
|
$cont .= $_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
close($inh);
|
||||||
|
|
||||||
|
$cont =~ s,\n, ,g;
|
||||||
|
$cont =~ s,/\*.*?\*/, ,g;
|
||||||
|
$cont =~ s,\h+, ,g;
|
||||||
|
my @ptypes = map { s,^ ,,r } split(/;/, $cont);
|
||||||
|
pop @ptypes; # last one is empty
|
||||||
|
|
||||||
|
my @cmd_table;
|
||||||
|
|
||||||
|
sub make_args($)
|
||||||
|
{
|
||||||
|
$_ = shift;
|
||||||
|
s/(?:^|(?<=, ))(?:const )?\w+ \*?//g;
|
||||||
|
return $_;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub type_to_format($)
|
||||||
|
{
|
||||||
|
$_ = shift;
|
||||||
|
s/xint /\%\#x/g;
|
||||||
|
s/int /\%d/g;
|
||||||
|
s/const char \*/\%s/g;
|
||||||
|
return $_;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub make_format($)
|
||||||
|
{
|
||||||
|
$_ = type_to_format(shift);
|
||||||
|
s/, (\%\#?.)(\w+)/, $2=$1/g;
|
||||||
|
return $_;
|
||||||
|
}
|
||||||
|
|
||||||
|
open(my $outh, ">".$out_source) or die("Cannot create $out_source: $!\n");
|
||||||
|
|
||||||
|
for (@ptypes) {
|
||||||
|
/^([\w* ]+)\(\*(\w+)\)\( (.*) \)$/ or die("Cannot parse prototype '$_'\n");
|
||||||
|
my ($cmd_type, $cmd_name, $cmd_args) = ($1, $2, $3);
|
||||||
|
if (defined($excluded{$cmd_name})) {
|
||||||
|
push @cmd_table, "0";
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
push @cmd_table, "proxy_$cmd_name";
|
||||||
|
next if (defined($special{$cmd_name}));
|
||||||
|
my %replace;
|
||||||
|
$replace{'name'} = $cmd_name;
|
||||||
|
$replace{'type'} = $cmd_type;
|
||||||
|
$cmd_args =~ s/^store_t \*ctx// or die("Arguments '$cmd_args' don't start with 'store_t *ctx'\n");
|
||||||
|
if ($cmd_type eq "void " && $cmd_args =~ s/, void \(\*cb\)\( (.*)void \*aux \), void \*aux$//) {
|
||||||
|
my $cmd_cb_args = $1;
|
||||||
|
$replace{'decl_cb_args'} = $cmd_cb_args;
|
||||||
|
$replace{'pass_cb_args'} = make_args($cmd_cb_args);
|
||||||
|
my $cmd_print_cb_args = $cmd_cb_args =~ s/(.*), $/, $1/r;
|
||||||
|
$replace{'print_pass_cb_args'} = make_args($cmd_print_cb_args);
|
||||||
|
$replace{'print_fmt_cb_args'} = make_format($cmd_print_cb_args);
|
||||||
|
$template = "CALLBACK";
|
||||||
|
} elsif ($cmd_name =~ /^get_/) {
|
||||||
|
$template = "GETTER";
|
||||||
|
$replace{'fmt'} = type_to_format($cmd_type);
|
||||||
|
} elsif ($cmd_type eq "void ") {
|
||||||
|
$template = "REGULAR_VOID";
|
||||||
|
} else {
|
||||||
|
$template = "REGULAR";
|
||||||
|
$replace{'fmt'} = type_to_format($cmd_type);
|
||||||
|
}
|
||||||
|
$replace{'decl_args'} = $cmd_args;
|
||||||
|
$replace{'print_pass_args'} = $replace{'pass_args'} = make_args($cmd_args);
|
||||||
|
$replace{'print_fmt_args'} = make_format($cmd_args);
|
||||||
|
for (keys %defines) {
|
||||||
|
$replace{$1} = $defines{$_} if (/^${cmd_name}_(.*)$/);
|
||||||
|
}
|
||||||
|
my $text = $templates{$template};
|
||||||
|
$text =~ s/^\h*\@(\w+)\@\n/$replace{$1} \/\/ ""/smeg;
|
||||||
|
$text =~ s/\@(\w+)\@/$replace{$1} \/\/ ""/eg;
|
||||||
|
print $outh $text."\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
print $outh "struct driver proxy_driver = {\n".join("", map { "\t$_,\n" } @cmd_table)."};\n";
|
||||||
|
close $outh;
|
29
src/main.c
29
src/main.c
|
@ -462,6 +462,10 @@ main( int argc, char **argv )
|
||||||
op = VERBOSE | DEBUG_ALL;
|
op = VERBOSE | DEBUG_ALL;
|
||||||
else if (!strcmp( opt, "-crash" ))
|
else if (!strcmp( opt, "-crash" ))
|
||||||
op = DEBUG_CRASH;
|
op = DEBUG_CRASH;
|
||||||
|
else if (!strcmp( opt, "-driver" ))
|
||||||
|
op = VERBOSE | DEBUG_DRV;
|
||||||
|
else if (!strcmp( opt, "-driver-all" ))
|
||||||
|
op = VERBOSE | DEBUG_DRV | DEBUG_DRV_ALL;
|
||||||
else if (!strcmp( opt, "-maildir" ))
|
else if (!strcmp( opt, "-maildir" ))
|
||||||
op = VERBOSE | DEBUG_MAILDIR;
|
op = VERBOSE | DEBUG_MAILDIR;
|
||||||
else if (!strcmp( opt, "-main" ))
|
else if (!strcmp( opt, "-main" ))
|
||||||
|
@ -648,6 +652,12 @@ main( int argc, char **argv )
|
||||||
case 'C':
|
case 'C':
|
||||||
op |= DEBUG_CRASH;
|
op |= DEBUG_CRASH;
|
||||||
break;
|
break;
|
||||||
|
case 'd':
|
||||||
|
op |= DEBUG_DRV | VERBOSE;
|
||||||
|
break;
|
||||||
|
case 'D':
|
||||||
|
op |= DEBUG_DRV | DEBUG_DRV_ALL | VERBOSE;
|
||||||
|
break;
|
||||||
case 'm':
|
case 'm':
|
||||||
op |= DEBUG_MAILDIR | VERBOSE;
|
op |= DEBUG_MAILDIR | VERBOSE;
|
||||||
break;
|
break;
|
||||||
|
@ -811,14 +821,20 @@ sync_chans( main_vars_t *mvars, int ent )
|
||||||
if (mvars->skip)
|
if (mvars->skip)
|
||||||
goto next2;
|
goto next2;
|
||||||
mvars->state[M] = mvars->state[S] = ST_FRESH;
|
mvars->state[M] = mvars->state[S] = ST_FRESH;
|
||||||
if (mvars->chan->stores[M]->driver->get_caps( 0 ) & mvars->chan->stores[S]->driver->get_caps( 0 ) & DRV_VERBOSE)
|
if ((DFlags & DEBUG_DRV) || (mvars->chan->stores[M]->driver->get_caps( 0 ) & mvars->chan->stores[S]->driver->get_caps( 0 ) & DRV_VERBOSE))
|
||||||
labels[M] = "M: ", labels[S] = "S: ";
|
labels[M] = "M: ", labels[S] = "S: ";
|
||||||
else
|
else
|
||||||
labels[M] = labels[S] = "";
|
labels[M] = labels[S] = "";
|
||||||
for (t = 0; t < 2; t++) {
|
for (t = 0; t < 2; t++) {
|
||||||
mvars->drv[t] = mvars->chan->stores[t]->driver;
|
driver_t *drv = mvars->chan->stores[t]->driver;
|
||||||
mvars->ctx[t] = mvars->drv[t]->alloc_store( mvars->chan->stores[t], labels[t] );
|
store_t *ctx = drv->alloc_store( mvars->chan->stores[t], labels[t] );
|
||||||
mvars->drv[t]->set_bad_callback( mvars->ctx[t], store_bad, AUX );
|
if (DFlags & DEBUG_DRV) {
|
||||||
|
drv = &proxy_driver;
|
||||||
|
ctx = proxy_alloc_store( ctx, labels[t] );
|
||||||
|
}
|
||||||
|
mvars->drv[t] = drv;
|
||||||
|
mvars->ctx[t] = ctx;
|
||||||
|
drv->set_bad_callback( ctx, store_bad, AUX );
|
||||||
}
|
}
|
||||||
for (t = 0; ; t++) {
|
for (t = 0; ; t++) {
|
||||||
info( "Opening %s store %s...\n", str_ms[t], mvars->chan->stores[t]->name );
|
info( "Opening %s store %s...\n", str_ms[t], mvars->chan->stores[t]->name );
|
||||||
|
@ -1008,11 +1024,6 @@ store_listed( int sts, string_list_t *boxes, void *aux )
|
||||||
case DRV_CANCELED:
|
case DRV_CANCELED:
|
||||||
return;
|
return;
|
||||||
case DRV_OK:
|
case DRV_OK:
|
||||||
if (DFlags & DEBUG_MAIN) {
|
|
||||||
debug( "got mailbox list from %s:\n", str_ms[t] );
|
|
||||||
for (box = boxes; box; box = box->next)
|
|
||||||
debug( " %s\n", box->string );
|
|
||||||
}
|
|
||||||
for (box = boxes; box; box = box->next) {
|
for (box = boxes; box; box = box->next) {
|
||||||
if (mvars->ctx[t]->conf->flat_delim) {
|
if (mvars->ctx[t]->conf->flat_delim) {
|
||||||
string_list_t *nbox;
|
string_list_t *nbox;
|
||||||
|
|
|
@ -83,12 +83,16 @@ Display version information.
|
||||||
\fB-V\fR, \fB--verbose\fR
|
\fB-V\fR, \fB--verbose\fR
|
||||||
Enable \fIverbose\fR mode, which displays what is currently happening.
|
Enable \fIverbose\fR mode, which displays what is currently happening.
|
||||||
.TP
|
.TP
|
||||||
\fB-D\fR[\fBC\fR][\fBm\fR][\fBM\fR][\fBn\fR|\fBN\fR][\fBs\fR]\fR]\fR,\
|
\fB-D\fR[\fBC\fR][\fBd\fR|\fBD\fR][\fBm\fR][\fBM\fR][\fBn\fR|\fBN\fR][\fBs\fR]\fR]\fR,\
|
||||||
\fB--debug\fR[\fB-crash\fR|\fB-maildir\fR|\fB-main\fR|\fB-net\fR|\fB-net-all\fR|\fB-sync\fR]
|
\fB--debug\fR[\fB-crash\fR|\fB-driver\fR|\fB-driver-all\fR|\fB-maildir\fR|\fB-main\fR|\fB-net\fR|\fB-net-all\fR|\fB-sync\fR]
|
||||||
Enable debugging categories:
|
Enable debugging categories:
|
||||||
.in +4
|
.in +4
|
||||||
\fBC\fR, \fBcrash\fR - use built-in crash handler
|
\fBC\fR, \fBcrash\fR - use built-in crash handler
|
||||||
.br
|
.br
|
||||||
|
\fBd\fR, \fBdriver\fR - print driver calls (metadata only)
|
||||||
|
.br
|
||||||
|
\fBD\fR, \fBdriver-all\fR - print driver calls (including messages)
|
||||||
|
.br
|
||||||
\fBm\fR, \fBmaildir\fR - print maildir debug info
|
\fBm\fR, \fBmaildir\fR - print maildir debug info
|
||||||
.br
|
.br
|
||||||
\fBM\fR, \fBmain\fR - print main debug info
|
\fBM\fR, \fBmain\fR - print main debug info
|
||||||
|
|
17
src/sync.c
17
src/sync.c
|
@ -1003,7 +1003,7 @@ sync_boxes( store_t *ctx[], const char *names[], int present[], channel_conf_t *
|
||||||
sync_bail3( svars );
|
sync_bail3( svars );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
svars->drv[t] = ctx[t]->conf->driver;
|
svars->drv[t] = ctx[t]->driver;
|
||||||
svars->drv[t]->set_bad_callback( ctx[t], store_bad, AUX );
|
svars->drv[t]->set_bad_callback( ctx[t], store_bad, AUX );
|
||||||
}
|
}
|
||||||
/* Both boxes must be fully set up at this point, so that error exit paths
|
/* Both boxes must be fully set up at this point, so that error exit paths
|
||||||
|
@ -1284,10 +1284,6 @@ box_opened2( sync_vars_t *svars, int t )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sort_int_array( mexcs.array );
|
sort_int_array( mexcs.array );
|
||||||
debugn( " exception list is:" );
|
|
||||||
for (t = 0; t < mexcs.array.size; t++)
|
|
||||||
debugn( " %d", mexcs.array.data[t] );
|
|
||||||
debug( "\n" );
|
|
||||||
} else {
|
} else {
|
||||||
minwuid = 1;
|
minwuid = 1;
|
||||||
}
|
}
|
||||||
|
@ -1336,10 +1332,6 @@ load_box( sync_vars_t *svars, int t, int minwuid, int_array_t mexcs )
|
||||||
seenuid = svars->maxuid[t];
|
seenuid = svars->maxuid[t];
|
||||||
}
|
}
|
||||||
info( "Loading %s...\n", str_ms[t] );
|
info( "Loading %s...\n", str_ms[t] );
|
||||||
if (maxwuid == INT_MAX)
|
|
||||||
debug( "loading %s [%d,inf] (new >= %d, seen <= %d)\n", str_ms[t], minwuid, svars->newuid[t], seenuid );
|
|
||||||
else
|
|
||||||
debug( "loading %s [%d,%d] (new >= %d, seen <= %d)\n", str_ms[t], minwuid, maxwuid, svars->newuid[t], seenuid );
|
|
||||||
svars->drv[t]->load_box( svars->ctx[t], minwuid, maxwuid, svars->newuid[t], seenuid, mexcs, box_loaded, AUX );
|
svars->drv[t]->load_box( svars->ctx[t], minwuid, maxwuid, svars->newuid[t], seenuid, mexcs, box_loaded, AUX );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1372,7 +1364,6 @@ box_loaded( int sts, message_t *msgs, int total_msgs, int recent_msgs, void *aux
|
||||||
int uid, no[2], del[2], alive, todel, t1, t2;
|
int uid, no[2], del[2], alive, todel, t1, t2;
|
||||||
int sflags, nflags, aflags, dflags;
|
int sflags, nflags, aflags, dflags;
|
||||||
uint hashsz, idx;
|
uint hashsz, idx;
|
||||||
char fbuf[16]; /* enlarge when support for keywords is added */
|
|
||||||
|
|
||||||
if (check_ret( sts, aux ))
|
if (check_ret( sts, aux ))
|
||||||
return;
|
return;
|
||||||
|
@ -1406,10 +1397,6 @@ box_loaded( int sts, message_t *msgs, int total_msgs, int recent_msgs, void *aux
|
||||||
if (tmsg->srec) /* found by TUID */
|
if (tmsg->srec) /* found by TUID */
|
||||||
continue;
|
continue;
|
||||||
uid = tmsg->uid;
|
uid = tmsg->uid;
|
||||||
if (DFlags & DEBUG_SYNC) {
|
|
||||||
make_flags( tmsg->flags, fbuf );
|
|
||||||
printf( tmsg->size ? " message %5d, %-4s, %6d: " : " message %5d, %-4s: ", uid, fbuf, tmsg->size );
|
|
||||||
}
|
|
||||||
idx = (uint)((uint)uid * 1103515245U) % hashsz;
|
idx = (uint)((uint)uid * 1103515245U) % hashsz;
|
||||||
while (srecmap[idx].uid) {
|
while (srecmap[idx].uid) {
|
||||||
if (srecmap[idx].uid == uid) {
|
if (srecmap[idx].uid == uid) {
|
||||||
|
@ -1419,12 +1406,10 @@ box_loaded( int sts, message_t *msgs, int total_msgs, int recent_msgs, void *aux
|
||||||
if (++idx == hashsz)
|
if (++idx == hashsz)
|
||||||
idx = 0;
|
idx = 0;
|
||||||
}
|
}
|
||||||
debug( "new\n" );
|
|
||||||
continue;
|
continue;
|
||||||
found:
|
found:
|
||||||
tmsg->srec = srec;
|
tmsg->srec = srec;
|
||||||
srec->msg[t] = tmsg;
|
srec->msg[t] = tmsg;
|
||||||
debug( "pairs %5d\n", srec->uid[1-t] );
|
|
||||||
}
|
}
|
||||||
free( srecmap );
|
free( srecmap );
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user