From 66d891ac9a62f4032f57a430d97ed24fb3cbc7eb Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Sat, 5 Aug 2017 21:53:25 +0200 Subject: [PATCH] *** attempt to structure all message output the central idea is to categorize all output and connect it hierarchically, so it can be presented by higher layers with appropriate context, e.g., to avoid a mess in a massively parallel run while avoiding noise in a single-threaded one. this is very far from completion ... --- src/common.h | 14 ++- src/config.c | 62 ++++++------ src/driver.c | 5 +- src/drv_imap.c | 233 +++++++++++++++++----------------------------- src/drv_maildir.c | 66 ++++++------- src/socket.c | 81 ++++++++-------- src/sync.c | 18 ++-- src/util.c | 127 +++++++++++++++++++++++-- 8 files changed, 330 insertions(+), 276 deletions(-) diff --git a/src/common.h b/src/common.h index 850594c..b6b42ae 100644 --- a/src/common.h +++ b/src/common.h @@ -73,10 +73,7 @@ typedef unsigned int uint; #define DEBUG_DRV 0x40 #define DEBUG_DRV_ALL 0x80 #define DEBUG_ALL (0xFF & ~(DEBUG_NET_ALL | DEBUG_DRV_ALL)) -#define QUIET 0x100 -#define VERYQUIET 0x200 #define PROGRESS 0x400 -#define VERBOSE 0x800 #define KEEPJOURNAL 0x1000 #define ZERODELAY 0x2000 @@ -110,6 +107,17 @@ void ATTR_PRINTFLIKE(1, 2) error( const char *, ... ); void ATTR_PRINTFLIKE(1, 2) sys_error( const char *, ... ); void flushn( void ); +extern int PrintLevel; +#define PRN_ERROR 0 +#define PRN_WARN 1 +#define PRN_NOTICE 2 +#define PRN_INFO 3 +#define PRN_NONL 0x100 +#define PRN_CONT 0x200 + +char *nfeprintf( char *buf, char *buf_end, const char *fmt, ... ); +char *nfevprintf( char *buf, char *buf_end, const char *fmt, va_list ap ); + typedef struct string_list { struct string_list *next; char string[1]; diff --git a/src/config.c b/src/config.c index 20f09d9..975e930 100644 --- a/src/config.c +++ b/src/config.c @@ -51,7 +51,7 @@ get_arg( conffile_t *cfile, int required, int *comment ) if (comment) *comment = (c == '#'); if (required) { - error( "%s:%d: parameter missing\n", cfile->file, cfile->line ); + glbl_print( PRN_ERROR, "%s:%d: parameter missing\n", cfile->file, cfile->line ); cfile->err = 1; } ret = 0; @@ -72,12 +72,12 @@ get_arg( conffile_t *cfile, int required, int *comment ) } *t = 0; if (escaped) { - error( "%s:%d: unterminated escape sequence\n", cfile->file, cfile->line ); + glbl_print( PRN_ERROR, "%s:%d: unterminated escape sequence\n", cfile->file, cfile->line ); cfile->err = 1; ret = 0; } if (quoted) { - error( "%s:%d: missing closing quote\n", cfile->file, cfile->line ); + glbl_print( PRN_ERROR, "%s:%d: missing closing quote\n", cfile->file, cfile->line ); cfile->err = 1; ret = 0; } @@ -98,8 +98,8 @@ parse_bool( conffile_t *cfile ) strcasecmp( cfile->val, "false" ) && strcasecmp( cfile->val, "off" ) && strcmp( cfile->val, "0" )) { - error( "%s:%d: invalid boolean value '%s'\n", - cfile->file, cfile->line, cfile->val ); + glbl_print( PRN_ERROR, "%s:%d: invalid boolean value '%s'\n", + cfile->file, cfile->line, cfile->val ); cfile->err = 1; } return 0; @@ -113,8 +113,8 @@ parse_int( conffile_t *cfile ) ret = strtol( cfile->val, &p, 10 ); if (*p) { - error( "%s:%d: invalid integer value '%s'\n", - cfile->file, cfile->line, cfile->val ); + glbl_print( PRN_ERROR, "%s:%d: invalid integer value '%s'\n", + cfile->file, cfile->line, cfile->val ); cfile->err = 1; return 0; } @@ -192,8 +192,8 @@ getopt_helper( conffile_t *cfile, int *cops, channel_conf_t *conf ) else if (!strcasecmp( "All", arg ) || !strcasecmp( "Full", arg )) *cops |= XOP_PULL|XOP_PUSH; else if (strcasecmp( "None", arg ) && strcasecmp( "Noop", arg )) { - error( "%s:%d: invalid Sync arg '%s'\n", - cfile->file, cfile->line, arg ); + glbl_print( PRN_ERROR, "%s:%d: invalid Sync arg '%s'\n", + cfile->file, cfile->line, arg ); cfile->err = 1; } while ((arg = get_arg( cfile, ARG_OPTIONAL, 0 ))); @@ -219,8 +219,8 @@ getopt_helper( conffile_t *cfile, int *cops, channel_conf_t *conf ) } else if (!strcasecmp( "Slave", arg )) { conf->ops[S] |= op; } else if (strcasecmp( "None", arg )) { - error( "%s:%d: invalid %s arg '%s'\n", - cfile->file, cfile->line, boxOps[i].name, arg ); + glbl_print( PRN_ERROR, "%s:%d: invalid %s arg '%s'\n", + cfile->file, cfile->line, boxOps[i].name, arg ); cfile->err = 1; } } while ((arg = get_arg( cfile, ARG_OPTIONAL, 0 ))); @@ -240,7 +240,7 @@ getcline( conffile_t *cfile ) int comment; if (cfile->rest && (arg = get_arg( cfile, ARG_OPTIONAL, 0 ))) { - error( "%s:%d: excess token '%s'\n", cfile->file, cfile->line, arg ); + glbl_print( PRN_ERROR, "%s:%d: excess token '%s'\n", cfile->file, cfile->line, arg ); cfile->err = 1; } while (fgets( cfile->buf, cfile->bufl, cfile->fp )) { @@ -270,7 +270,7 @@ merge_ops( int cops, int ops[] ) if (aops & OP_MASK_TYPE) { if (aops & cops & OP_MASK_TYPE) { cfl: - error( "Conflicting Sync args specified.\n" ); + glbl_print( PRN_ERROR, "Conflicting Sync args specified.\n" ); return 1; } ops[M] |= cops & OP_MASK_TYPE; @@ -300,7 +300,7 @@ merge_ops( int cops, int ops[] ) op = boxOps[i].op; if (ops[M] & (op * (XOP_HAVE_EXPUNGE / OP_EXPUNGE))) { if (aops & cops & op) { - error( "Conflicting %s args specified.\n", boxOps[i].name ); + glbl_print( PRN_ERROR, "Conflicting %s args specified.\n", boxOps[i].name ); return 1; } ops[M] |= cops & op; @@ -334,7 +334,7 @@ load_config( const char *where, int pseudo ) info( "Reading configuration file %s\n", cfile.file ); if (!(cfile.fp = fopen( cfile.file, "r" ))) { - sys_error( "Cannot open config file '%s'", cfile.file ); + glbl_print( PRN_ERROR, "Cannot open config file '%s': %m\n", cfile.file ); return 1; } buf[sizeof(buf) - 1] = 0; @@ -388,8 +388,8 @@ load_config( const char *where, int pseudo ) ms = S; linkst: if (*cfile.val != ':' || !(p = strchr( cfile.val + 1, ':' ))) { - error( "%s:%d: malformed mailbox spec\n", - cfile.file, cfile.line ); + glbl_print( PRN_ERROR, "%s:%d: malformed mailbox spec\n", + cfile.file, cfile.line ); cfile.err = 1; continue; } @@ -399,23 +399,24 @@ load_config( const char *where, int pseudo ) channel->stores[ms] = store; goto stpcom; } - error( "%s:%d: unknown store '%s'\n", - cfile.file, cfile.line, cfile.val + 1 ); + glbl_print( PRN_ERROR, "%s:%d: unknown store '%s'\n", + cfile.file, cfile.line, cfile.val + 1 ); cfile.err = 1; continue; stpcom: if (*++p) channel->boxes[ms] = nfstrdup( p ); } else if (!getopt_helper( &cfile, &cops, channel )) { - error( "%s:%d: unknown keyword '%s'\n", cfile.file, cfile.line, cfile.cmd ); + glbl_print( PRN_ERROR, "%s:%d: unknown keyword '%s'\n", + cfile.file, cfile.line, cfile.cmd ); cfile.err = 1; } } if (!channel->stores[M]) { - error( "channel '%s' refers to no master store\n", channel->name ); + glbl_print( PRN_ERROR, "Channel '%s' refers to no master store\n", channel->name ); cfile.err = 1; } else if (!channel->stores[S]) { - error( "channel '%s' refers to no slave store\n", channel->name ); + glbl_print( PRN_ERROR, "Channel '%s' refers to no slave store\n", channel->name ); cfile.err = 1; } else if (merge_ops( cops, channel->ops )) cfile.err = 1; @@ -458,8 +459,8 @@ load_config( const char *where, int pseudo ) } else { - error( "%s:%d: unknown keyword '%s'\n", - cfile.file, cfile.line, cfile.cmd ); + glbl_print( PRN_ERROR, "%s:%d: unknown keyword '%s'\n", + cfile.file, cfile.line, cfile.cmd ); cfile.err = 1; } } @@ -472,12 +473,14 @@ load_config( const char *where, int pseudo ) else if (!strcasecmp( "FieldDelimiter", cfile.cmd )) { if (strlen( cfile.val ) != 1) { - error( "%s:%d: Field delimiter must be exactly one character long\n", cfile.file, cfile.line ); + glbl_print( PRN_ERROR, "%s:%d: field delimiter must be exactly one character long\n", + cfile.file, cfile.line ); cfile.err = 1; } else { FieldDelimiter = cfile.val[0]; if (!ispunct( FieldDelimiter )) { - error( "%s:%d: Field delimiter must be a punctuation character\n", cfile.file, cfile.line ); + glbl_print( PRN_ERROR, "%s:%d: field delimiter must be a punctuation character\n", + cfile.file, cfile.line ); cfile.err = 1; } } @@ -486,14 +489,15 @@ load_config( const char *where, int pseudo ) { BufferLimit = parse_size( &cfile ); if (BufferLimit <= 0) { - error( "%s:%d: BufferLimit must be positive\n", cfile.file, cfile.line ); + glbl_print( PRN_ERROR, "%s:%d: BufferLimit must be positive\n", + cfile.file, cfile.line ); cfile.err = 1; } } else if (!getopt_helper( &cfile, &gcops, &global_conf )) { - error( "%s:%d: unknown section keyword '%s'\n", - cfile.file, cfile.line, cfile.cmd ); + glbl_print( PRN_ERROR, "%s:%d: unknown section keyword '%s'\n", + cfile.file, cfile.line, cfile.cmd ); cfile.err = 1; while (getcline( &cfile )) if (!cfile.cmd) diff --git a/src/driver.c b/src/driver.c index e522d14..fc5933d 100644 --- a/src/driver.c +++ b/src/driver.c @@ -56,14 +56,15 @@ parse_generic_store( store_conf_t *store, conffile_t *cfg ) const char *p; for (p = cfg->val; *p; p++) { if (*p == '/') { - error( "%s:%d: flattened hierarchy delimiter cannot contain the canonical delimiter '/'\n", cfg->file, cfg->line ); + glbl_print( PRN_ERROR, "%s:%d: flattened hierarchy delimiter cannot contain the canonical delimiter '/'\n", + cfg->file, cfg->line ); cfg->err = 1; return; } } store->flat_delim = nfstrdup( cfg->val ); } else { - error( "%s:%d: unknown keyword '%s'\n", cfg->file, cfg->line, cfg->cmd ); + glbl_print( PRN_ERROR, "%s:%d: unknown keyword '%s'\n", cfg->file, cfg->line, cfg->cmd ); cfg->err = 1; } } diff --git a/src/drv_imap.c b/src/drv_imap.c index 7e5e2c0..e8a9e44 100644 --- a/src/drv_imap.c +++ b/src/drv_imap.c @@ -440,76 +440,9 @@ submit_imap_cmd( imap_store_t *ctx, imap_cmd_t *cmd ) static char * imap_vprintf( const char *fmt, va_list ap ) { - const char *s; - char *d, *ed; - int maxlen; - char c; char buf[1024]; /* Minimal supported command buffer size per IMAP spec. */ - d = buf; - ed = d + sizeof(buf); - s = fmt; - for (;;) { - c = *fmt; - if (!c || c == '%') { - int l = fmt - s; - if (d + l > ed) - oob(); - memcpy( d, s, l ); - d += l; - if (!c) - return nfstrndup( buf, d - buf ); - maxlen = INT_MAX; - c = *++fmt; - if (c == '\\') { - c = *++fmt; - if (c != 's') { - fputs( "Fatal: unsupported escaped format specifier. Please report a bug.\n", stderr ); - abort(); - } - s = va_arg( ap, const char * ); - while ((c = *s++)) { - if (d + 2 > ed) - oob(); - if (c == '\\' || c == '"') - *d++ = '\\'; - *d++ = c; - } - } else { /* \\ cannot be combined with anything else. */ - if (c == '.') { - c = *++fmt; - if (c != '*') { - fputs( "Fatal: unsupported string length specification. Please report a bug.\n", stderr ); - abort(); - } - maxlen = va_arg( ap , int ); - c = *++fmt; - } - if (c == 'c') { - if (d + 1 > ed) - oob(); - *d++ = (char)va_arg( ap , int ); - } else if (c == 's') { - s = va_arg( ap, const char * ); - l = strnlen( s, maxlen ); - if (d + l > ed) - oob(); - memcpy( d, s, l ); - d += l; - } else if (c == 'd') { - d += nfsnprintf( d, ed - d, "%d", va_arg( ap , int ) ); - } else if (c == 'u') { - d += nfsnprintf( d, ed - d, "%u", va_arg( ap , uint ) ); - } else { - fputs( "Fatal: unsupported format specifier. Please report a bug.\n", stderr ); - abort(); - } - } - s = ++fmt; - } else { - fmt++; - } - } + return nfstrndup( buf, nfevprintf( buf, buf + sizeof(buf), fmt, ap ) - buf ); } static void @@ -788,7 +721,7 @@ parse_imap_list( imap_store_t *ctx, char **sp, parse_list_state_t *sts ) n = socket_read( &ctx->conn, s, bytes ); if (n < 0) { badeof: - error( "IMAP error: unexpected EOF from %s\n", ctx->conn.name ); + drv_print( PRN_ERROR, "Unexpected EOF from %s\n", ctx->conn.name ); goto bail; } bytes -= n; @@ -911,7 +844,7 @@ parse_namespace_check( list_t *list ) } return 0; bad: - error( "IMAP error: malformed NAMESPACE response\n" ); + drv_print( PRN_ERROR, "Malformed IMAP NAMESPACE response\n" ); return -1; } @@ -970,7 +903,7 @@ parse_fetch_rsp( imap_store_t *ctx, list_t *list, char *s ATTR_UNUSED ) time_t date = 0; if (!is_list( list )) { - error( "IMAP error: bogus FETCH response\n" ); + drv_print( PRN_ERROR, "Malformed IMAP FETCH response\n" ); free_list( list ); return LIST_BAD; } @@ -980,7 +913,7 @@ parse_fetch_rsp( imap_store_t *ctx, list_t *list, char *s ATTR_UNUSED ) if (!strcmp( "UID", tmp->val )) { tmp = tmp->next; if (!is_atom( tmp ) || (uid = strtoul( tmp->val, &ep, 10 ), *ep)) - error( "IMAP error: unable to parse UID\n" ); + drv_print( PRN_ERROR, "Malformed UID in IMAP FETCH response\n" ); } else if (!strcmp( "FLAGS", tmp->val )) { tmp = tmp->next; if (is_list( tmp )) { @@ -998,26 +931,26 @@ parse_fetch_rsp( imap_store_t *ctx, list_t *list, char *s ATTR_UNUSED ) } if (flags->val[1] == 'X' && flags->val[2] == '-') goto flagok; /* ignore system flag extensions */ - error( "IMAP warning: unknown system flag %s\n", flags->val ); + drv_print( PRN_WARN, "Unknown system flag %s in IMAP FETCH response\n", flags->val ); } flagok: ; } else - error( "IMAP error: unable to parse FLAGS list\n" ); + drv_print( PRN_ERROR, "Malformed FLAGS in IMAP FETCH response\n" ); } status |= M_FLAGS; } else - error( "IMAP error: unable to parse FLAGS\n" ); + drv_print( PRN_ERROR, "Malformed FLAGS in IMAP FETCH response\n" ); } else if (!strcmp( "INTERNALDATE", tmp->val )) { tmp = tmp->next; if (is_atom( tmp )) { if ((date = parse_date( tmp->val )) == -1) - error( "IMAP error: unable to parse INTERNALDATE format\n" ); + drv_print( PRN_ERROR, "Unable to parse IMAP INTERNALDATE format\n" ); } else - error( "IMAP error: unable to parse INTERNALDATE\n" ); + drv_print( PRN_ERROR, "Malformed INTERNALDATE in IMAP FETCH response\n" ); } else if (!strcmp( "RFC822.SIZE", tmp->val )) { tmp = tmp->next; if (!is_atom( tmp ) || (size = strtoul( tmp->val, &ep, 10 ), *ep)) - error( "IMAP error: unable to parse RFC822.SIZE\n" ); + drv_print( PRN_ERROR, "Malformed RFC822.SIZE in IMAP FETCH response\n" ); } else if (!strcmp( "BODY[]", tmp->val )) { tmp = tmp->next; if (is_atom( tmp )) { @@ -1025,7 +958,7 @@ parse_fetch_rsp( imap_store_t *ctx, list_t *list, char *s ATTR_UNUSED ) tmp->val = 0; /* don't free together with list */ size = tmp->len; } else - error( "IMAP error: unable to parse BODY[]\n" ); + drv_print( PRN_ERROR, "Malformed BODY[] in IMAP FETCH response\n" ); } else if (!strcmp( "BODY[HEADER.FIELDS", tmp->val )) { tmp = tmp->next; if (is_list( tmp )) { @@ -1073,7 +1006,7 @@ parse_fetch_rsp( imap_store_t *ctx, list_t *list, char *s ATTR_UNUSED ) } } else { bfail: - error( "IMAP error: unable to parse BODY[HEADER.FIELDS ...]\n" ); + drv_print( PRN_ERROR, "Malformed BODY[HEADER.FIELDS ...] in IMAP FETCH response\n" ); } } } @@ -1091,7 +1024,7 @@ parse_fetch_rsp( imap_store_t *ctx, list_t *list, char *s ATTR_UNUSED ) for (cmdp = ctx->in_progress; cmdp; cmdp = cmdp->next) if (cmdp->param.uid == uid) goto gotuid; - error( "IMAP error: unexpected FETCH response (UID %u)\n", uid ); + drv_print( PRN_ERROR, "Unexpected IMAP FETCH response (UID %u)\n", uid ); free_list( list ); return LIST_BAD; gotuid: @@ -1156,7 +1089,7 @@ parse_response_code( imap_store_t *ctx, imap_cmd_t *cmd, char *s ) s++; if (!(p = strchr( s, ']' ))) { bad_resp: - error( "IMAP error: malformed response code\n" ); + drv_print( PRN_ERROR, "Malformed IMAP response code\n" ); return RESP_CANCEL; } *p++ = 0; @@ -1166,14 +1099,14 @@ parse_response_code( imap_store_t *ctx, imap_cmd_t *cmd, char *s ) if (!(arg = next_arg( &s )) || (ctx->uidvalidity = strtoul( arg, &earg, 10 ), *earg)) { - error( "IMAP error: malformed UIDVALIDITY status\n" ); + drv_print( PRN_ERROR, "Malformed IMAP UIDVALIDITY status\n" ); return RESP_CANCEL; } } else if (!strcmp( "UIDNEXT", arg )) { if (!(arg = next_arg( &s )) || (ctx->uidnext = strtoul( arg, &earg, 10 ), *earg)) { - error( "IMAP error: malformed NEXTUID status\n" ); + drv_print( PRN_ERROR, "Malformed IMAP NEXTUID status\n" ); return RESP_CANCEL; } } else if (!strcmp( "CAPABILITY", arg )) { @@ -1183,14 +1116,14 @@ parse_response_code( imap_store_t *ctx, imap_cmd_t *cmd, char *s ) * to the user */ for (; isspace( (uchar)*p ); p++); - error( "*** IMAP ALERT *** %s\n", p ); + drv_print( PRN_ERROR, "*** IMAP ALERT: %s\n", p ); } else if (cmd && !strcmp( "APPENDUID", arg )) { if (!(arg = next_arg( &s )) || (ctx->uidvalidity = strtoul( arg, &earg, 10 ), *earg) || !(arg = next_arg( &s )) || (((imap_cmd_out_uid_t *)cmd)->out_uid = strtoul( arg, &earg, 10 ), *earg)) { - error( "IMAP error: malformed APPENDUID status\n" ); + drv_print( PRN_ERROR, "Malformed IMAP APPENDUID status\n" ); return RESP_CANCEL; } } @@ -1208,7 +1141,7 @@ parse_list_rsp( imap_store_t *ctx, list_t *list, char *cmd ) if (!is_list( list )) { free_list( list ); bad_list: - error( "IMAP error: malformed LIST response\n" ); + drv_print( PRN_ERROR, "Malformed IMAP LIST response\n" ); return LIST_BAD; } for (lp = list->child; lp; lp = lp->next) @@ -1242,7 +1175,7 @@ parse_list_rsp_p2( imap_store_t *ctx, list_t *list, char *cmd ATTR_UNUSED ) int argl, l; if (!is_atom( list )) { - error( "IMAP error: malformed LIST response\n" ); + drv_print( PRN_ERROR, "Malformed IMAP LIST response\n" ); free_list( list ); return LIST_BAD; } @@ -1254,7 +1187,7 @@ parse_list_rsp_p2( imap_store_t *ctx, list_t *list, char *cmd ATTR_UNUSED ) argl -= l; if (is_inbox( ctx, arg, argl )) { if (!arg[5]) - warn( "IMAP warning: ignoring INBOX in %s\n", ctx->prefix ); + drv_print( PRN_WARN, "Ignoring nested INBOX in %s\n", ctx->prefix ); goto skip; } } else if (!is_inbox( ctx, arg, argl )) { @@ -1264,7 +1197,7 @@ parse_list_rsp_p2( imap_store_t *ctx, list_t *list, char *cmd ATTR_UNUSED ) if (argl >= 5 && !memcmp( arg + argl - 5, ".lock", 5 )) /* workaround broken servers */ goto skip; if (map_name( arg, (char **)&narg, offsetof(string_list_t, string), ctx->delimiter, "/") < 0) { - warn( "IMAP warning: ignoring mailbox %s (reserved character '/' in name)\n", arg ); + drv_print( PRN_WARN, "Ignoring mailbox %s (reserved character '/' in name)\n", arg ); goto skip; } narg->next = ctx->boxes; @@ -1281,10 +1214,10 @@ prepare_name( char **buf, const imap_store_t *ctx, const char *prefix, const cha switch (map_name( name, buf, pl, "/", ctx->delimiter )) { case -1: - error( "IMAP error: mailbox name %s contains server's hierarchy delimiter\n", name ); + drv_print( PRN_ERROR, "Mailbox name %s contains server's hierarchy delimiter\n", name ); return -1; case -2: - error( "IMAP error: server's hierarchy delimiter not known\n" ); + drv_print( PRN_ERROR, "Server's hierarchy delimiter is not known\n" ); return -1; default: memcpy( *buf, prefix, pl ); @@ -1338,7 +1271,7 @@ imap_socket_read( void *aux ) return; if (cmd == (void *)~0) { if (!ctx->expectEOF) - error( "IMAP error: unexpected EOF from %s\n", ctx->conn.name ); + drv_print( PRN_ERROR, "Unexpected EOF from %s\n", ctx->conn.name ); /* A clean shutdown sequence ends with bad_callback as well (see imap_cleanup()). */ break; } @@ -1349,13 +1282,13 @@ imap_socket_read( void *aux ) arg = next_arg( &cmd ); if (!arg) { - error( "IMAP error: empty response\n" ); + drv_print( PRN_ERROR, "Empty IMAP response\n" ); break; } if (*arg == '*') { arg = next_arg( &cmd ); if (!arg) { - error( "IMAP error: malformed untagged response\n" ); + drv_print( PRN_ERROR, "Malformed untagged IMAP response\n" ); break; } @@ -1376,19 +1309,19 @@ imap_socket_read( void *aux ) } else if (!strcmp( "BYE", arg )) { if (!ctx->expectBYE) { ctx->greeting = GreetingBad; - error( "IMAP error: unexpected BYE response: %s\n", cmd ); + drv_print( PRN_ERROR, "Unexpected IMAP BYE response: %s\n", cmd ); /* We just wait for the server to close the connection now. */ ctx->expectEOF = 1; } else { /* We still need to wait for the LOGOUT's tagged OK. */ } } else if (ctx->greeting == GreetingPending) { - error( "IMAP error: bogus greeting response %s\n", arg ); + drv_print( PRN_ERROR, "Unexpected IMAP greeting response %s\n", arg ); break; } else if (!strcmp( "NO", arg )) { - warn( "Warning from IMAP server: %s\n", cmd ); + drv_print( PRN_WARN, "Message from server: %s\n", cmd ); } else if (!strcmp( "BAD", arg )) { - error( "Error from IMAP server: %s\n", cmd ); + drv_print( PRN_ERROR, "Message from server: %s\n", cmd ); } else if (!strcmp( "CAPABILITY", arg )) { parse_capability( ctx, cmd ); } else if (!strcmp( "LIST", arg )) { @@ -1407,12 +1340,12 @@ imap_socket_read( void *aux ) goto listret; } } else { - error( "IMAP error: unrecognized untagged response '%s'\n", arg ); + drv_print( PRN_ERROR, "Unrecognized untagged IMAP response '%s'\n", arg ); break; /* this may mean anything, so prefer not to spam the log */ } continue; } else if (!ctx->in_progress) { - error( "IMAP error: unexpected reply: %s %s\n", arg, cmd ? cmd : "" ); + drv_print( PRN_ERROR, "Unexpected IMAP reply: %s %s\n", arg, cmd ? cmd : "" ); break; /* this may mean anything, so prefer not to spam the log */ } else if (*arg == '+') { socket_expect_read( &ctx->conn, 0 ); @@ -1442,7 +1375,7 @@ imap_socket_read( void *aux ) if (cmdp->param.cont( ctx, cmdp, cmd )) return; } else { - error( "IMAP error: unexpected command continuation request\n" ); + drv_print( PRN_ERROR, "Unexpected IMAP command continuation request\n" ); break; } socket_expect_read( &ctx->conn, 1 ); @@ -1451,7 +1384,7 @@ imap_socket_read( void *aux ) for (pcmdp = &ctx->in_progress; (cmdp = *pcmdp); pcmdp = &cmdp->next) if (cmdp->tag == tag) goto gottag; - error( "IMAP error: unexpected tag %s\n", arg ); + drv_print( PRN_ERROR, "Unexpected tag '%s' in IMAP response\n", arg ); break; gottag: if (!(*pcmdp = cmdp->next)) @@ -1460,7 +1393,7 @@ imap_socket_read( void *aux ) socket_expect_read( &ctx->conn, 0 ); arg = next_arg( &cmd ); if (!arg) { - error( "IMAP error: malformed tagged response\n" ); + drv_print( PRN_ERROR, "Malformed tagged IMAP response\n" ); break; } if (!strcmp( "OK", arg )) { @@ -1484,7 +1417,7 @@ imap_socket_read( void *aux ) goto doresp; } else /*if (!strcmp( "BAD", arg ))*/ resp = RESP_CANCEL; - error( "IMAP command '%s' returned an error: %s %s\n", + drv_print( PRN_ERROR, "IMAP command '%s' returned an error: %s %s\n", starts_with( cmdp->cmd, -1, "LOGIN", 5 ) ? "LOGIN " : starts_with( cmdp->cmd, -1, "AUTHENTICATE PLAIN", 18 ) ? @@ -1799,7 +1732,7 @@ imap_open_store_authenticate( imap_store_t *ctx ) imap_exec( ctx, 0, imap_open_store_authenticate_p2, "STARTTLS" ); return; } else { - error( "IMAP error: SSL support not available\n" ); + drv_print( PRN_ERROR, "IMAP server does not support STARTTLS\n" ); imap_open_store_bail( ctx, FAIL_FINAL ); return; } @@ -1809,7 +1742,7 @@ imap_open_store_authenticate( imap_store_t *ctx ) } else { #ifdef HAVE_LIBSSL if (srvc->ssl_type == SSL_STARTTLS) { - error( "IMAP error: SSL support not available\n" ); + drv_print( PRN_ERROR, "STARTTLS cannot be used with preauthenticated IMAP connection\n" ); imap_open_store_bail( ctx, FAIL_FINAL ); return; } @@ -1853,7 +1786,7 @@ static const char * ensure_user( imap_server_conf_t *srvc ) { if (!srvc->user) { - error( "Skipping account %s, no user\n", srvc->name ); + glbl_print( PRN_ERROR, "Skipping IMAP account %s, no user\n", srvc->name ); return 0; } return srvc->user; @@ -1875,7 +1808,7 @@ ensure_password( imap_server_conf_t *srvc ) } if (!(fp = popen( cmd, "r" ))) { pipeerr: - sys_error( "Skipping account %s, password command failed", srvc->name ); + glbl_print( PRN_ERROR, "Skipping IMAP account %s, password command failed: %m\n", srvc->name ); return 0; } if (!fgets( buffer, sizeof(buffer), fp )) @@ -1884,13 +1817,13 @@ ensure_password( imap_server_conf_t *srvc ) goto pipeerr; if (ret) { if (WIFSIGNALED( ret )) - error( "Skipping account %s, password command crashed\n", srvc->name ); + glbl_print( PRN_ERROR, "Skipping IMAP account %s, password command crashed\n", srvc->name ); else - error( "Skipping account %s, password command exited with status %d\n", srvc->name, WEXITSTATUS( ret ) ); + glbl_print( PRN_ERROR, "Skipping IMAP account %s, password command exited with status %d\n", srvc->name, WEXITSTATUS( ret ) ); return 0; } if (!buffer[0]) { - error( "Skipping account %s, password command produced no output\n", srvc->name ); + glbl_print( PRN_ERROR, "Skipping IMAP account %s, password command produced no output\n", srvc->name ); return 0; } buffer[strcspn( buffer, "\n" )] = 0; /* Strip trailing newline */ @@ -1907,7 +1840,7 @@ ensure_password( imap_server_conf_t *srvc ) exit( 1 ); } if (!*pass) { - error( "Skipping account %s, no password\n", srvc->name ); + glbl_print( PRN_ERROR, "Skipping IMAP account %s, no password\n", srvc->name ); return 0; } /* getpass() returns a pointer to a static buffer. Make a copy for long term storage. */ @@ -1942,7 +1875,7 @@ process_sasl_interact( sasl_interact_t *interact, imap_server_conf_t *srvc ) val = ensure_password( srvc ); break; default: - error( "Error: Unknown SASL interaction ID\n" ); + drv_print( PRN_ERROR, "Unknown SASL interaction ID\n" ); return -1; } if (!val) @@ -1968,7 +1901,7 @@ process_sasl_step( imap_store_t *ctx, int rc, const char *in, uint in_len, } else if (rc == SASL_OK) { ctx->sasl_cont = 0; } else { - error( "Error: %s\n", sasl_errdetail( ctx->sasl ) ); + drv_print( PRN_ERROR, "%s\n", sasl_errdetail( ctx->sasl ) ); return -1; } return 0; @@ -1985,7 +1918,7 @@ decode_sasl_data( const char *prompt, char **in, uint *in_len ) rc = sasl_decode64( prompt, prompt_len, *in, prompt_len, in_len ); if (rc != SASL_OK) { free( *in ); - error( "Error: SASL(%d): %s\n", rc, sasl_errstring( rc, NULL, NULL ) ); + drv_print( PRN_ERROR, "SASL: %s (error %d)\n", sasl_errstring( rc, NULL, NULL ), rc ); return -1; } } else { @@ -2004,7 +1937,7 @@ encode_sasl_data( const char *out, uint out_len, char **enc, uint *enc_len ) rc = sasl_encode64( out, out_len, *enc, enc_len_max, enc_len ); if (rc != SASL_OK) { free( *enc ); - error( "Error: SASL(%d): %s\n", rc, sasl_errstring( rc, NULL, NULL ) ); + drv_print( PRN_ERROR, "SASL: %s (error %d)\n", sasl_errstring( rc, NULL, NULL ), rc ); return -1; } return 0; @@ -2021,7 +1954,7 @@ do_sasl_auth( imap_store_t *ctx, imap_cmd_t *cmdp ATTR_UNUSED, const char *promp conn_iovec_t iov[2]; if (!ctx->sasl_cont) { - error( "Error: IMAP wants more steps despite successful SASL authentication.\n" ); + drv_print( PRN_ERROR, "Server wants more steps despite successful SASL authentication\n" ); goto bail; } if (decode_sasl_data( prompt, &in, &in_len ) < 0) @@ -2072,9 +2005,9 @@ done_sasl_auth( imap_store_t *ctx, imap_cmd_t *cmd ATTR_UNUSED, int response ) uint out_len; int rc = sasl_client_step( ctx->sasl, NULL, 0, &interact, &out, &out_len ); if (process_sasl_step( ctx, rc, NULL, 0, interact, &out, &out_len ) < 0) - warn( "Warning: SASL reported failure despite successful IMAP authentication. Ignoring...\n" ); + drv_print( PRN_WARN, "SASL reported failure despite successful IMAP authentication. Ignoring...\n" ); else if (out) - warn( "Warning: SASL wants more steps despite successful IMAP authentication. Ignoring...\n" ); + drv_print( PRN_WARN, "SASL wants more steps despite successful IMAP authentication. Ignoring...\n" ); } imap_open_store_authenticate2_p2( ctx, NULL, response ); @@ -2095,7 +2028,7 @@ imap_open_store_authenticate2( imap_store_t *ctx ) char saslmechs[1024], *saslend = saslmechs; #endif - info( "Logging in...\n" ); + drv_print( PRN_INFO, "Logging in...\n" ); for (mech = srvc->auth_mechs; mech; mech = mech->next) { int any = !strcmp( mech->string, "*" ); for (cmech = ctx->auth_mechs; cmech; cmech = cmech->next) { @@ -2136,7 +2069,7 @@ imap_open_store_authenticate2( imap_store_t *ctx ) rc = sasl_client_init( sasl_callbacks ); if (rc != SASL_OK) { saslbail: - error( "Error: SASL(%d): %s\n", rc, sasl_errstring( rc, NULL, NULL ) ); + drv_print( PRN_ERROR, "SASL: %s (error %d)\n", sasl_errstring( rc, NULL, NULL ), rc ); goto bail; } sasl_inited = 1; @@ -2148,7 +2081,7 @@ imap_open_store_authenticate2( imap_store_t *ctx ) goto notsasl; if (!ctx->sasl) goto saslbail; - error( "Error: %s\n", sasl_errdetail( ctx->sasl ) ); + drv_print( PRN_ERROR, "%s\n", sasl_errdetail( ctx->sasl ) ); goto bail; } @@ -2156,7 +2089,7 @@ imap_open_store_authenticate2( imap_store_t *ctx ) if (rc == SASL_NOMECH) goto notsasl; if (gotmech) - info( "Authenticating with SASL mechanism %s...\n", gotmech ); + drv_print( PRN_INFO, "Authenticating with SASL mechanism %s...\n", gotmech ); /* Technically, we are supposed to loop over sasl_client_start(), * but it just calls sasl_client_step() anyway. */ if (process_sasl_step( ctx, rc, NULL, 0, interact, CAP(SASLIR) ? &out : NULL, &out_len ) < 0) @@ -2177,11 +2110,11 @@ imap_open_store_authenticate2( imap_store_t *ctx ) if (!ctx->sasl || sasl_listmech( ctx->sasl, NULL, "", "", "", &saslavail, NULL, NULL ) != SASL_OK) saslavail = "(none)"; /* EXTERNAL is always there anyway. */ if (!auth_login) { - error( "IMAP error: selected SASL mechanism(s) not available;\n" + drv_print( PRN_ERROR, "Selected SASL mechanism(s) not available;\n" " selected:%s\n available: %s\n", saslmechs, saslavail ); goto skipnote; } - info( "NOT using available SASL mechanism(s): %s\n", saslavail ); + drv_print( PRN_INFO, "NOT using available SASL mechanism(s): %s\n", saslavail ); sasl_dispose( &ctx->sasl ); } #endif @@ -2191,17 +2124,17 @@ imap_open_store_authenticate2( imap_store_t *ctx ) #ifdef HAVE_LIBSSL if (!ctx->conn.ssl) #endif - warn( "*** IMAP Warning *** Password is being sent in the clear\n" ); + drv_print( PRN_WARN, "*** IMAP Password is being sent unencrypted\n" ); imap_exec( ctx, 0, imap_open_store_authenticate2_p2, "LOGIN \"%\\s\" \"%\\s\"", srvc->user, srvc->pass ); return; } - error( "IMAP error: server supports no acceptable authentication mechanism\n" ); + drv_print( PRN_ERROR, "Server supports no acceptable authentication mechanism\n" ); #ifdef HAVE_LIBSASL skipnote: #endif if (skipped_login) - error( "Note: not using LOGIN because connection is not encrypted;\n" + drv_print( PRN_ERROR, "Note: not using LOGIN because connection is not encrypted;\n" " use 'AuthMechs LOGIN' explicitly to force it.\n" ); bail: @@ -3138,7 +3071,7 @@ imap_parse_store( conffile_t *cfg, store_conf_t **storep ) server->sconf.timeout = parse_int( cfg ); else if (!strcasecmp( "PipelineDepth", cfg->cmd )) { if ((server->max_in_progress = parse_int( cfg )) < 1) { - error( "%s:%d: PipelineDepth must be at least 1\n", cfg->file, cfg->line ); + glbl_print( PRN_ERROR, "%s:%d: PipelineDepth must be at least 1\n", cfg->file, cfg->line ); cfg->err = 1; } } else if (!strcasecmp( "DisableExtension", cfg->cmd ) || @@ -3151,7 +3084,7 @@ imap_parse_store( conffile_t *cfg, store_conf_t **storep ) goto gotcap; } } - error( "%s:%d: Unrecognized IMAP extension '%s'\n", cfg->file, cfg->line, arg ); + glbl_print( PRN_ERROR, "%s:%d: Unrecognized IMAP extension '%s'\n", cfg->file, cfg->line, arg ); cfg->err = 1; gotcap: ; } while ((arg = get_arg( cfg, ARG_OPTIONAL, 0 ))); @@ -3160,8 +3093,8 @@ imap_parse_store( conffile_t *cfg, store_conf_t **storep ) else if (!strcasecmp( "CertificateFile", cfg->cmd )) { server->sconf.cert_file = expand_strdup( cfg->val ); if (access( server->sconf.cert_file, R_OK )) { - sys_error( "%s:%d: CertificateFile '%s'", - cfg->file, cfg->line, server->sconf.cert_file ); + glbl_print( PRN_ERROR, "%s:%d: CertificateFile '%s': %m\n", + cfg->file, cfg->line, server->sconf.cert_file ); cfg->err = 1; } } else if (!strcasecmp( "SystemCertificates", cfg->cmd )) { @@ -3169,15 +3102,15 @@ imap_parse_store( conffile_t *cfg, store_conf_t **storep ) } else if (!strcasecmp( "ClientCertificate", cfg->cmd )) { server->sconf.client_certfile = expand_strdup( cfg->val ); if (access( server->sconf.client_certfile, R_OK )) { - sys_error( "%s:%d: ClientCertificate '%s'", - cfg->file, cfg->line, server->sconf.client_certfile ); + glbl_print( PRN_ERROR, "%s:%d: ClientCertificate '%s': %m\n", + cfg->file, cfg->line, server->sconf.client_certfile ); cfg->err = 1; } } else if (!strcasecmp( "ClientKey", cfg->cmd )) { server->sconf.client_keyfile = expand_strdup( cfg->val ); if (access( server->sconf.client_keyfile, R_OK )) { - sys_error( "%s:%d: ClientKey '%s'", - cfg->file, cfg->line, server->sconf.client_keyfile ); + glbl_print( PRN_ERROR, "%s:%d: ClientKey '%s': %m\n", + cfg->file, cfg->line, server->sconf.client_keyfile ); cfg->err = 1; } } else if (!strcasecmp( "SSLType", cfg->cmd )) { @@ -3188,7 +3121,7 @@ imap_parse_store( conffile_t *cfg, store_conf_t **storep ) } else if (!strcasecmp( "IMAPS", cfg->val )) { server->ssl_type = SSL_IMAPS; } else { - error( "%s:%d: Invalid SSL type\n", cfg->file, cfg->line ); + glbl_print( PRN_ERROR, "%s:%d: Invalid SSL type\n", cfg->file, cfg->line ); cfg->err = 1; } } else if (!strcasecmp( "SSLVersion", cfg->cmd ) || @@ -3207,7 +3140,7 @@ imap_parse_store( conffile_t *cfg, store_conf_t **storep ) } else if (!strcasecmp( "TLSv1.2", arg )) { server->sconf.ssl_versions |= TLSv1_2; } else { - error( "%s:%d: Unrecognized SSL version\n", cfg->file, cfg->line ); + glbl_print( PRN_ERROR, "%s:%d: Unrecognized SSL version\n", cfg->file, cfg->line ); cfg->err = 1; } } while ((arg = get_arg( cfg, ARG_OPTIONAL, 0 ))); @@ -3241,7 +3174,7 @@ imap_parse_store( conffile_t *cfg, store_conf_t **storep ) for (srv = servers; srv; srv = srv->next) if (srv->name && !strcmp( srv->name, cfg->val )) goto gotsrv; - error( "%s:%d: unknown IMAP account '%s'\n", cfg->file, cfg->line, cfg->val ); + glbl_print( PRN_ERROR, "%s:%d: unknown IMAP account '%s'\n", cfg->file, cfg->line, cfg->val ); cfg->err = 1; continue; gotsrv: @@ -3252,7 +3185,7 @@ imap_parse_store( conffile_t *cfg, store_conf_t **storep ) store->gen.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 ); + glbl_print( PRN_ERROR, "%s:%d: Path delimiter must be exactly one character long\n", cfg->file, cfg->line ); cfg->err = 1; continue; } @@ -3261,7 +3194,7 @@ imap_parse_store( conffile_t *cfg, store_conf_t **storep ) parse_generic_store( &store->gen, cfg ); continue; } else { - error( "%s:%d: unknown/misplaced keyword '%s'\n", cfg->file, cfg->line, cfg->cmd ); + glbl_print( PRN_ERROR, "%s:%d: unknown/misplaced keyword '%s'\n", cfg->file, cfg->line, cfg->cmd ); cfg->err = 1; continue; } @@ -3273,19 +3206,19 @@ imap_parse_store( conffile_t *cfg, store_conf_t **storep ) type = "IMAP account", name = server->name; if (!store || !store->server) { if (!server->sconf.tunnel && !server->sconf.host) { - error( "%s '%s' has neither Tunnel nor Host\n", type, name ); + glbl_print( PRN_ERROR, "%s '%s' has neither Tunnel nor Host\n", type, name ); cfg->err = 1; return 1; } if (server->pass && server->pass_cmd) { - error( "%s '%s' has both Pass and PassCmd\n", type, name ); + glbl_print( PRN_ERROR, "%s '%s' has both Pass and PassCmd\n", type, name ); cfg->err = 1; return 1; } #ifdef HAVE_LIBSSL if ((use_sslv2 & use_sslv3 & use_tlsv1 & use_tlsv11 & use_tlsv12) != -1 || use_imaps >= 0 || require_ssl >= 0) { if (server->ssl_type >= 0 || server->sconf.ssl_versions >= 0) { - error( "%s '%s': The deprecated UseSSL*, UseTLS*, UseIMAPS, and RequireSSL options are mutually exlusive with SSLType and SSLVersions.\n", type, name ); + glbl_print( PRN_ERROR, "%s '%s': The deprecated UseSSL*, UseTLS*, UseIMAPS, and RequireSSL options are mutually exlusive with SSLType and SSLVersions.\n", type, name ); cfg->err = 1; return 1; } @@ -3303,11 +3236,11 @@ imap_parse_store( conffile_t *cfg, store_conf_t **storep ) } else if (!server->sconf.ssl_versions) { server->ssl_type = SSL_None; } else { - warn( "Notice: %s '%s': 'RequireSSL no' is being ignored\n", type, name ); + glbl_print( PRN_NOTICE, "%s '%s': 'RequireSSL no' is being ignored\n", type, name ); server->ssl_type = SSL_STARTTLS; } if (server->ssl_type != SSL_None && !server->sconf.ssl_versions) { - error( "%s '%s' requires SSL but no SSL versions enabled\n", type, name ); + glbl_print( PRN_ERROR, "%s '%s' requires SSL but no SSL versions enabled\n", type, name ); cfg->err = 1; return 1; } @@ -3320,11 +3253,11 @@ imap_parse_store( conffile_t *cfg, store_conf_t **storep ) #endif if (require_cram >= 0) { if (server->auth_mechs) { - error( "%s '%s': The deprecated RequireCRAM option is mutually exlusive with AuthMech.\n", type, name ); + glbl_print( PRN_ERROR, "%s '%s': The deprecated RequireCRAM option is mutually exlusive with AuthMech.\n", type, name ); cfg->err = 1; return 1; } - warn( "Notice: %s '%s': RequireCRAM is deprecated. Use AuthMech instead.\n", type, name ); + glbl_print( PRN_NOTICE, "%s '%s': RequireCRAM is deprecated. Use AuthMech instead.\n", type, name ); if (require_cram) add_string_list(&server->auth_mechs, "CRAM-MD5"); } @@ -3343,7 +3276,7 @@ imap_parse_store( conffile_t *cfg, store_conf_t **storep ) memcpy( store->server, &sserver, sizeof(sserver) ); store->server->name = store->gen.name; } else if (acc_opt) { - error( "%s '%s' has both Account and account-specific options\n", type, name ); + glbl_print( PRN_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 index 673df88..5822637 100644 --- a/src/drv_maildir.c +++ b/src/drv_maildir.c @@ -129,7 +129,7 @@ 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 ); + drv_print( PRN_ERROR, "Maildir store '%s' has no Path\n", conf->gen.name ); conf->failed = FAIL_FINAL; return -1; } @@ -157,13 +157,13 @@ maildir_join_path( maildir_store_conf_t *conf, int in_inbox, const char *box ) 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", + drv_print( PRN_ERROR, "Accessing subfolder '%s', but Maildir store '%s' does not specify SubFolders style\n", box, conf->gen.name ); return 0; } 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", + drv_print( PRN_ERROR, "Maildir store '%s', folder '%s': SubFolders style Maildir++ does not support dots in mailbox names\n", conf->gen.name, box ); return 0; } @@ -397,7 +397,7 @@ maildir_list_recurse( maildir_store_t *ctx, int isBox, int flags, if (!(dir = opendir( path ))) { if (isBox && (errno == ENOENT || errno == ENOTDIR)) return 0; - sys_error( "Maildir error: cannot list %s", path ); + sys_error( "Maildir error: cannot list %s: %m\n", path ); return -1; } if (isBox > 1 && style == SUB_UNSET) { @@ -550,7 +550,7 @@ maildir_clear_tmp( char *buf, int bufsz, int bl ) memcpy( buf + bl, "tmp/", 5 ); bl += 4; if (!(dirp = opendir( buf ))) { - sys_error( "Maildir error: cannot list %s", buf ); + sys_error( "Maildir error: cannot list %s: %m\n", buf ); return DRV_BOX_BAD; } time( &now ); @@ -558,14 +558,14 @@ maildir_clear_tmp( char *buf, int bufsz, int bl ) nfsnprintf( buf + bl, bufsz - bl, "%s", entry->d_name ); if (stat( buf, &st )) { if (errno != ENOENT) - sys_error( "Maildir error: cannot access %s", buf ); + sys_error( "Maildir error: cannot access %s: %m\n", buf ); } else if (S_ISREG(st.st_mode) && now - st.st_ctime >= _24_HOURS) { /* This should happen infrequently enough that it won't be * bothersome to the user to display when it occurs. */ notice( "Maildir notice: removing stale file %s\n", buf ); if (unlink( buf ) && errno != ENOENT) - sys_error( "Maildir error: cannot remove %s", buf ); + sys_error( "Maildir error: cannot remove %s: %m\n", buf ); } } closedir( dirp ); @@ -597,13 +597,13 @@ maildir_validate( const char *box, int create, maildir_store_t *ctx ) bl = nfsnprintf( buf, sizeof(buf) - 4, "%s/", box ); if (stat( buf, &st )) { if (errno != ENOENT) { - sys_error( "Maildir error: cannot access mailbox '%s'", box ); + sys_error( "Maildir error: cannot access mailbox '%s': %m\n", box ); return DRV_BOX_BAD; } if (!create) return DRV_BOX_BAD; if (make_box_dir( buf, bl )) { - sys_error( "Maildir error: cannot create mailbox '%s'", box ); + sys_error( "Maildir error: cannot create mailbox '%s': %m\n", box ); ((maildir_store_conf_t *)ctx->gen.conf)->failed = FAIL_FINAL; maildir_invoke_bad_callback( ctx ); return DRV_CANCELED; @@ -620,7 +620,7 @@ maildir_validate( const char *box, int create, maildir_store_t *ctx ) if (!i && !create) return DRV_BOX_BAD; if (mkdir( buf, 0700 )) { - sys_error( "Maildir error: cannot create directory %s", buf ); + sys_error( "Maildir error: cannot create directory %s: %m\n", buf ); return DRV_BOX_BAD; } ctx->fresh[i] = 1; @@ -736,7 +736,7 @@ maildir_uidval_lock( maildir_store_t *ctx ) #ifdef USE_DB if (ctx->usedb) { if (fstat( ctx->uvfd, &st )) { - sys_error( "Maildir error: cannot fstat UID database" ); + sys_error( "Maildir error: cannot fstat UID database: %m\n" ); return DRV_BOX_BAD; } if (db_create( &ctx->db, 0, 0 )) { @@ -938,7 +938,7 @@ maildir_scan( maildir_store_t *ctx, msg_t_array_alloc_t *msglist ) for (i = 0; i < 2; i++) { memcpy( buf + bl, subdirs[i], 4 ); if (stat( buf, &st )) { - sys_error( "Maildir error: cannot stat %s", buf ); + sys_error( "Maildir error: cannot stat %s: %m\n", buf ); goto dfail; } if (st.st_mtime == now && !(DFlags & ZERODELAY) && !ctx->fresh[i]) { @@ -955,7 +955,7 @@ maildir_scan( maildir_store_t *ctx, msg_t_array_alloc_t *msglist ) for (i = 0; i < 2; i++) { memcpy( buf + bl, subdirs[i], 4 ); if (!(d = opendir( buf ))) { - sys_error( "Maildir error: cannot list %s", buf ); + sys_error( "Maildir error: cannot list %s: %m\n", buf ); rfail: maildir_free_scan( msglist ); dfail: @@ -1016,7 +1016,7 @@ maildir_scan( maildir_store_t *ctx, msg_t_array_alloc_t *msglist ) for (i = 0; i < 2; i++) { memcpy( buf + bl, subdirs[i], 4 ); if (stat( buf, &st )) { - sys_error( "Maildir error: cannot re-stat %s", buf ); + sys_error( "Maildir error: cannot re-stat %s: %m\n", buf ); goto rfail; } if (st.st_mtime != stamps[i]) { @@ -1115,7 +1115,7 @@ maildir_scan( maildir_store_t *ctx, msg_t_array_alloc_t *msglist ) nfsnprintf( nbuf + bl + 4, sizeof(nbuf) - bl - 4, "%s", entry->base ); if (rename( nbuf, buf )) { if (errno != ENOENT) { - sys_error( "Maildir error: cannot rename %s to %s", nbuf, buf ); + sys_error( "Maildir error: cannot rename %s to %s: %m\n", nbuf, buf ); fail: maildir_free_scan( msglist ); return DRV_BOX_BAD; @@ -1137,7 +1137,7 @@ maildir_scan( maildir_store_t *ctx, msg_t_array_alloc_t *msglist ) if (want_size) { if (stat( buf, &st )) { if (errno != ENOENT) { - sys_error( "Maildir error: cannot stat %s", buf ); + sys_error( "Maildir error: cannot stat %s: %m\n", buf ); goto fail; } goto retry; @@ -1147,7 +1147,7 @@ maildir_scan( maildir_store_t *ctx, msg_t_array_alloc_t *msglist ) if (want_tuid || want_msgid) { if (!(f = fopen( buf, "r" ))) { if (errno != ENOENT) { - sys_error( "Maildir error: cannot open %s", buf ); + sys_error( "Maildir error: cannot open %s: %m\n", buf ); goto fail; } goto retry; @@ -1299,7 +1299,7 @@ maildir_open_box( store_t *gctx, if ((ctx->uvfd = open( uvpath, O_RDWR|O_CREAT, 0600 )) >= 0) goto fnok; } - sys_error( "Maildir error: cannot write %s", uvpath ); + sys_error( "Maildir error: cannot write %s: %m\n", uvpath ); cb( DRV_BOX_BAD, UIDVAL_BAD, aux ); return; } else { @@ -1356,7 +1356,7 @@ maildir_delete_box( store_t *gctx, bl = nfsnprintf( buf, sizeof(buf) - 4, "%s/", ctx->path ); if (stat( buf, &st )) { if (errno != ENOENT) { - sys_error( "Maildir error: cannot access mailbox '%s'", ctx->path ); + sys_error( "Maildir error: cannot access mailbox '%s': %m\n", ctx->path ); ret = DRV_BOX_BAD; } } else if (!S_ISDIR(st.st_mode)) { @@ -1377,7 +1377,7 @@ maildir_delete_box( store_t *gctx, memcpy( buf + bl, subdirs[i], 4 ); if (rmdir( buf ) && errno != ENOENT) { badrm: - sys_error( "Maildir error: cannot remove '%s'", buf ); + sys_error( "Maildir error: cannot remove '%s': %m\n", buf ); ret = DRV_BOX_BAD; break; } @@ -1394,7 +1394,7 @@ maildir_finish_delete_box( store_t *gctx ) /* Subfolders are not deleted; the deleted folder is only "stripped of its mailboxness". * Consequently, the rmdir may legitimately fail. This behavior follows the IMAP spec. */ if (rmdir( ctx->path ) && errno != ENOENT && errno != ENOTEMPTY) { - sys_error( "Maildir warning: cannot remove '%s'", ctx->path ); + sys_error( "Maildir warning: cannot remove '%s': %m\n", ctx->path ); return DRV_BOX_BAD; } return DRV_OK; @@ -1522,7 +1522,7 @@ maildir_fetch_msg( store_t *gctx, message_t *gmsg, msg_data_t *data, nfsnprintf( buf, sizeof(buf), "%s/%s/%s", ctx->path, subdirs[gmsg->status & M_RECENT], msg->base ); if ((fd = open( buf, O_RDONLY )) >= 0) break; - if ((ret = maildir_again( ctx, msg, "Cannot open %s", buf, 0 )) != DRV_OK) { + if ((ret = maildir_again( ctx, msg, "Cannot open %s: %m\n", buf, 0 )) != DRV_OK) { cb( ret, aux ); return; } @@ -1533,7 +1533,7 @@ maildir_fetch_msg( store_t *gctx, message_t *gmsg, msg_data_t *data, data->date = st.st_mtime; data->data = nfmalloc( data->len ); if (read( fd, data->data, data->len ) != data->len) { - sys_error( "Maildir error: cannot read %s", buf ); + sys_error( "Maildir error: cannot read %s: %m\n", buf ); close( fd ); cb( DRV_MSG_BAD, aux ); return; @@ -1598,7 +1598,7 @@ maildir_store_msg( store_t *gctx, msg_data_t *data, int to_trash, 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) { - sys_error( "Maildir error: cannot create %s", buf ); + sys_error( "Maildir error: cannot create %s: %m\n", buf ); free( data->data ); cb( DRV_BOX_BAD, 0, aux ); return; @@ -1609,7 +1609,7 @@ maildir_store_msg( store_t *gctx, msg_data_t *data, int to_trash, return; } if ((fd = open( buf, O_WRONLY|O_CREAT|O_EXCL, 0600 )) < 0) { - sys_error( "Maildir error: cannot create %s", buf ); + sys_error( "Maildir error: cannot create %s: %m\n", buf ); free( data->data ); cb( DRV_BOX_BAD, 0, aux ); return; @@ -1619,7 +1619,7 @@ maildir_store_msg( store_t *gctx, msg_data_t *data, int to_trash, free( data->data ); if (ret != data->len || (UseFSync && (ret = fsync( fd )))) { if (ret < 0) - sys_error( "Maildir error: cannot write %s", buf ); + sys_error( "Maildir error: cannot write %s: %m\n", buf ); else error( "Maildir error: cannot write %s. Disk full?\n", buf ); close( fd ); @@ -1628,7 +1628,7 @@ maildir_store_msg( store_t *gctx, msg_data_t *data, int to_trash, } if (close( fd ) < 0) { /* Quota exceeded may cause this. */ - sys_error( "Maildir error: cannot write %s", buf ); + sys_error( "Maildir error: cannot write %s: %m\n", buf ); cb( DRV_BOX_BAD, 0, aux ); return; } @@ -1638,7 +1638,7 @@ maildir_store_msg( store_t *gctx, msg_data_t *data, int to_trash, struct utimbuf utimebuf; utimebuf.actime = utimebuf.modtime = data->date; if (utime( buf, &utimebuf ) < 0) { - sys_error( "Maildir error: cannot set times for %s", buf ); + sys_error( "Maildir error: cannot set times for %s: %m\n", buf ); cb( DRV_BOX_BAD, 0, aux ); return; } @@ -1647,7 +1647,7 @@ maildir_store_msg( store_t *gctx, msg_data_t *data, int to_trash, /* Moving seen messages to cur/ is strictly speaking incorrect, but makes mutt happy. */ nfsnprintf( nbuf, sizeof(nbuf), "%s/%s/%s%s", box, subdirs[!(data->flags & F_SEEN)], base, fbuf ); if (rename( buf, nbuf )) { - sys_error( "Maildir error: cannot rename %s to %s", buf, nbuf ); + sys_error( "Maildir error: cannot rename %s to %s: %m\n", buf, nbuf ); cb( DRV_BOX_BAD, 0, aux ); return; } @@ -1705,7 +1705,7 @@ maildir_set_msg_flags( store_t *gctx, message_t *gmsg, uint uid ATTR_UNUSED, int } if (!rename( buf, nbuf )) break; - if ((ret = maildir_again( ctx, msg, "Maildir error: cannot rename %s to %s", buf, nbuf )) != DRV_OK) { + if ((ret = maildir_again( ctx, msg, "Maildir error: cannot rename %s to %s: %m\n", buf, nbuf )) != DRV_OK) { cb( ret, aux ); return; } @@ -1762,12 +1762,12 @@ maildir_trash_msg( store_t *gctx, message_t *gmsg, if (!rename( buf, nbuf )) break; if (errno != ENOENT) { - sys_error( "Maildir error: cannot move %s to %s", buf, nbuf ); + sys_error( "Maildir error: cannot move %s to %s: %m\n", buf, nbuf ); cb( DRV_BOX_BAD, aux ); return; } } - if ((ret = maildir_again( ctx, msg, "Maildir error: cannot move %s to %s", buf, nbuf )) != DRV_OK) { + if ((ret = maildir_again( ctx, msg, "Maildir error: cannot move %s to %s: %m\n", buf, nbuf )) != DRV_OK) { cb( ret, aux ); return; } @@ -1803,7 +1803,7 @@ maildir_close_box( store_t *gctx, if (errno == ENOENT) retry = 1; else - sys_error( "Maildir error: cannot remove %s", buf ); + sys_error( "Maildir error: cannot remove %s: %m\n", buf ); } else { msg->status |= M_DEAD; ctx->total_msgs--; diff --git a/src/socket.c b/src/socket.c index 6ab3ce4..fc74195 100644 --- a/src/socket.c +++ b/src/socket.c @@ -85,13 +85,13 @@ ssl_return( const char *func, conn_t *conn, int ret ) conn->read_callback( conn->callback_aux ); return -1; } - sys_error( "Socket error: secure %s %s", func, conn->name ); + sock_print( PRN_ERROR, "SSL %s %s: %m\n", func, conn->name ); } else { - error( "Socket error: secure %s %s: %s\n", func, conn->name, ERR_error_string( err, 0 ) ); + sock_print( PRN_ERROR, "SSL %s %s: %s\n", func, conn->name, ERR_error_string( err, 0 ) ); } break; default: - error( "Socket error: secure %s %s: unhandled SSL error %d\n", func, conn->name, err ); + sock_print( PRN_ERROR, "SSL %s %s: unhandled error %d\n", func, conn->name, err ); break; } if (conn->state == SCK_STARTTLS) @@ -117,7 +117,7 @@ host_matches( const char *host, const char *pattern ) } static int -verify_hostname( X509 *cert, const char *hostname ) +verify_hostname( conn_t *conn, X509 *cert, const char *hostname ) { int i, len, found; X509_NAME *subj; @@ -145,17 +145,17 @@ verify_hostname( X509 *cert, const char *hostname ) /* try the common name */ if (!(subj = X509_get_subject_name( cert ))) { - error( "Error, cannot get certificate subject\n" ); + sock_print( PRN_ERROR, "Cannot get subject from SSL certificate for %s\n", conn->name ); return -1; } if ((len = X509_NAME_get_text_by_NID( subj, NID_commonName, cname, sizeof(cname) )) < 0) { - error( "Error, cannot get certificate common name\n" ); + sock_print( PRN_ERROR, "Cannot get SSL certificate subject's common name for %s\n", conn->name ); return -1; } if (strlen( cname ) == (size_t)len && host_matches( hostname, cname )) return 0; - error( "Error, certificate owner does not match hostname %s\n", hostname ); + sock_print( PRN_ERROR, "SSL certificate subject for %s does not match hostname %s\n", conn->name, hostname ); return -1; } @@ -169,7 +169,7 @@ verify_cert_host( const server_conf_t *conf, conn_t *sock ) cert = SSL_get_peer_certificate( sock->ssl ); if (!cert) { - error( "Error, no server certificate\n" ); + sock_print( PRN_ERROR, "No SSL certificate provided by %s\n", sock->name ); return -1; } @@ -181,21 +181,22 @@ verify_cert_host( const server_conf_t *conf, conn_t *sock ) err = SSL_get_verify_result( sock->ssl ); if (err != X509_V_OK) { - error( "SSL error connecting %s: %s\n", sock->name, X509_verify_cert_error_string( err ) ); + sock_print( PRN_ERROR, "Cannot verify SSL certificate for %s: %s\n", sock->name, X509_verify_cert_error_string( err ) ); return -1; } if (!conf->host) { - error( "SSL error connecting %s: Neither host nor matching certificate specified\n", sock->name ); + sock_print( PRN_ERROR, "Neither hostname nor matching SSL certificate specified for %s\n", sock->name ); return -1; } - return verify_hostname( cert, conf->host ); + return verify_hostname( sock, cert, conf->host ); } static int -init_ssl_ctx( const server_conf_t *conf ) +init_ssl_ctx( conn_t *conn ) { + const server_conf_t *conf = conn->conf; server_conf_t *mconf = (server_conf_t *)conf; int options = 0; @@ -222,25 +223,25 @@ init_ssl_ctx( const server_conf_t *conf ) SSL_CTX_set_options( mconf->SSLContext, options ); if (conf->cert_file && !SSL_CTX_load_verify_locations( mconf->SSLContext, conf->cert_file, 0 )) { - error( "Error while loading certificate file '%s': %s\n", - conf->cert_file, ERR_error_string( ERR_get_error(), 0 ) ); + sock_print( PRN_ERROR, "Cannot load certificate file '%s': %s\n", + conf->cert_file, ERR_error_string( ERR_get_error(), 0 ) ); return 0; } mconf->trusted_certs = (_STACK *)sk_X509_OBJECT_dup( X509_STORE_get0_objects( SSL_CTX_get_cert_store( mconf->SSLContext ) ) ); if (mconf->system_certs && !SSL_CTX_set_default_verify_paths( mconf->SSLContext )) - warn( "Warning: Unable to load default certificate files: %s\n", - ERR_error_string( ERR_get_error(), 0 ) ); + sock_print( PRN_WARN, "Cannot load default certificate files: %s\n", + ERR_error_string( ERR_get_error(), 0 ) ); SSL_CTX_set_verify( mconf->SSLContext, SSL_VERIFY_NONE, NULL ); if (conf->client_certfile && !SSL_CTX_use_certificate_chain_file( mconf->SSLContext, conf->client_certfile)) { - error( "Error while loading client certificate file '%s': %s\n", - conf->client_certfile, ERR_error_string( ERR_get_error(), 0 ) ); + sock_print( PRN_ERROR, "Cannot load client certificate file '%s': %s\n", + conf->client_certfile, ERR_error_string( ERR_get_error(), 0 ) ); return 0; } if (conf->client_keyfile && !SSL_CTX_use_PrivateKey_file( mconf->SSLContext, conf->client_keyfile, SSL_FILETYPE_PEM)) { - error( "Error while loading client private key '%s': %s\n", - conf->client_keyfile, ERR_error_string( ERR_get_error(), 0 ) ); + sock_print( PRN_ERROR, "Cannot load client private key '%s': %s\n", + conf->client_keyfile, ERR_error_string( ERR_get_error(), 0 ) ); return 0; } @@ -265,7 +266,7 @@ socket_start_tls( conn_t *conn, void (*cb)( int ok, void *aux ) ) ssl_inited = 1; } - if (!init_ssl_ctx( conn->conf )) { + if (!init_ssl_ctx( conn )) { start_tls_p3( conn, 0 ); return; } @@ -286,7 +287,7 @@ start_tls_p2( conn_t *conn ) if (verify_cert_host( conn->conf, conn )) { start_tls_p3( conn, 0 ); } else { - info( "Connection is now encrypted\n" ); + sock_print( PRN_INFO, "Connection is now encrypted\n" ); start_tls_p3( conn, 1 ); } } @@ -379,7 +380,7 @@ socket_connect( conn_t *sock, void (*cb)( int ok, void *aux ) ) int a[2]; nfasprintf( &sock->name, "tunnel '%s'", conf->tunnel ); - infon( "Starting %s... ", sock->name ); + sock_print( PRN_INFO | PRN_NONL, "Starting %s... ", sock->name ); if (socketpair( PF_UNIX, SOCK_STREAM, 0, a )) { perror( "socketpair" ); @@ -398,9 +399,10 @@ socket_connect( conn_t *sock, void (*cb)( int ok, void *aux ) ) close( a[0] ); socket_open_internal( sock, a[1] ); - info( "\vok\n" ); + sock_print( PRN_INFO | PRN_CONT, "ok\n" ); socket_connected( sock ); } else { + sock_print( PRN_INFO | PRN_NONL, "Resolving %s... ", conf->host ); #ifdef HAVE_IPV6 int gaierr; struct addrinfo hints; @@ -409,29 +411,26 @@ socket_connect( conn_t *sock, void (*cb)( int ok, void *aux ) ) hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_ADDRCONFIG; - infon( "Resolving %s... ", conf->host ); if ((gaierr = getaddrinfo( conf->host, NULL, &hints, &sock->addrs ))) { - error( "Error: Cannot resolve server '%s': %s\n", conf->host, gai_strerror( gaierr ) ); + sock_print( PRN_ERROR, "Cannot resolve server '%s': %s\n", conf->host, gai_strerror( gaierr ) ); socket_connect_bail( sock ); return; } - info( "\vok\n" ); sock->curr_addr = sock->addrs; #else struct hostent *he; - infon( "Resolving %s... ", conf->host ); he = gethostbyname( conf->host ); if (!he) { - error( "Error: Cannot resolve server '%s': %s\n", conf->host, hstrerror( h_errno ) ); + sock_print( PRN_ERROR, "Cannot resolve server '%s': %s\n", conf->host, hstrerror( h_errno ) ); socket_connect_bail( sock ); return; } - info( "\vok\n" ); sock->curr_addr = he->h_addr_list; #endif + sock_print( PRN_INFO | PRN_CONT, "ok\n" ); socket_connect_one( sock ); } } @@ -453,7 +452,7 @@ socket_connect_one( conn_t *sock ) #else if (!*sock->curr_addr) { #endif - error( "No working address found for %s\n", sock->conf->host ); + sock_print( PRN_ERROR, "No working address found for %s\n", sock->conf->host ); socket_connect_bail( sock ); return; } @@ -490,7 +489,7 @@ socket_connect_one( conn_t *sock ) } socket_open_internal( sock, s ); - infon( "Connecting to %s... ", sock->name ); + sock_print( PRN_INFO | PRN_NONL, "Connecting to %s... ", sock->name ); #ifdef HAVE_IPV6 if (connect( s, ai->ai_addr, ai->ai_addrlen )) { #else @@ -503,17 +502,17 @@ socket_connect_one( conn_t *sock ) conf_notifier( &sock->notify, 0, POLLOUT ); socket_expect_read( sock, 1 ); sock->state = SCK_CONNECTING; - info( "\v\n" ); + sock_print( PRN_INFO | PRN_CONT, "\n" ); return; } - info( "\vok\n" ); + sock_print( PRN_INFO | PRN_CONT, "ok\n" ); socket_connected( sock ); } static void socket_connect_failed( conn_t *conn ) { - sys_error( "Cannot connect to %s", conn->name ); + sock_print( PRN_ERROR, "Cannot connect to %s: %m\n", conn->name ); socket_close_internal( conn ); free( conn->name ); conn->name = 0; @@ -595,7 +594,7 @@ prepare_read( conn_t *sock, char **buf, int *len ) { int n = sock->offset + sock->bytes; if (!(*len = sizeof(sock->buf) - n)) { - error( "Socket error: receive buffer full. Probably protocol error.\n" ); + sock_print( PRN_ERROR, "Socket receive buffer full. Probably protocol error.\n" ); socket_fail( sock ); return -1; } @@ -622,7 +621,7 @@ do_read( conn_t *sock, char *buf, int len ) #endif { if ((n = read( sock->fd, buf, len )) < 0) { - sys_error( "Socket error: read from %s", sock->name ); + sock_print( PRN_ERROR, "Read from %s failed", sock->name ); socket_fail( sock ); } else if (!n) { /* EOF. Callers take the short path out, so signal higher layers from here. */ @@ -649,7 +648,7 @@ socket_fill_z( conn_t *sock ) ret = inflate( sock->in_z, Z_SYNC_FLUSH ); if (ret != Z_OK && ret != Z_STREAM_END) { - error( "Error decompressing data from %s: %s\n", sock->name, sock->in_z->msg ); + sock_print( PRN_ERROR, "Cannot decompress data from %s: %s\n", sock->name, sock->in_z->msg ); socket_fail( sock ); return; } @@ -758,7 +757,7 @@ do_write( conn_t *sock, char *buf, int len ) n = write( sock->fd, buf, len ); if (n < 0) { if (errno != EAGAIN && errno != EWOULDBLOCK) { - sys_error( "Socket error: write to %s", sock->name ); + sock_print( PRN_ERROR, "Write to %s failed: %m\n", sock->name ); socket_fail( sock ); } else { n = 0; @@ -967,7 +966,7 @@ socket_fd_cb( int events, void *aux ) socket_connected( conn ); return; } - sys_error( "Socket error from %s", conn->name ); + sock_print( PRN_ERROR, "Unexpected event on %s: %m\n", conn->name ); socket_fail( conn ); return; } @@ -1015,7 +1014,7 @@ socket_timeout_cb( void *aux ) errno = ETIMEDOUT; socket_connect_failed( conn ); } else { - error( "Socket error on %s: timeout.\n", conn->name ); + sock_print( PRN_ERROR, "Timeout on %s\n", conn->name ); socket_fail( conn ); } } diff --git a/src/sync.c b/src/sync.c index dffaf1b..6b1ac79 100644 --- a/src/sync.c +++ b/src/sync.c @@ -69,7 +69,7 @@ void Fclose( FILE *f, int safe ) { if ((safe && (fflush( f ) || (UseFSync && fdatasync( fileno( f ) )))) || fclose( f ) == EOF) { - sys_error( "Error: cannot close file" ); + glbl_print( PRN_ERROR, "Cannot close file: %m\n" ); exit( 1 ); } } @@ -81,7 +81,7 @@ vFprintf( FILE *f, const char *msg, va_list va ) r = vfprintf( f, msg, va ); if (r < 0) { - sys_error( "Error: cannot write file" ); + glbl_print( PRN_ERROR, "Cannot write file: %m\n" ); exit( 1 ); } } @@ -614,7 +614,7 @@ prepare_state( sync_vars_t *svars ) } *s = 0; if (mkdir( svars->dname, 0700 ) && errno != EEXIST) { - sys_error( "Error: cannot create SyncState directory '%s'", svars->dname ); + drv_print( PRN_ERROR, "Cannot create SyncState directory '%s': %m\n", svars->dname ); return 0; } *s = '/'; @@ -640,7 +640,7 @@ lock_state( sync_vars_t *svars ) lck.l_type = F_WRLCK; #endif if ((svars->lfd = open( svars->lname, O_WRONLY|O_CREAT, 0666 )) < 0) { - sys_error( "Error: cannot create lock file %s", svars->lname ); + drv_print( PRN_ERROR, "Cannot create lock file %s: %m\n", svars->lname ); return 0; } if (fcntl( svars->lfd, F_SETLK, &lck )) { @@ -801,7 +801,7 @@ load_state( sync_vars_t *svars ) svars->existing = 1; } else { if (errno != ENOENT) { - sys_error( "Error: cannot read sync state %s", svars->dname ); + drv_print( PRN_ERROR, "Cannot read sync state %s: %m\n", svars->dname ); return 0; } svars->existing = 0; @@ -963,7 +963,7 @@ load_state( sync_vars_t *svars ) fclose( jfp ); } else { if (errno != ENOENT) { - sys_error( "Error: cannot read journal %s", svars->jname ); + drv_print( PRN_ERROR, "Cannot read journal %s: %m\n", svars->jname ); return 0; } } @@ -978,7 +978,7 @@ delete_state( sync_vars_t *svars ) unlink( svars->nname ); unlink( svars->jname ); if (unlink( svars->dname ) || unlink( svars->lname )) { - sys_error( "Error: channel %s: sync state cannot be deleted", svars->chan->name ); + drv_print( PRN_ERROR, "Channel %s: sync state cannot be deleted: %m\n", svars->chan->name ); svars->ret = SYNC_FAIL; } } @@ -1221,11 +1221,11 @@ box_opened2( sync_vars_t *svars, int t ) if (!lock_state( svars )) goto bail; if (!(svars->nfp = fopen( svars->nname, "w" ))) { - sys_error( "Error: cannot create new sync state %s", svars->nname ); + drv_print( PRN_ERROR, "Cannot create new sync state %s: %m\n", svars->nname ); goto bail; } if (!(svars->jfp = fopen( svars->jname, "a" ))) { - sys_error( "Error: cannot create journal %s", svars->jname ); + drv_print( PRN_ERROR, "Cannot create journal %s: %m\n", svars->jname ); fclose( svars->nfp ); goto bail; } diff --git a/src/util.c b/src/util.c index 9576b65..fd63987 100644 --- a/src/util.c +++ b/src/util.c @@ -23,8 +23,10 @@ #include "common.h" #include +#include #include #include +#include #include #include #include @@ -43,16 +45,27 @@ flushn( void ) } static void -printn( const char *msg, va_list va ) +vprintn( const char *msg, va_list va ) { if (*msg == '\v') msg++; else flushn(); - vprintf( msg, va ); + char buf[1000]; + fwrite( buf, 1, nfevprintf( buf, buf + sizeof(buf), msg, va ) - buf, stdout ); fflush( stdout ); } +static void +printn( const char *msg, ... ) +{ + va_list va; + + va_start( va, msg ); + vprintn( msg, va ); + va_end( va ); +} + void vdebug( int cat, const char *msg, va_list va ) { @@ -92,7 +105,7 @@ info( const char *msg, ... ) if (DFlags & VERBOSE) { va_start( va, msg ); - printn( msg, va ); + vprintn( msg, va ); va_end( va ); need_nl = 0; } @@ -105,7 +118,7 @@ infon( const char *msg, ... ) if (DFlags & VERBOSE) { va_start( va, msg ); - printn( msg, va ); + vprintn( msg, va ); va_end( va ); need_nl = 1; } @@ -115,10 +128,12 @@ void notice( const char *msg, ... ) { va_list va; + char buf[1000]; if (!(DFlags & QUIET)) { + flushn(); va_start( va, msg ); - printn( msg, va ); + fwrite( buf, 1, nfeprintf( buf, buf + sizeof(buf), "Notice: %v", msg, &va ) - buf, stdout ); va_end( va ); need_nl = 0; } @@ -128,11 +143,12 @@ void warn( const char *msg, ... ) { va_list va; + char buf[1000]; if (!(DFlags & VERYQUIET)) { flushn(); va_start( va, msg ); - vfprintf( stderr, msg, va ); + fwrite( buf, 1, nfeprintf( buf, buf + sizeof(buf), "WARNING: %v", msg, &va ) - buf, stderr ); va_end( va ); } } @@ -141,10 +157,11 @@ void error( const char *msg, ... ) { va_list va; + char buf[1000]; flushn(); va_start( va, msg ); - vfprintf( stderr, msg, va ); + fwrite( buf, 1, nfeprintf( buf, buf + sizeof(buf), "ERROR: %v", msg, &va ) - buf, stderr ); va_end( va ); } @@ -162,6 +179,98 @@ sys_error( const char *msg, ... ) perror( buf ); } +/* Minimal printf() core with some extensions: + * - %m to print strerror(errno) (GNU compatible extension) + * - %\s to print backslash-escaped IMAP string literals + * - %v to recurse formatting; expects (const char *fmt, va_list *ap) as parameters + */ +char * +nfevprintf( char *d, char *ed, const char *fmt, va_list ap ) +{ + const char *s = fmt; + for (;;) { + char c = *fmt; + if (!c || c == '%') { + int l = fmt - s; + if (d + l > ed) + oob(); + memcpy( d, s, l ); + d += l; + if (!c) + return d; + int maxlen = INT_MAX; + c = *++fmt; + if (c == '\\') { + c = *++fmt; + if (c != 's') { + fputs( "Fatal: unsupported escaped format specifier. Please report a bug.\n", stderr ); + abort(); + } + s = va_arg( ap, const char * ); + while ((c = *s++)) { + if (d + 2 > ed) + oob(); + if (c == '\\' || c == '"') + *d++ = '\\'; + *d++ = c; + } + } else { /* \\ cannot be combined with anything else. */ + if (c == '.') { + c = *++fmt; + if (c != '*') { + fputs( "Fatal: unsupported string length specification. Please report a bug.\n", stderr ); + abort(); + } + maxlen = va_arg( ap, int ); + c = *++fmt; + } + if (c == 'c') { + if (d + 1 > ed) + oob(); + *d++ = (char)va_arg( ap, int ); + } else if (c == 's') { + s = va_arg( ap, const char * ); + l = strnlen( s, maxlen ); + cpstr: + if (d + l > ed) + oob(); + memcpy( d, s, l ); + d += l; + } else if (c == 'm') { + s = strerror( errno ); + l = strlen( s ); + goto cpstr; + } else if (c == 'v') { + s = va_arg( ap, const char * ); + va_list *nap = va_arg( ap, va_list * ); + d = nfevprintf( d, ed, s, *nap ); + } else if (c == 'd') { + d += nfsnprintf( d, ed - d, "%d", va_arg( ap, int ) ); + } else if (c == 'u') { + d += nfsnprintf( d, ed - d, "%u", va_arg( ap , uint ) ); + } else { + fputs( "Fatal: unsupported format specifier. Please report a bug.\n", stderr ); + abort(); + } + } + s = ++fmt; + } else { + fmt++; + } + } +} + +char * +nfeprintf( char *d, char *ed, const char *fmt, ... ) +{ + va_list va; + + va_start( va, fmt ); + char *ret = nfevprintf( d, ed, fmt, va ); + va_end( va ); + return ret; +} + void add_string_list_n( string_list_t **list, const char *str, int len ) { @@ -579,11 +688,11 @@ arc4_init( void ) uchar j, si, dat[128]; if ((fd = open( "/dev/urandom", O_RDONLY )) < 0 && (fd = open( "/dev/random", O_RDONLY )) < 0) { - error( "Fatal: no random number source available.\n" ); + glbl_print( PRN_FATAL, "No random number source available.\n" ); exit( 3 ); } if (read( fd, dat, 128 ) != 128) { - error( "Fatal: cannot read random number source.\n" ); + glbl_print( PRN_FATAL, "Cannot read random number source.\n" ); exit( 3 ); } close( fd );