@ -57,6 +57,8 @@ typedef struct maildir_store_conf {
# ifdef USE_DB
int alt_map ;
# endif /* USE_DB */
char info_delimiter ;
char * info_prefix , * info_stop ; /* precalculated from info_delimiter */
} maildir_store_conf_t ;
typedef struct maildir_message {
@ -84,14 +86,14 @@ static int MaildirCount;
static const char Flags [ ] = { ' D ' , ' F ' , ' R ' , ' S ' , ' T ' } ;
static unsigned char
maildir_parse_flags ( const char * base )
maildir_parse_flags ( const char * info_prefix , const char * base )
{
const char * s ;
unsigned i ;
unsigned char flags ;
flags = 0 ;
if ( ( s = strstr ( base , " :2, " ) ) )
if ( ( s = strstr ( base , info_prefix ) ) )
for ( s + = 3 , i = 0 ; i < as ( Flags ) ; i + + )
if ( strchr ( s , Flags [ i ] ) )
flags | = ( 1 < < i ) ;
@ -413,9 +415,9 @@ maildir_validate( const char *box, int create, maildir_store_t *ctx )
# ifdef USE_DB
static void
make_key ( DBT * tkey , char * name )
make_key ( const char * info_stop , DBT * tkey , char * name )
{
char * u = strpbrk ( name , " :, " ) ;
char * u = strpbrk ( name , info_stop ) ;
tkey - > data = name ;
tkey - > size = u ? ( size_t ) ( u - name ) : strlen ( name ) ;
}
@ -439,7 +441,7 @@ maildir_set_uid( maildir_store_t *ctx, const char *name, int *uid )
return DRV_BOX_BAD ;
}
if ( uid ) {
make_key ( & key , ( char * ) name ) ;
make_key ( ( ( maildir_store_conf_t * ) ctx - > gen . conf ) - > info_stop , & key , ( char * ) name ) ;
value . data = uid ;
value . size = sizeof ( * uid ) ;
if ( ( ret = ctx - > db - > put ( ctx - > db , 0 , & key , & value , 0 ) ) )
@ -615,6 +617,7 @@ maildir_compare( const void *l, const void *r )
static int
maildir_scan ( maildir_store_t * ctx , msglist_t * msglist )
{
maildir_store_conf_t * conf = ( maildir_store_conf_t * ) ctx - > gen . conf ;
DIR * d ;
FILE * f ;
struct dirent * e ;
@ -694,7 +697,7 @@ maildir_scan( maildir_store_t *ctx, msglist_t *msglist )
ctx - > gen . recent + = i ;
# ifdef USE_DB
if ( ctx - > db ) {
make_key ( & key , e - > d_name ) ;
make_key ( conf - > info_stop , & key , e - > d_name ) ;
if ( ( ret = ctx - > db - > get ( ctx - > db , 0 , & key , & value , 0 ) ) ) {
if ( ret ! = DB_NOTFOUND ) {
ctx - > db - > err ( ctx - > db , ret , " Maildir error: db->get() " ) ;
@ -834,7 +837,7 @@ maildir_scan( maildir_store_t *ctx, msglist_t *msglist )
if ( ( u = strstr ( entry - > base , " ,U= " ) ) )
for ( ru = u + 3 ; isdigit ( ( unsigned char ) * ru ) ; ru + + ) ;
else
u = ru = strchr ( entry - > base , ' : ' ) ;
u = ru = strchr ( entry - > base , conf - > info_delimiter ) ;
fnl = ( u ?
nfsnprintf ( buf + bl , sizeof ( buf ) - bl , " %s/%.*s,U=%d%s " , subdirs [ entry - > recent ] , ( int ) ( u - entry - > base ) , entry - > base , uid , ru ) :
nfsnprintf ( buf + bl , sizeof ( buf ) - bl , " %s/%s,U=%d " , subdirs [ entry - > recent ] , entry - > base , uid ) )
@ -906,7 +909,7 @@ maildir_init_msg( maildir_store_t *ctx, maildir_message_t *msg, msg_t *entry )
msg - > gen . status | = M_RECENT ;
if ( ctx - > gen . opts & OPEN_FLAGS ) {
msg - > gen . status | = M_FLAGS ;
msg - > gen . flags = maildir_parse_flags ( msg - > base ) ;
msg - > gen . flags = maildir_parse_flags ( ( ( maildir_store_conf_t * ) ctx - > gen . conf ) - > info_prefix , msg - > base ) ;
} else
msg - > gen . flags = 0 ;
}
@ -1177,16 +1180,16 @@ maildir_fetch_msg( store_t *gctx, message_t *gmsg, msg_data_t *data,
}
close ( fd ) ;
if ( ! ( gmsg - > status & M_FLAGS ) )
data - > flags = maildir_parse_flags ( msg - > base ) ;
data - > flags = maildir_parse_flags ( ( ( maildir_store_conf_t * ) gctx - > conf ) - > info_prefix , msg - > base ) ;
cb ( DRV_OK , aux ) ;
}
static int
maildir_make_flags ( int flags , char * buf )
maildir_make_flags ( char info_delimiter , int flags , char * buf )
{
unsigned i , d ;
buf [ 0 ] = ' : ' ;
buf [ 0 ] = info_delimiter ;
buf [ 1 ] = ' 2 ' ;
buf [ 2 ] = ' , ' ;
for ( d = 3 , i = 0 ; i < as ( Flags ) ; i + + )
@ -1231,7 +1234,7 @@ maildir_store_msg( store_t *gctx, msg_data_t *data, int to_trash,
box = ctx - > trash ;
}
maildir_make_flags ( data - > flags , fbuf ) ;
maildir_make_flags ( ( ( maildir_store_conf_t * ) gctx - > 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 ) {
@ -1302,6 +1305,7 @@ static void
maildir_set_flags ( store_t * gctx , message_t * gmsg , int 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_message_t * msg = ( maildir_message_t * ) gmsg ;
char * s , * p ;
@ -1319,7 +1323,7 @@ maildir_set_flags( store_t *gctx, message_t *gmsg, int uid ATTR_UNUSED, int add,
oob ( ) ;
memcpy ( buf + bl , msg - > base , ol + 1 ) ;
memcpy ( nbuf + bl , msg - > base , ol + 1 ) ;
if ( ( s = strstr ( nbuf + bl , " :2, " ) ) ) {
if ( ( s = strstr ( nbuf + bl , conf - > info_prefix ) ) ) {
s + = 3 ;
fl = ol - ( s - ( nbuf + bl ) ) ;
for ( i = 0 ; i < as ( Flags ) ; i + + ) {
@ -1337,7 +1341,7 @@ maildir_set_flags( store_t *gctx, message_t *gmsg, int uid ATTR_UNUSED, int add,
}
tl = ol + 3 + fl ;
} else {
tl = ol + maildir_make_flags ( msg - > gen . flags , nbuf + bl + ol ) ;
tl = ol + maildir_make_flags ( conf - > info_delimiter , msg - > gen . flags , nbuf + bl + ol ) ;
}
if ( ! rename ( buf , nbuf ) )
break ;
@ -1362,7 +1366,7 @@ maildir_purge_msg( maildir_store_t *ctx, const char *name )
{
int ret ;
make_key ( & key , ( char * ) name ) ;
make_key ( ( ( maildir_store_conf_t * ) ctx - > gen . conf ) - > info_stop , & key , ( char * ) name ) ;
if ( ( ret = ctx - > db - > del ( ctx - > db , 0 , & key , 0 ) ) ) {
ctx - > db - > err ( ctx - > db , ret , " Maildir error: db->del() " ) ;
return DRV_BOX_BAD ;
@ -1384,7 +1388,7 @@ maildir_trash_msg( store_t *gctx, message_t *gmsg,
for ( ; ; ) {
nfsnprintf ( buf , sizeof ( buf ) , " %s/%s/%s " , gctx - > path , subdirs [ gmsg - > status & M_RECENT ] , msg - > base ) ;
s = strstr ( msg - > base , " :2, " ) ;
s = strstr ( msg - > base , ( ( maildir_store_conf_t * ) gctx - > conf ) - > info_prefix ) ;
nfsnprintf ( nbuf , sizeof ( nbuf ) , " %s/%s/%ld.%d_%d.%s%s " , ctx - > trash ,
subdirs [ gmsg - > status & M_RECENT ] , ( long ) time ( 0 ) , Pid , + + MaildirCount , Hostname , s ? s : " " ) ;
if ( ! rename ( buf , nbuf ) )
@ -1484,6 +1488,7 @@ maildir_parse_store( conffile_t *cfg, store_conf_t **storep )
if ( strcasecmp ( " MaildirStore " , cfg - > cmd ) )
return 0 ;
store = nfcalloc ( sizeof ( * store ) ) ;
store - > info_delimiter = FieldDelimiter ;
store - > gen . driver = & maildir_driver ;
store - > gen . name = nfstrdup ( cfg - > val ) ;
@ -1496,10 +1501,24 @@ maildir_parse_store( conffile_t *cfg, store_conf_t **storep )
else if ( ! strcasecmp ( " AltMap " , cfg - > cmd ) )
store - > alt_map = parse_bool ( cfg ) ;
# endif /* USE_DB */
else
else if ( ! strcasecmp ( " InfoDelimiter " , cfg - > cmd ) ) {
if ( strlen ( cfg - > val ) ! = 1 ) {
error ( " %s:%d: Info delimiter must be exactly one character long \n " , cfg - > file , cfg - > line ) ;
cfg - > err = 1 ;
continue ;
}
store - > info_delimiter = cfg - > val [ 0 ] ;
if ( ! ispunct ( store - > info_delimiter ) ) {
error ( " %s:%d: Info delimiter must be a punctuation character \n " , cfg - > file , cfg - > line ) ;
cfg - > err = 1 ;
continue ;
}
} else
parse_generic_store ( & store - > gen , cfg ) ;
if ( ! store - > inbox )
store - > inbox = expand_strdup ( " ~/Maildir " ) ;
nfasprintf ( & store - > info_prefix , " %c2, " , store - > info_delimiter ) ;
nfasprintf ( & store - > info_stop , " %c, " , store - > info_delimiter ) ;
* storep = & store - > gen ;
return 1 ;
}