Compare commits

..

No commits in common. '15c7e02e4a5fe127bd55bce2b9aa63a5da8eb228' and '3c4b5f1c83a568f18c14c93aab95c9a853edfd15' have entirely different histories.

  1. 30
      mbsync-get-cert
  2. 5
      src/drv_imap.c
  3. 32
      src/main_sync.c
  4. 2
      src/mbsync.1.in
  5. 1
      src/socket.c
  6. 37
      src/sync.c
  7. 5
      src/util.c

30
mbsync-get-cert

@ -9,25 +9,9 @@
# from a trusted source. # from a trusted source.
# #
usage() { if [ $# != 1 ]; then
echo "Usage: $0 [-s] <host>" >&2 echo "Usage: $0 <host>" >&2
echo " -s Use IMAP+STARTTLS (port 143) instead of IMAPS (port 993)" >&2
exit 1 exit 1
}
STARTTLS=false
while getopts "s" opt; do
case $opt in
s) STARTTLS=true ;;
*) usage ;;
esac
done
shift `expr $OPTIND - 1`
if [ $# -ne 1 ]; then
usage
fi fi
HOST=$1 HOST=$1
@ -49,15 +33,7 @@ TMPFILE=$TMPDIR/get-cert
ERRFILE=$TMPDIR/get-cert-err ERRFILE=$TMPDIR/get-cert-err
CERTFILE=$TMPDIR/cert CERTFILE=$TMPDIR/cert
if $STARTTLS; then echo QUIT | openssl s_client -connect $HOST:993 -showcerts \
FLAGS="-starttls imap"
PORT=143
else
FLAGS=
PORT=993
fi
echo QUIT | openssl s_client $FLAGS -connect $HOST:$PORT -showcerts \
> $TMPFILE 2> $ERRFILE > $TMPFILE 2> $ERRFILE
sed -e '1,/^-----BEGIN CERTIFICATE-----/d' \ sed -e '1,/^-----BEGIN CERTIFICATE-----/d' \
-e '/^-----END CERTIFICATE-----/,$d' < $TMPFILE > $CERTFILE -e '/^-----END CERTIFICATE-----/,$d' < $TMPFILE > $CERTFILE

5
src/drv_imap.c

@ -780,8 +780,6 @@ parse_imap_list( imap_store_t *ctx, char **sp, parse_list_state_t *sts )
if (sts->callback->atom( ctx, NULL, bytes, AtomChunkedLiteral ) != LIST_OK) if (sts->callback->atom( ctx, NULL, bytes, AtomChunkedLiteral ) != LIST_OK)
goto bail; goto bail;
sts->in_literal = ChunkedLiteral; sts->in_literal = ChunkedLiteral;
if (!bytes)
goto nobytes;
sts->big_literal = 1; sts->big_literal = 1;
get_chunked: get_chunked:
n = 1; n = 1;
@ -808,7 +806,7 @@ parse_imap_list( imap_store_t *ctx, char **sp, parse_list_state_t *sts )
} else if (DFlags & DEBUG_NET_ALL) { } else if (DFlags & DEBUG_NET_ALL) {
printf( "%s=========\n", ctx->label ); printf( "%s=========\n", ctx->label );
fwrite( p, n, 1, stdout ); fwrite( p, n, 1, stdout );
if (n && p[n - 1] != '\n') if (p[n - 1] != '\n')
fputs( "\n(no-nl) ", stdout ); fputs( "\n(no-nl) ", stdout );
printf( "%s=========\n", ctx->label ); printf( "%s=========\n", ctx->label );
} else { } else {
@ -821,7 +819,6 @@ parse_imap_list( imap_store_t *ctx, char **sp, parse_list_state_t *sts )
bytes -= n; bytes -= n;
if (bytes > 0) if (bytes > 0)
goto postpone; goto postpone;
nobytes:
if (sts->in_literal == ChunkedLiteral && sts->callback->atom( ctx, NULL, 0, AtomLiteral ) != LIST_OK) if (sts->in_literal == ChunkedLiteral && sts->callback->atom( ctx, NULL, 0, AtomLiteral ) != LIST_OK)
goto bail; goto bail;
getline: getline:

32
src/main_sync.c

@ -9,6 +9,7 @@
#define nz(a, b) ((a) ? (a) : (b)) #define nz(a, b) ((a) ? (a) : (b))
static int ops_any[2], trash_any[2], expunge_any[2];
static int chans_total, chans_done; static int chans_total, chans_done;
static int boxes_total, boxes_done; static int boxes_total, boxes_done;
@ -83,10 +84,25 @@ summary( void )
if (!boxes_done) if (!boxes_done)
return; // Shut up if we errored out early. return; // Shut up if we errored out early.
printf( "Channels: %d Boxes: %d Far: +%d *%d #%d -%d Near: +%d *%d #%d -%d\n", printf( "Processed %d box(es) in %d channel(s)", boxes_done, chans_done );
chans_done, boxes_done, for (int t = 2; --t >= 0; ) {
new_done[F], flags_done[F], trash_done[F], expunge_done[F], if (ops_any[t])
new_done[N], flags_done[N], trash_done[N], expunge_done[N] ); printf( (DFlags & DRYRUN) ?
",\nwould %s %d new message(s) and %d flag update(s)" :
",\n%sed %d new message(s) and %d flag update(s)",
str_hl[t], new_done[t], flags_done[t] );
if (trash_any[t])
printf( (DFlags & DRYRUN) ?
",\nwould move %d %s message(s) to trash" :
",\nmoved %d %s message(s) to trash",
trash_done[t], str_fn[t] );
if (expunge_any[t])
printf( (DFlags & DRYRUN) ?
",\nwould expunge %d message(s) from %s" :
",\nexpunged %d message(s) from %s",
expunge_done[t], str_fn[t] );
}
puts( "." );
} }
static int static int
@ -228,6 +244,14 @@ add_channel( chan_ent_t ***chanapp, channel_conf_t *chan, int ops[] )
free( ce ); free( ce );
return NULL; return NULL;
} }
if (chan->ops[t] & OP_MASK_TYPE)
ops_any[t] = 1;
if (chan->ops[t] & (OP_EXPUNGE | OP_EXPUNGE_SOLO)) {
expunge_any[t] = 1;
if (chan->stores[t]->trash ||
(chan->stores[t^1]->trash && chan->stores[t^1]->trash_remote_new))
trash_any[t] = 1;
}
} }
**chanapp = ce; **chanapp = ce;

2
src/mbsync.1.in

@ -802,7 +802,7 @@ No attempt is made to calculate the totals in advance, so they grow over
time as more information is gathered. time as more information is gathered.
.P .P
Irrespective of output redirection, \fBmbsync\fR will print a summary Irrespective of output redirection, \fBmbsync\fR will print a summary
of the above upon completion, except in quiet mode. of the above in plain language upon completion, except in quiet mode.
. .
.SH RECOMMENDATIONS .SH RECOMMENDATIONS
Make sure your IMAP server does not auto-expunge deleted messages - it is Make sure your IMAP server does not auto-expunge deleted messages - it is

1
src/socket.c

@ -952,6 +952,7 @@ socket_expect_bytes( conn_t *conn, uint len )
char * char *
socket_read( conn_t *conn, uint min_len, uint max_len, uint *out_len ) socket_read( conn_t *conn, uint min_len, uint max_len, uint *out_len )
{ {
assert( min_len > 0 );
assert( min_len <= sizeof(conn->buf) ); assert( min_len <= sizeof(conn->buf) );
assert( min_len <= max_len ); assert( min_len <= max_len );

37
src/sync.c

@ -511,7 +511,7 @@ box_opened2( sync_vars_t *svars, int t )
channel_conf_t *chan; channel_conf_t *chan;
sync_rec_t *srec; sync_rec_t *srec;
uint_array_alloc_t mexcs; uint_array_alloc_t mexcs;
uint opts[2], minwuid; uint opts[2], fails, minwuid;
svars->state[t] |= ST_SELECTED; svars->state[t] |= ST_SELECTED;
if (!(svars->state[t^1] & ST_SELECTED)) if (!(svars->state[t^1] & ST_SELECTED))
@ -520,13 +520,23 @@ box_opened2( sync_vars_t *svars, int t )
ctx[1] = svars->ctx[1]; ctx[1] = svars->ctx[1];
chan = svars->chan; chan = svars->chan;
if (!lock_state( svars )) { fails = 0;
for (t = 0; t < 2; t++)
if (svars->uidval[t] != UIDVAL_BAD && svars->uidval[t] != svars->newuidval[t])
fails++;
// If only one side changed UIDVALIDITY, we will try to re-approve it further down.
if (fails == 2) {
error( "Error: channel %s: UIDVALIDITY of both far side %s and near side %s changed.\n",
svars->chan->name, svars->orig_name[F], svars->orig_name[N]);
bail: bail:
svars->ret = SYNC_FAIL; svars->ret = SYNC_FAIL;
sync_bail( svars ); sync_bail( svars );
return; return;
} }
if (!lock_state( svars ))
goto bail;
int any_dummies[2] = { 0, 0 }; int any_dummies[2] = { 0, 0 };
int any_purges[2] = { 0, 0 }; int any_purges[2] = { 0, 0 };
int any_upgrades[2] = { 0, 0 }; int any_upgrades[2] = { 0, 0 };
@ -564,11 +574,9 @@ box_opened2( sync_vars_t *svars, int t )
} }
opts[F] = opts[N] = 0; opts[F] = opts[N] = 0;
if (fails)
opts[F] = opts[N] = OPEN_PAIRED | OPEN_PAIRED_IDS;
for (t = 0; t < 2; t++) { for (t = 0; t < 2; t++) {
if (svars->uidval[t] != UIDVAL_BAD && svars->uidval[t] != svars->newuidval[t]) {
opts[F] |= OPEN_PAIRED | OPEN_PAIRED_IDS;
opts[N] |= OPEN_PAIRED | OPEN_PAIRED_IDS;
}
if (any_purges[t]) { if (any_purges[t]) {
debug( "resuming %d %s purge(s)\n", any_purges[t], str_fn[t] ); debug( "resuming %d %s purge(s)\n", any_purges[t], str_fn[t] );
opts[t] |= OPEN_SETFLAGS; opts[t] |= OPEN_SETFLAGS;
@ -851,15 +859,8 @@ box_loaded( int sts, message_t *msgs, int total_msgs, int recent_msgs, void *aux
if (!srec->msg[t^1]) if (!srec->msg[t^1])
continue; // Partner disappeared. continue; // Partner disappeared.
if (!srec->msg[t^1]->msgid || strcmp( srec->msg[F]->msgid, srec->msg[N]->msgid )) { if (!srec->msg[t^1]->msgid || strcmp( srec->msg[F]->msgid, srec->msg[N]->msgid )) {
if (svars->uidval[t^1] != svars->newuidval[t^1]) { error( "Error: channel %s, %s box %s: UIDVALIDITY genuinely changed (at UID %u).\n",
error( "Error: channel %s, %s box %s (at UID %u):" svars->chan->name, str_fn[t], svars->orig_name[t], srec->uid[t] );
" Unable to recover from both-sided UIDVALIDITY change,"
" as it is genuine on at least one side.\n",
svars->chan->name, str_fn[t], svars->orig_name[t], srec->uid[t] );
} else {
error( "Error: channel %s, %s box %s (at UID %u): UIDVALIDITY genuinely changed.\n",
svars->chan->name, str_fn[t], svars->orig_name[t], srec->uid[t] );
}
uvchg: uvchg:
svars->ret |= SYNC_FAIL; svars->ret |= SYNC_FAIL;
cancel_sync( svars ); cancel_sync( svars );
@ -1013,7 +1014,7 @@ box_loaded( int sts, message_t *msgs, int total_msgs, int recent_msgs, void *aux
sflags = sanitize_flags( sflags, svars, t ); sflags = sanitize_flags( sflags, svars, t );
if ((t != xt) && (srec->status & (S_EXPIRE | S_EXPIRED))) { if ((t != xt) && (srec->status & (S_EXPIRE | S_EXPIRED))) {
/* Don't propagate deletion resulting from expiration. */ /* Don't propagate deletion resulting from expiration. */
debug( " %s side expiring\n", str_fn[xt] ); debug( " near side expiring\n" );
sflags &= ~F_DELETED; sflags &= ~F_DELETED;
} }
if (srec->status & S_DUMMY(t^1)) { if (srec->status & S_DUMMY(t^1)) {
@ -1204,7 +1205,7 @@ box_loaded( int sts, message_t *msgs, int total_msgs, int recent_msgs, void *aux
if (!srec->uid[xt^1]) if (!srec->uid[xt^1])
continue; continue;
if (!(srec->status & S_PENDING)) { if (!(srec->status & S_PENDING)) {
// We ignore unpaired keep-side messages, as there is obviously nothing // We ignore unpaired far-side messages, as there is obviously nothing
// to expire in the first place. // to expire in the first place.
if (!srec->msg[xt]) if (!srec->msg[xt])
continue; continue;
@ -1229,8 +1230,6 @@ box_loaded( int sts, message_t *msgs, int total_msgs, int recent_msgs, void *aux
// but we may be pulling in the real ones. // but we may be pulling in the real ones.
nflags = (srec->pflags | srec->aflags[xt]) & ~srec->dflags[xt]; nflags = (srec->pflags | srec->aflags[xt]) & ~srec->dflags[xt];
} else { } else {
if (!srec->msg[xt^1])
continue;
nflags = srec->msg[xt^1]->flags; nflags = srec->msg[xt^1]->flags;
} }
} }

5
src/util.c

@ -637,11 +637,6 @@ nfmalloc( size_t sz )
{ {
void *ret; void *ret;
#ifndef __GLIBC__
// The C standard allows NULL returns for zero-sized allocations.
if (!sz)
sz = 1;
#endif
if (!(ret = malloc( sz ))) if (!(ret = malloc( sz )))
oom(); oom();
return ret; return ret;

Loading…
Cancel
Save