isync

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

commit d7126dca5e5598592bba210722bf922ad760e9f3
parent bb7bbcf5b10fe91dbf1a4ddb1129d21666e009e3
Author: Oswald Buddenhagen <ossi@users.sf.net>
Date:   Sun, 19 Mar 2006 11:29:12 +0000

"fprintf( stderr," => "error(". new functions debugn() and infon()
for messages with missing newline; warn() and error() act upon this.

Diffstat:
Msrc/config.c | 55++++++++++++++++++++++++++-----------------------------
Msrc/drv_imap.c | 116++++++++++++++++++++++++++++++++++++++-----------------------------------------
Msrc/drv_maildir.c | 40++++++++++++++++++++--------------------
Msrc/isync.h | 5++++-
Msrc/main.c | 15++++++++-------
Msrc/sync.c | 50+++++++++++++++++++++++++-------------------------
Msrc/util.c | 54+++++++++++++++++++++++++++++++++++++++++++++++++++---
7 files changed, 190 insertions(+), 145 deletions(-)

diff --git a/src/config.c b/src/config.c @@ -50,8 +50,8 @@ parse_bool( conffile_t *cfile ) strcasecmp( cfile->val, "false" ) && strcasecmp( cfile->val, "off" ) && strcmp( cfile->val, "0" )) - fprintf( stderr, "%s:%d: invalid boolean value '%s'\n", - cfile->file, cfile->line, cfile->val ); + error( "%s:%d: invalid boolean value '%s'\n", + cfile->file, cfile->line, cfile->val ); return 0; } @@ -63,8 +63,8 @@ parse_int( conffile_t *cfile ) ret = strtol( cfile->val, &p, 10 ); if (*p) { - fprintf( stderr, "%s:%d: invalid integer value '%s'\n", - cfile->file, cfile->line, cfile->val ); + error( "%s:%d: invalid integer value '%s'\n", + cfile->file, cfile->line, cfile->val ); return 0; } return ret; @@ -130,8 +130,8 @@ getopt_helper( conffile_t *cfile, int *cops, int ops[], char **sync_state ) else if (!strcasecmp( "All", arg ) || !strcasecmp( "Full", arg )) *cops |= XOP_PULL|XOP_PUSH; else if (strcasecmp( "None", arg ) && strcasecmp( "Noop", arg )) - fprintf( stderr, "%s:%d: invalid Sync arg '%s'\n", - cfile->file, cfile->line, arg ); + error( "%s:%d: invalid Sync arg '%s'\n", + cfile->file, cfile->line, arg ); while ((arg = next_arg( &cfile->rest ))); ops[M] |= XOP_HAVE_TYPE; } else if (!strcasecmp( "Expunge", cfile->cmd )) { @@ -144,8 +144,8 @@ getopt_helper( conffile_t *cfile, int *cops, int ops[], char **sync_state ) else if (!strcasecmp( "Slave", arg )) ops[S] |= OP_EXPUNGE; else if (strcasecmp( "None", arg )) - fprintf( stderr, "%s:%d: invalid Expunge arg '%s'\n", - cfile->file, cfile->line, arg ); + error( "%s:%d: invalid Expunge arg '%s'\n", + cfile->file, cfile->line, arg ); while ((arg = next_arg( &cfile->rest ))); ops[M] |= XOP_HAVE_EXPUNGE; } else if (!strcasecmp( "Create", cfile->cmd )) { @@ -158,8 +158,8 @@ getopt_helper( conffile_t *cfile, int *cops, int ops[], char **sync_state ) else if (!strcasecmp( "Slave", arg )) ops[S] |= OP_CREATE; else if (strcasecmp( "None", arg )) - fprintf( stderr, "%s:%d: invalid Create arg '%s'\n", - cfile->file, cfile->line, arg ); + error( "%s:%d: invalid Create arg '%s'\n", + cfile->file, cfile->line, arg ); while ((arg = next_arg( &cfile->rest ))); ops[M] |= XOP_HAVE_CREATE; } else if (!strcasecmp( "SyncState", cfile->cmd )) @@ -182,8 +182,7 @@ getcline( conffile_t *cfile ) if (*cfile->cmd == '#') continue; if (!(cfile->val = next_arg( &p ))) { - fprintf( stderr, "%s:%d: parameter missing\n", - cfile->file, cfile->line ); + error( "%s:%d: parameter missing\n", cfile->file, cfile->line ); continue; } cfile->rest = p; @@ -203,7 +202,7 @@ merge_ops( int cops, int ops[] ) if (aops & OP_MASK_TYPE) { if (aops & cops & OP_MASK_TYPE) { cfl: - fprintf( stderr, "Conflicting Sync args specified.\n" ); + error( "Conflicting Sync args specified.\n" ); return 1; } ops[M] |= cops & OP_MASK_TYPE; @@ -231,7 +230,7 @@ merge_ops( int cops, int ops[] ) } if (ops[M] & XOP_HAVE_EXPUNGE) { if (aops & cops & OP_EXPUNGE) { - fprintf( stderr, "Conflicting Expunge args specified.\n" ); + error( "Conflicting Expunge args specified.\n" ); return 1; } ops[M] |= cops & OP_EXPUNGE; @@ -239,7 +238,7 @@ merge_ops( int cops, int ops[] ) } if (ops[M] & XOP_HAVE_CREATE) { if (aops & cops & OP_CREATE) { - fprintf( stderr, "Conflicting Create args specified.\n" ); + error( "Conflicting Create args specified.\n" ); return 1; } ops[M] |= cops & OP_CREATE; @@ -321,8 +320,8 @@ load_config( const char *where, int pseudo ) ms = S; linkst: if (*cfile.val != ':' || !(p = strchr( cfile.val + 1, ':' ))) { - fprintf( stderr, "%s:%d: malformed mailbox spec\n", - cfile.file, cfile.line ); + error( "%s:%d: malformed mailbox spec\n", + cfile.file, cfile.line ); err = 1; continue; } @@ -332,24 +331,23 @@ load_config( const char *where, int pseudo ) channel->stores[ms] = store; goto stpcom; } - fprintf( stderr, "%s:%d: unknown store '%s'\n", - cfile.file, cfile.line, cfile.val + 1 ); + error( "%s:%d: unknown store '%s'\n", + cfile.file, cfile.line, cfile.val + 1 ); err = 1; continue; stpcom: if (*++p) channel->boxes[ms] = nfstrdup( p ); } else if (!getopt_helper( &cfile, &cops, channel->ops, &channel->sync_state )) { - fprintf( stderr, "%s:%d: unknown keyword '%s'\n", - cfile.file, cfile.line, cfile.cmd ); + error( "%s:%d: unknown keyword '%s'\n", cfile.file, cfile.line, cfile.cmd ); err = 1; } } if (!channel->stores[M]) { - fprintf( stderr, "channel '%s' refers to no master store\n", channel->name ); + error( "channel '%s' refers to no master store\n", channel->name ); err = 1; } else if (!channel->stores[S]) { - fprintf( stderr, "channel '%s' refers to no slave store\n", channel->name ); + error( "channel '%s' refers to no slave store\n", channel->name ); err = 1; } else if (merge_ops( cops, channel->ops )) err = 1; @@ -391,8 +389,8 @@ load_config( const char *where, int pseudo ) } else { - fprintf( stderr, "%s:%d: unknown keyword '%s'\n", - cfile.file, cfile.line, cfile.cmd ); + error( "%s:%d: unknown keyword '%s'\n", + cfile.file, cfile.line, cfile.cmd ); err = 1; } } @@ -400,8 +398,8 @@ load_config( const char *where, int pseudo ) } else if (!getopt_helper( &cfile, &gcops, global_ops, &global_sync_state )) { - fprintf( stderr, "%s:%d: unknown section keyword '%s'\n", - cfile.file, cfile.line, cfile.cmd ); + error( "%s:%d: unknown section keyword '%s'\n", + cfile.file, cfile.line, cfile.cmd ); err = 1; while (getcline( &cfile )) if (!cfile.cmd) @@ -432,8 +430,7 @@ parse_generic_store( store_conf_t *store, conffile_t *cfg, int *err ) else if (!strcasecmp( "MapInbox", cfg->cmd )) store->map_inbox = nfstrdup( cfg->val ); else { - fprintf( stderr, "%s:%d: unknown keyword '%s'\n", - cfg->file, cfg->line, cfg->cmd ); + error( "%s:%d: unknown keyword '%s'\n", cfg->file, cfg->line, cfg->cmd ); *err = 1; } } diff --git a/src/drv_imap.c b/src/drv_imap.c @@ -194,12 +194,11 @@ verify_cert( SSL *ssl ) X509 *cert; int err; char buf[256]; - int ret = -1; BIO *bio; cert = SSL_get_peer_certificate( ssl ); if (!cert) { - fprintf( stderr, "Error, no server certificate\n" ); + error( "Error, no server certificate\n" ); return -1; } @@ -207,8 +206,8 @@ verify_cert( SSL *ssl ) if (err == X509_V_OK) return 0; - fprintf( stderr, "Error, can't verify certificate: %s (%d)\n", - X509_verify_cert_error_string(err), err ); + error( "Error, can't verify certificate: %s (%d)\n", + X509_verify_cert_error_string(err), err ); X509_NAME_oneline( X509_get_subject_name( cert ), buf, sizeof(buf) ); info( "\nSubject: %s\n", buf ); @@ -230,10 +229,10 @@ verify_cert( SSL *ssl ) " server certificate. Continue at your own risk!\n" "\nAccept this certificate anyway? [no]: ", stderr ); if (fgets( buf, sizeof(buf), stdin ) && (buf[0] == 'y' || buf[0] == 'Y')) { - ret = 0; - fprintf( stderr, "\n*** Fine, but don't say I didn't warn you!\n\n" ); + error( "\n*** Fine, but don't say I didn't warn you!\n\n" ); + return 0; } - return ret; + return -1; } static int @@ -252,11 +251,11 @@ init_ssl_ctx( imap_store_t *ctx ) imap->SSLContext = SSL_CTX_new( method ); if (!srvc->cert_file) { - fprintf( stderr, "Error, CertificateFile not defined\n" ); + error( "Error, CertificateFile not defined\n" ); return -1; } else if (!SSL_CTX_load_verify_locations( imap->SSLContext, srvc->cert_file, NULL )) { - fprintf( stderr, "Error while loading certificate file '%s': %s\n", - srvc->cert_file, ERR_error_string( ERR_get_error(), 0 ) ); + error( "Error while loading certificate file '%s': %s\n", + srvc->cert_file, ERR_error_string( ERR_get_error(), 0 ) ); return -1; } @@ -287,14 +286,14 @@ socket_perror( const char *func, Socket_t *sock, int ret ) case SSL_ERROR_SSL: if ((err = ERR_get_error()) == 0) { if (ret == 0) - fprintf( stderr, "SSL_%s:got EOF\n", func ); + error( "SSL_%s:got EOF\n", func ); else - fprintf( stderr, "SSL_%s:%d:%s\n", func, errno, strerror(errno) ); + error( "SSL_%s:%d:%s\n", func, errno, strerror(errno) ); } else - fprintf( stderr, "SSL_%s:%d:%s\n", func, err, ERR_error_string( err, 0 ) ); + error( "SSL_%s:%d:%s\n", func, err, ERR_error_string( err, 0 ) ); return; default: - fprintf( stderr, "SSL_%s:%d:unhandled SSL error\n", func, err ); + error( "SSL_%s:%d:unhandled SSL error\n", func, err ); break; } return; @@ -305,7 +304,7 @@ socket_perror( const char *func, Socket_t *sock, int ret ) if (ret < 0) perror( func ); else - fprintf( stderr, "%s: unexpected EOF\n", func ); + error( "%s: unexpected EOF\n", func ); } static int @@ -714,7 +713,7 @@ parse_fetch( imap_t *imap, char *cmd ) /* move this down */ list = parse_imap_list( imap, &cmd ); if (!is_list( list )) { - fprintf( stderr, "IMAP error: bogus FETCH response\n" ); + error( "IMAP error: bogus FETCH response\n" ); free_list( list ); return -1; } @@ -726,7 +725,7 @@ parse_fetch( imap_t *imap, char *cmd ) /* move this down */ if (is_atom( tmp )) uid = atoi( tmp->val ); else - fprintf( stderr, "IMAP error: unable to parse UID\n" ); + error( "IMAP error: unable to parse UID\n" ); } else if (!strcmp( "FLAGS", tmp->val )) { tmp = tmp->next; if (is_list( tmp )) { @@ -742,21 +741,21 @@ parse_fetch( imap_t *imap, char *cmd ) /* move this down */ mask |= 1 << i; goto flagok; } - fprintf( stderr, "IMAP warning: unknown system flag %s\n", flags->val ); + error( "IMAP warning: unknown system flag %s\n", flags->val ); } flagok: ; } else - fprintf( stderr, "IMAP error: unable to parse FLAGS list\n" ); + error( "IMAP error: unable to parse FLAGS list\n" ); } status |= M_FLAGS; } else - fprintf( stderr, "IMAP error: unable to parse FLAGS\n" ); + error( "IMAP error: unable to parse FLAGS\n" ); } else if (!strcmp( "RFC822.SIZE", tmp->val )) { tmp = tmp->next; if (is_atom( tmp )) size = atoi( tmp->val ); else - fprintf( stderr, "IMAP error: unable to parse RFC822.SIZE\n" ); + error( "IMAP error: unable to parse RFC822.SIZE\n" ); } else if (!strcmp( "BODY[]", tmp->val )) { tmp = tmp->next; if (is_atom( tmp )) { @@ -764,7 +763,7 @@ parse_fetch( imap_t *imap, char *cmd ) /* move this down */ tmp->val = 0; /* don't free together with list */ size = tmp->len; } else - fprintf( stderr, "IMAP error: unable to parse BODY[]\n" ); + error( "IMAP error: unable to parse BODY[]\n" ); } } } @@ -773,7 +772,7 @@ parse_fetch( imap_t *imap, char *cmd ) /* move this down */ for (cmdp = imap->in_progress; cmdp; cmdp = cmdp->next) if (cmdp->cb.uid == uid) goto gotuid; - fprintf( stderr, "IMAP error: unexpected FETCH response (UID %d)\n", uid ); + error( "IMAP error: unexpected FETCH response (UID %d)\n", uid ); free_list( list ); return -1; gotuid: @@ -822,19 +821,19 @@ parse_response_code( imap_store_t *ctx, struct imap_cmd_cb *cb, char *s ) return RESP_OK; /* no response code */ s++; if (!(p = strchr( s, ']' ))) { - fprintf( stderr, "IMAP error: malformed response code\n" ); + error( "IMAP error: malformed response code\n" ); return RESP_BAD; } *p++ = 0; arg = next_arg( &s ); if (!strcmp( "UIDVALIDITY", arg )) { if (!(arg = next_arg( &s )) || !(ctx->gen.uidvalidity = atoi( arg ))) { - fprintf( stderr, "IMAP error: malformed UIDVALIDITY status\n" ); + error( "IMAP error: malformed UIDVALIDITY status\n" ); return RESP_BAD; } } else if (!strcmp( "UIDNEXT", arg )) { if (!(arg = next_arg( &s )) || !(imap->uidnext = atoi( arg ))) { - fprintf( stderr, "IMAP error: malformed NEXTUID status\n" ); + error( "IMAP error: malformed NEXTUID status\n" ); return RESP_BAD; } } else if (!strcmp( "CAPABILITY", arg )) { @@ -844,12 +843,12 @@ parse_response_code( imap_store_t *ctx, struct imap_cmd_cb *cb, char *s ) * to the user */ for (; isspace( (unsigned char)*p ); p++); - fprintf( stderr, "*** IMAP ALERT *** %s\n", p ); + error( "*** IMAP ALERT *** %s\n", p ); } else if (cb && cb->ctx && !strcmp( "APPENDUID", arg )) { if (!(arg = next_arg( &s )) || !(ctx->gen.uidvalidity = atoi( arg )) || !(arg = next_arg( &s )) || !(*(int *)cb->ctx = atoi( arg ))) { - fprintf( stderr, "IMAP error: malformed APPENDUID status\n" ); + error( "IMAP error: malformed APPENDUID status\n" ); return RESP_BAD; } } @@ -866,7 +865,7 @@ parse_search( imap_t *imap, char *cmd ) if (!(arg = next_arg( &cmd ))) uid = -1; else if (!(uid = atoi( arg ))) { - fprintf( stderr, "IMAP error: malformed SEARCH response\n" ); + error( "IMAP error: malformed SEARCH response\n" ); return; } else if (next_arg( &cmd )) { warn( "IMAP warning: SEARCH returns multiple matches\n" ); @@ -882,7 +881,7 @@ parse_search( imap_t *imap, char *cmd ) *(int *)cmdp->cb.ctx = uid; return; } - fprintf( stderr, "IMAP error: unexpected SEARCH response (UID %u)\n", uid ); + error( "IMAP error: unexpected SEARCH response (UID %u)\n", uid ); } static void @@ -928,7 +927,7 @@ get_cmd_result( imap_store_t *ctx, struct imap_cmd *tcmd ) if (*arg == '*') { arg = next_arg( &cmd ); if (!arg) { - fprintf( stderr, "IMAP error: unable to parse untagged response\n" ); + error( "IMAP error: unable to parse untagged response\n" ); return RESP_BAD; } @@ -956,11 +955,11 @@ get_cmd_result( imap_store_t *ctx, struct imap_cmd *tcmd ) return RESP_BAD; } } else { - fprintf( stderr, "IMAP error: unable to parse untagged response\n" ); + error( "IMAP error: unable to parse untagged response\n" ); return RESP_BAD; } } else if (!imap->in_progress) { - fprintf( stderr, "IMAP error: unexpected reply: %s %s\n", arg, cmd ? cmd : "" ); + error( "IMAP error: unexpected reply: %s %s\n", arg, cmd ? cmd : "" ); return RESP_BAD; } else if (*arg == '+') { /* This can happen only with the last command underway, as @@ -977,7 +976,7 @@ get_cmd_result( imap_store_t *ctx, struct imap_cmd *tcmd ) if (cmdp->cb.cont( ctx, cmdp, cmd )) return RESP_BAD; } else { - fprintf( stderr, "IMAP error: unexpected command continuation request\n" ); + error( "IMAP error: unexpected command continuation request\n" ); return RESP_BAD; } if (socket_write( &imap->buf.sock, "\r\n", 2 ) != 2) @@ -991,7 +990,7 @@ get_cmd_result( imap_store_t *ctx, struct imap_cmd *tcmd ) for (pcmdp = &imap->in_progress; (cmdp = *pcmdp); pcmdp = &cmdp->next) if (cmdp->tag == tag) goto gottag; - fprintf( stderr, "IMAP error: unexpected tag %s\n", arg ); + error( "IMAP error: unexpected tag %s\n", arg ); return RESP_BAD; gottag: if (!(*pcmdp = cmdp->next)) @@ -1028,10 +1027,9 @@ get_cmd_result( imap_store_t *ctx, struct imap_cmd *tcmd ) resp = RESP_NO; } else /*if (!strcmp( "BAD", arg ))*/ resp = RESP_BAD; - fprintf( stderr, "IMAP command '%s' returned an error: %s %s\n", - memcmp (cmdp->cmd, "LOGIN", 5) ? - cmdp->cmd : "LOGIN <user> <pass>", - arg, cmd ? cmd : ""); + error( "IMAP command '%s' returned an error: %s %s\n", + memcmp( cmdp->cmd, "LOGIN", 5 ) ? cmdp->cmd : "LOGIN <user> <pass>", + arg, cmd ? cmd : "" ); } if ((resp2 = parse_response_code( ctx, &cmdp->cb, cmd )) > resp) resp = resp2; @@ -1222,7 +1220,7 @@ imap_open_store( store_conf_t *conf, store_t *oldctx ) #endif if (srvc->tunnel) { - info( "Starting tunnel '%s'... ", srvc->tunnel ); + infon( "Starting tunnel '%s'... ", srvc->tunnel ); if (socketpair( PF_UNIX, SOCK_STREAM, 0, a )) { perror( "socketpair" ); @@ -1248,7 +1246,7 @@ imap_open_store( store_conf_t *conf, store_t *oldctx ) addr.sin_port = htons( srvc->port ); addr.sin_family = AF_INET; - info( "Resolving %s... ", srvc->host ); + infon( "Resolving %s... ", srvc->host ); he = gethostbyname( srvc->host ); if (!he) { perror( "gethostbyname" ); @@ -1260,7 +1258,7 @@ imap_open_store( store_conf_t *conf, store_t *oldctx ) s = socket( PF_INET, SOCK_STREAM, 0 ); - info( "Connecting to %s:%hu... ", inet_ntoa( addr.sin_addr ), ntohs( addr.sin_port ) ); + infon( "Connecting to %s:%hu... ", inet_ntoa( addr.sin_addr ), ntohs( addr.sin_port ) ); if (connect( s, (struct sockaddr *)&addr, sizeof(addr) )) { close( s ); perror( "connect" ); @@ -1281,19 +1279,19 @@ imap_open_store( store_conf_t *conf, store_t *oldctx ) /* read the greeting string */ if (buffer_gets( &imap->buf, &rsp )) { - fprintf( stderr, "IMAP error: no greeting response\n" ); + error( "IMAP error: no greeting response\n" ); goto bail; } arg = next_arg( &rsp ); if (!arg || *arg != '*' || (arg = next_arg( &rsp )) == NULL) { - fprintf( stderr, "IMAP error: invalid greeting response\n" ); + error( "IMAP error: invalid greeting response\n" ); goto bail; } preauth = 0; if (!strcmp( "PREAUTH", arg )) preauth = 1; else if (strcmp( "OK", arg ) != 0) { - fprintf( stderr, "IMAP error: unknown greeting response\n" ); + error( "IMAP error: unknown greeting response\n" ); goto bail; } parse_response_code( ctx, 0, rsp ); @@ -1315,7 +1313,7 @@ imap_open_store( store_conf_t *conf, store_t *oldctx ) goto bail; } else { if (srvc->require_ssl) { - fprintf( stderr, "IMAP error: SSL support not available\n" ); + error( "IMAP error: SSL support not available\n" ); goto bail; } else warn( "IMAP warning: SSL support not available\n" ); @@ -1325,7 +1323,7 @@ imap_open_store( store_conf_t *conf, store_t *oldctx ) info ("Logging in...\n"); if (!srvc->user) { - fprintf( stderr, "Skipping server %s, no user\n", srvc->host ); + error( "Skipping server %s, no user\n", srvc->host ); goto bail; } if (!srvc->pass) { @@ -1337,7 +1335,7 @@ imap_open_store( store_conf_t *conf, store_t *oldctx ) exit( 1 ); } if (!*arg) { - fprintf( stderr, "Skipping account %s@%s, no password\n", srvc->user, srvc->host ); + error( "Skipping account %s@%s, no password\n", srvc->user, srvc->host ); goto bail; } /* @@ -1356,13 +1354,13 @@ imap_open_store( store_conf_t *conf, store_t *oldctx ) if (imap_exec( ctx, &cb, "AUTHENTICATE CRAM-MD5" ) != RESP_OK) goto bail; } else if (srvc->require_cram) { - fprintf( stderr, "IMAP error: CRAM-MD5 authentication is not supported by server\n" ); + error( "IMAP error: CRAM-MD5 authentication is not supported by server\n" ); goto bail; } else #endif { if (CAP(NOLOGIN)) { - fprintf( stderr, "Skipping account %s@%s, server forbids LOGIN\n", srvc->user, srvc->host ); + error( "Skipping account %s@%s, server forbids LOGIN\n", srvc->user, srvc->host ); goto bail; } #if HAVE_LIBSSL @@ -1370,7 +1368,7 @@ imap_open_store( store_conf_t *conf, store_t *oldctx ) #endif warn( "*** IMAP Warning *** Password is being sent in the clear\n" ); if (imap_exec( ctx, 0, "LOGIN \"%s\" \"%s\"", srvc->user, srvc->pass ) != RESP_OK) { - fprintf( stderr, "IMAP error: LOGIN failed\n" ); + error( "IMAP error: LOGIN failed\n" ); goto bail; } } @@ -1700,8 +1698,8 @@ imap_parse_store( conffile_t *cfg, store_conf_t **storep, int *err ) else if (!strcasecmp( "CertificateFile", cfg->cmd )) { server->cert_file = expand_strdup( cfg->val ); if (access( server->cert_file, R_OK )) { - fprintf( stderr, "%s:%d: CertificateFile '%s': %s\n", - cfg->file, cfg->line, server->cert_file, strerror( errno ) ); + error( "%s:%d: CertificateFile '%s': %s\n", + cfg->file, cfg->line, server->cert_file, strerror( errno ) ); *err = 1; } } else if (!strcasecmp( "RequireSSL", cfg->cmd )) @@ -1722,8 +1720,7 @@ imap_parse_store( conffile_t *cfg, store_conf_t **storep, int *err ) for (srv = servers; srv; srv = srv->next) if (srv->name && !strcmp( srv->name, cfg->val )) goto gotsrv; - fprintf( stderr, "%s:%d: unknown IMAP account '%s'\n", - cfg->file, cfg->line, cfg->val ); + error( "%s:%d: unknown IMAP account '%s'\n", cfg->file, cfg->line, cfg->val ); *err = 1; continue; gotsrv: @@ -1736,8 +1733,7 @@ imap_parse_store( conffile_t *cfg, store_conf_t **storep, int *err ) parse_generic_store( &store->gen, cfg, err ); continue; } else { - fprintf( stderr, "%s:%d: unknown/misplaced keyword '%s'\n", - cfg->file, cfg->line, cfg->cmd ); + error( "%s:%d: unknown/misplaced keyword '%s'\n", cfg->file, cfg->line, cfg->cmd ); *err = 1; continue; } @@ -1746,9 +1742,9 @@ imap_parse_store( conffile_t *cfg, store_conf_t **storep, int *err ) if (!store || !store->server) { if (!server->tunnel && !server->host) { if (store) - fprintf( stderr, "IMAP store '%s' has incomplete/missing connection details\n", store->gen.name ); + error( "IMAP store '%s' has incomplete/missing connection details\n", store->gen.name ); else - fprintf( stderr, "IMAP account '%s' has incomplete/missing connection details\n", server->name ); + error( "IMAP account '%s' has incomplete/missing connection details\n", server->name ); *err = 1; return 1; } @@ -1758,7 +1754,7 @@ imap_parse_store( conffile_t *cfg, store_conf_t **storep, int *err ) store->server = nfmalloc( sizeof(sserver) ); memcpy( store->server, &sserver, sizeof(sserver) ); } else if (acc_opt) { - fprintf( stderr, "IMAP store '%s' has both Account and account-specific options\n", store->gen.name ); + error( "IMAP store '%s' has both Account and account-specific options\n", store->gen.name ); *err = 1; } } diff --git a/src/drv_maildir.c b/src/drv_maildir.c @@ -104,7 +104,7 @@ maildir_open_store( store_conf_t *conf, store_t *oldctx ) if (oldctx) maildir_close_store( oldctx ); if (stat( conf->path, &st ) || !S_ISDIR(st.st_mode)) { - fprintf( stderr, "Maildir error: cannot open store %s\n", conf->path ); + error( "Maildir error: cannot open store %s\n", conf->path ); return 0; } ctx = nfcalloc( sizeof(*ctx) ); @@ -157,7 +157,7 @@ maildir_list( store_t *gctx, string_list_t **retb ) struct dirent *de; if (!(dir = opendir( gctx->conf->path ))) { - fprintf( stderr, "%s: %s\n", gctx->conf->path, strerror(errno) ); + error( "%s: %s\n", gctx->conf->path, strerror(errno) ); return DRV_STORE_BAD; } *retb = 0; @@ -221,26 +221,26 @@ maildir_validate( const char *prefix, const char *box, int create ) if (errno == ENOENT) { if (create) { if (mkdir( buf, 0700 )) { - fprintf( stderr, "Maildir error: mkdir %s: %s (errno %d)\n", - buf, strerror(errno), errno ); + error( "Maildir error: mkdir %s: %s (errno %d)\n", + buf, strerror(errno), errno ); return DRV_STORE_BAD; } mkdirs: for (i = 0; i < 3; i++) { memcpy( buf + bl, subdirs[i], 4 ); if (mkdir( buf, 0700 )) { - fprintf( stderr, "Maildir error: mkdir %s: %s (errno %d)\n", - buf, strerror(errno), errno ); + error( "Maildir error: mkdir %s: %s (errno %d)\n", + buf, strerror(errno), errno ); return DRV_BOX_BAD; } } } else { - fprintf( stderr, "Maildir error: mailbox '%s' does not exist\n", buf ); + error( "Maildir error: mailbox '%s' does not exist\n", buf ); return DRV_BOX_BAD; } } else { - fprintf( stderr, "Maildir error: stat %s: %s (errno %d)\n", - buf, strerror(errno), errno ); + error( "Maildir error: stat %s: %s (errno %d)\n", + buf, strerror(errno), errno ); return DRV_BOX_BAD; } } else { @@ -252,30 +252,30 @@ maildir_validate( const char *prefix, const char *box, int create ) if (!j) goto mkdirs; if (j != 3) { - fprintf( stderr, "Maildir error: '%.*s' is no valid mailbox\n", bl, buf ); + error( "Maildir error: '%.*s' is no valid mailbox\n", bl, buf ); return DRV_BOX_BAD; } memcpy( buf + bl, "tmp/", 5 ); bl += 4; if (!(dirp = opendir( buf ))) { - fprintf( stderr, "Maildir error: opendir: %s: %s (errno %d)\n", - buf, strerror(errno), errno ); + error( "Maildir error: opendir: %s: %s (errno %d)\n", + buf, strerror(errno), errno ); return DRV_BOX_BAD; } time( &now ); while ((entry = readdir( dirp ))) { nfsnprintf( buf + bl, sizeof(buf) - bl, "%s", entry->d_name ); if (stat( buf, &st )) - fprintf( stderr, "Maildir error: stat: %s: %s (errno %d)\n", - buf, strerror(errno), errno ); + error( "Maildir error: stat: %s: %s (errno %d)\n", + buf, strerror(errno), errno ); 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. */ info( "Maildir notice: removing stale file %s\n", buf ); if (unlink( buf )) - fprintf( stderr, "Maildir error: unlink: %s: %s (errno %d)\n", - buf, strerror(errno), errno ); + error( "Maildir error: unlink: %s: %s (errno %d)\n", + buf, strerror(errno), errno ); } } closedir( dirp ); @@ -337,7 +337,7 @@ maildir_store_uid( maildir_store_t *ctx ) n = sprintf( buf, "%d\n%d\n", ctx->gen.uidvalidity, ctx->nuid ); lseek( ctx->uvfd, 0, SEEK_SET ); if (write( ctx->uvfd, buf, n ) != n || ftruncate( ctx->uvfd, n )) { - fprintf( stderr, "Maildir error: cannot write UIDVALIDITY.\n" ); + error( "Maildir error: cannot write UIDVALIDITY.\n" ); return DRV_BOX_BAD; } return DRV_OK; @@ -368,7 +368,7 @@ maildir_uidval_lock( maildir_store_t *ctx ) #ifdef LEGACY_FLOCK /* This is legacy only */ if (flock( ctx->uvfd, LOCK_EX ) < 0) { - fprintf( stderr, "Maildir error: cannot flock UIDVALIDITY.\n" ); + error( "Maildir error: cannot flock UIDVALIDITY.\n" ); return DRV_BOX_BAD; } #endif @@ -379,7 +379,7 @@ maildir_uidval_lock( maildir_store_t *ctx ) #endif lck.l_type = F_WRLCK; if (fcntl( ctx->uvfd, F_SETLKW, &lck )) { - fprintf( stderr, "Maildir error: cannot fcntl lock UIDVALIDITY.\n" ); + error( "Maildir error: cannot fcntl lock UIDVALIDITY.\n" ); return DRV_BOX_BAD; } lseek( ctx->uvfd, 0, SEEK_SET ); @@ -1008,7 +1008,7 @@ maildir_store_msg( store_t *gctx, msg_data_t *data, int *uid ) if (ret < 0) perror( buf ); else - fprintf( stderr, "Maildir error: %s: partial write\n", buf ); + error( "Maildir error: %s: partial write\n", buf ); close( fd ); return DRV_BOX_BAD; } diff --git a/src/isync.h b/src/isync.h @@ -205,12 +205,15 @@ extern const char *Home; #define VERYQUIET 8 #define KEEPJOURNAL 16 -extern int DFlags; +extern int DFlags, Ontty; void debug( const char *, ... ); +void debugn( const char *, ... ); void info( const char *, ... ); +void infon( const char *, ... ); void infoc( char ); void warn( const char *, ... ); +void error( const char *, ... ); char *next_arg( char ** ); diff --git a/src/main.c b/src/main.c @@ -92,7 +92,7 @@ crashHandler( int n ) open( "/dev/tty", O_RDWR ); dup2( 0, 1 ); dup2( 0, 2 ); - fprintf( stderr, "*** " EXE " caught signal %d. Starting debugger ...\n", n ); + error( "*** " EXE " caught signal %d. Starting debugger ...\n", n ); switch ((dpid = fork ())) { case -1: perror( "fork()" ); @@ -208,6 +208,7 @@ main( int argc, char **argv ) fputs( "Fatal: $HOME not set\n", stderr ); return 1; } + Ontty = isatty( 1 ) && isatty( 2 ); arc4_init(); for (oind = 1, ochar = 0; oind < argc; ) { @@ -220,7 +221,7 @@ main( int argc, char **argv ) break; if (!strcmp( opt, "config" )) { if (oind >= argc) { - fprintf( stderr, "--config requires an argument.\n" ); + error( "--config requires an argument.\n" ); return 1; } config = argv[oind++]; @@ -299,7 +300,7 @@ main( int argc, char **argv ) op |= OP_FLAGS; else { badopt: - fprintf( stderr, "Unknown option '%s'\n", argv[oind - 1] ); + error( "Unknown option '%s'\n", argv[oind - 1] ); return 1; } switch (op & XOP_MASK_DIR) { @@ -313,7 +314,7 @@ main( int argc, char **argv ) } ochar = argv[oind++] + 1; if (!*ochar) { - fprintf( stderr, "Invalid option '-'\n" ); + error( "Invalid option '-'\n" ); return 1; } } @@ -330,7 +331,7 @@ main( int argc, char **argv ) pseudo = 1; } if (oind >= argc) { - fprintf( stderr, "-c requires an argument.\n" ); + error( "-c requires an argument.\n" ); return 1; } config = argv[oind++]; @@ -411,7 +412,7 @@ main( int argc, char **argv ) case 'h': usage( 0 ); default: - fprintf( stderr, "Unknown option '-%c'\n", *(ochar - 1) ); + error( "Unknown option '-%c'\n", *(ochar - 1) ); return 1; } } @@ -477,7 +478,7 @@ main( int argc, char **argv ) for (chan = channels; chan; chan = chan->next) if (!strcmp( chan->name, channame )) goto gotchan; - fprintf( stderr, "No channel or group named '%s' defined.\n", channame ); + error( "No channel or group named '%s' defined.\n", channame ); ret = 1; goto gotnone; gotchan: ; diff --git a/src/sync.c b/src/sync.c @@ -126,14 +126,14 @@ select_box( sync_rec_t *srecs, store_t *ctx[], int maxuid[], int uidval[], int t maxwuid = srec->uid[t]; } else maxwuid = 0; - info( "Selecting %s %s... ", str_ms[t], ctx[t]->name ); + infon( "Selecting %s %s... ", str_ms[t], ctx[t]->name ); debug( maxwuid == INT_MAX ? "selecting %s [%d,inf]\n" : "selecting %s [%d,%d]\n", str_ms[t], minwuid, maxwuid ); switch (ctx[t]->conf->driver->select( ctx[t], minwuid, maxwuid, mexcs, nmexcs )) { case DRV_STORE_BAD: return SYNC_BAD(t); case DRV_BOX_BAD: return SYNC_FAIL; } if (uidval[t] && uidval[t] != ctx[t]->uidvalidity) { - fprintf( stderr, "Error: UIDVALIDITY of %s changed (got %d, expected %d)\n", str_ms[t], ctx[t]->uidvalidity, uidval[t] ); + error( "Error: UIDVALIDITY of %s changed (got %d, expected %d)\n", str_ms[t], ctx[t]->uidvalidity, uidval[t] ); return SYNC_FAIL; } info( "%d messages, %d recent\n", ctx[M]->count, ctx[M]->recent ); @@ -401,7 +401,7 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan ) if (!strcmp( chan->sync_state ? chan->sync_state : global_sync_state, "*" )) { if (!ctx[S]->path) { - fprintf( stderr, "Error: store '%s' does not support in-box sync state\n", chan->stores[S]->name ); + error( "Error: store '%s' does not support in-box sync state\n", chan->stores[S]->name ); return SYNC_BAD(S); } nfasprintf( &dname, "%s/." EXE "state", ctx[S]->path ); @@ -418,13 +418,13 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan ) free( csname ); } if (!(s = strrchr( dname, '/' ))) { - fprintf( stderr, "Error: invalid SyncState '%s'\n", dname ); + error( "Error: invalid SyncState '%s'\n", dname ); free( dname ); return SYNC_BAD(S); } *s = 0; if (mkdir( dname, 0700 ) && errno != EEXIST) { - fprintf( stderr, "Error: cannot create SyncState directory '%s': %s\n", dname, strerror(errno) ); + error( "Error: cannot create SyncState directory '%s': %s\n", dname, strerror(errno) ); free( dname ); return SYNC_BAD(S); } @@ -441,12 +441,12 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan ) lck.l_type = F_WRLCK; #endif if ((lfd = open( lname, O_WRONLY|O_CREAT, 0666 )) < 0) { - fprintf( stderr, "Error: cannot create lock file %s: %s\n", lname, strerror(errno) ); + error( "Error: cannot create lock file %s: %s\n", lname, strerror(errno) ); ret = SYNC_FAIL; goto bail2; } if (fcntl( lfd, F_SETLK, &lck )) { - fprintf( stderr, "Error: channel :%s:%s-:%s:%s is locked\n", + error( "Error: channel :%s:%s-:%s:%s is locked\n", chan->stores[M]->name, ctx[M]->name, chan->stores[S]->name, ctx[S]->name ); ret = SYNC_FAIL; goto bail1; @@ -454,13 +454,13 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan ) if ((dfp = fopen( dname, "r" ))) { debug( "reading sync state %s ...\n", dname ); if (!fgets( buf, sizeof(buf), dfp ) || !(t = strlen( buf )) || buf[t - 1] != '\n') { - fprintf( stderr, "Error: incomplete sync state header in %s\n", dname ); + error( "Error: incomplete sync state header in %s\n", dname ); fclose( dfp ); ret = SYNC_FAIL; goto bail; } if (sscanf( buf, "%d:%d %d:%d:%d", &uidval[M], &maxuid[M], &uidval[S], &smaxxuid, &maxuid[S]) != 5) { - fprintf( stderr, "Error: invalid sync state header in %s\n", dname ); + error( "Error: invalid sync state header in %s\n", dname ); fclose( dfp ); ret = SYNC_FAIL; goto bail; @@ -469,14 +469,14 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan ) while (fgets( buf, sizeof(buf), dfp )) { sline++; if (!(t = strlen( buf )) || buf[t - 1] != '\n') { - fprintf( stderr, "Error: incomplete sync state entry at %s:%d\n", dname, sline ); + error( "Error: incomplete sync state entry at %s:%d\n", dname, sline ); fclose( dfp ); ret = SYNC_FAIL; goto bail; } fbuf[0] = 0; if (sscanf( buf, "%d %d %15s", &t1, &t2, fbuf ) < 2) { - fprintf( stderr, "Error: invalid sync state entry at %s:%d\n", dname, sline ); + error( "Error: invalid sync state entry at %s:%d\n", dname, sline ); fclose( dfp ); ret = SYNC_FAIL; goto bail; @@ -501,7 +501,7 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan ) fclose( dfp ); } else { if (errno != ENOENT) { - fprintf( stderr, "Error: cannot read sync state %s\n", dname ); + error( "Error: cannot read sync state %s\n", dname ); ret = SYNC_FAIL; goto bail; } @@ -511,13 +511,13 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan ) if (!stat( nname, &st ) && fgets( buf, sizeof(buf), jfp )) { debug( "recovering journal ...\n" ); if (!(t = strlen( buf )) || buf[t - 1] != '\n') { - fprintf( stderr, "Error: incomplete journal header in %s\n", jname ); + error( "Error: incomplete journal header in %s\n", jname ); fclose( jfp ); ret = SYNC_FAIL; goto bail; } if (memcmp( buf, JOURNAL_VERSION "\n", strlen(JOURNAL_VERSION) + 1 )) { - fprintf( stderr, "Error: incompatible journal version " + error( "Error: incompatible journal version " "(got %.*s, expected " JOURNAL_VERSION ")\n", t - 1, buf ); fclose( jfp ); ret = SYNC_FAIL; @@ -528,7 +528,7 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan ) while (fgets( buf, sizeof(buf), jfp )) { line++; if (!(t = strlen( buf )) || buf[t - 1] != '\n') { - fprintf( stderr, "Error: incomplete journal entry at %s:%d\n", jname, line ); + error( "Error: incomplete journal entry at %s:%d\n", jname, line ); fclose( jfp ); ret = SYNC_FAIL; goto bail; @@ -541,7 +541,7 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan ) (sscanf( buf + 2, "%d %d", &t1, &t2 ) != 2) : (sscanf( buf + 2, "%d %d %d", &t1, &t2, &t3 ) != 3)) { - fprintf( stderr, "Error: malformed journal entry at %s:%d\n", jname, line ); + error( "Error: malformed journal entry at %s:%d\n", jname, line ); fclose( jfp ); ret = SYNC_FAIL; goto bail; @@ -572,12 +572,12 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan ) for (srec = recs; srec != nsrec; srec = srec->next) if (srec->uid[M] == t1 && srec->uid[S] == t2) goto syncfnd; - fprintf( stderr, "Error: journal entry at %s:%d refers to non-existing sync state entry\n", jname, line ); + error( "Error: journal entry at %s:%d refers to non-existing sync state entry\n", jname, line ); fclose( jfp ); ret = SYNC_FAIL; goto bail; syncfnd: - debug( " entry(%d,%d,%u) ", srec->uid[M], srec->uid[S], srec->flags ); + debugn( " entry(%d,%d,%u) ", srec->uid[M], srec->uid[S], srec->flags ); switch (buf[0]) { case '-': debug( "killed\n" ); @@ -632,7 +632,7 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan ) srec->status &= ~S_EXPIRED; break; default: - fprintf( stderr, "Error: unrecognized journal entry at %s:%d\n", jname, line ); + error( "Error: unrecognized journal entry at %s:%d\n", jname, line ); fclose( jfp ); ret = SYNC_FAIL; goto bail; @@ -643,18 +643,18 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan ) fclose( jfp ); } else { if (errno != ENOENT) { - fprintf( stderr, "Error: cannot read journal %s\n", jname ); + error( "Error: cannot read journal %s\n", jname ); ret = SYNC_FAIL; goto bail; } } if (!(nfp = fopen( nname, "w" ))) { - fprintf( stderr, "Error: cannot write new sync state %s\n", nname ); + error( "Error: cannot write new sync state %s\n", nname ); ret = SYNC_FAIL; goto bail; } if (!(jfp = fopen( jname, "a" ))) { - fprintf( stderr, "Error: cannot write journal %s\n", jname ); + error( "Error: cannot write journal %s\n", jname ); fclose( nfp ); ret = SYNC_FAIL; goto bail; @@ -766,9 +766,9 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan ) } } } - debug( " exception list is:" ); + debugn( " exception list is:" ); for (t = 0; t < nmexcs; t++) - debug( " %d", mexcs[t] ); + debugn( " %d", mexcs[t] ); debug( "\n" ); } else if (ctx[M]->opts & OPEN_OLD) minwuid = 1; @@ -811,7 +811,7 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan ) } if ((tmsg->flags & F_FLAGGED) || !chan->stores[t]->max_size || tmsg->size <= chan->stores[t]->max_size) { if (!nmsgs) - info( t ? "Pulling new messages..." : "Pushing new messages..." ); + infon( t ? "Pulling new messages..." : "Pushing new messages..." ); else infoc( '.' ); nmsgs++; diff --git a/src/util.c b/src/util.c @@ -30,7 +30,8 @@ #include <pwd.h> #include <ctype.h> -int DFlags; +int DFlags, Ontty; +static int need_nl; void debug( const char *msg, ... ) @@ -46,6 +47,20 @@ debug( const char *msg, ... ) } void +debugn( const char *msg, ... ) +{ + va_list va; + + if (DFlags & DEBUG) { + va_start( va, msg ); + vprintf( msg, va ); + va_end( va ); + fflush( stdout ); + need_nl = Ontty; + } +} + +void info( const char *msg, ... ) { va_list va; @@ -59,11 +74,26 @@ info( const char *msg, ... ) } void +infon( const char *msg, ... ) +{ + va_list va; + + if (!(DFlags & QUIET)) { + va_start( va, msg ); + vprintf( msg, va ); + va_end( va ); + fflush( stdout ); + need_nl = Ontty; + } +} + +void infoc( char c ) { if (!(DFlags & QUIET)) { putchar( c ); fflush( stdout ); + need_nl = Ontty; } } @@ -73,12 +103,30 @@ warn( const char *msg, ... ) va_list va; if (!(DFlags & VERYQUIET)) { + if (need_nl) { + putchar( '\n' ); + need_nl = 0; + } va_start( va, msg ); vfprintf( stderr, msg, va ); va_end( va ); } } +void +error( const char *msg, ... ) +{ + va_list va; + + if (need_nl) { + putchar( '\n' ); + need_nl = 0; + } + va_start( va, msg ); + vfprintf( stderr, msg, va ); + va_end( va ); +} + char * next_arg( char **s ) { @@ -335,11 +383,11 @@ arc4_init( void ) unsigned char j, si, dat[128]; if ((fd = open( "/dev/urandom", O_RDONLY )) < 0 && (fd = open( "/dev/random", O_RDONLY )) < 0) { - fprintf( stderr, "Fatal: no random number source available.\n" ); + error( "Fatal: no random number source available.\n" ); exit( 3 ); } if (read( fd, dat, 128 ) != 128) { - fprintf( stderr, "Fatal: cannot read random number source.\n" ); + error( "Fatal: cannot read random number source.\n" ); exit( 3 ); } close( fd );