Compare commits
40 commits
Author | SHA1 | Date | |
---|---|---|---|
|
9f1320ff0c | ||
|
e895cd11f7 | ||
|
b6ae600419 | ||
|
2074a7ab03 | ||
|
1af2cfde4f | ||
|
2d5a73c55d | ||
|
608a2863e0 | ||
|
b546877d70 | ||
|
d47cca7dd9 | ||
|
d2ccc93584 | ||
|
dff2f6a9f5 | ||
|
5e43508aec | ||
|
8616ed393d | ||
|
6636d7ebb7 | ||
|
e161af47bb | ||
|
1b9b5f8bfd | ||
|
5d03247bec | ||
|
0d27c5f4cb | ||
|
0eb399c672 | ||
|
9a0539868a | ||
|
43f23fb180 | ||
|
d51a91aeba | ||
|
f7ba199d35 | ||
|
a54459af1c | ||
|
3759f0c802 | ||
|
6494cfc438 | ||
|
afc48600fa | ||
|
4b70d9b96c | ||
|
41c4e0d681 | ||
|
b6c6299ea6 | ||
|
2e39fa9930 | ||
|
927feae988 | ||
|
3f1009a839 | ||
|
fd3f4f33ff | ||
|
314287cbb4 | ||
|
b40fb7f281 | ||
|
534ccb326a | ||
|
63c065a127 | ||
|
161a4b1159 | ||
|
9a5920c028 |
17 changed files with 238 additions and 1549 deletions
6
.cvsignore → .gitignore
vendored
6
.cvsignore → .gitignore
vendored
|
@ -1,4 +1,6 @@
|
|||
.autoconf_trace
|
||||
ChangeLog
|
||||
INSTALL
|
||||
Makefile
|
||||
Makefile.in
|
||||
autom4te.cache
|
||||
|
@ -14,9 +16,13 @@ config.sub
|
|||
configure
|
||||
configure.lineno
|
||||
configure-stamp
|
||||
depcomp
|
||||
install-sh
|
||||
isync.spec
|
||||
isync-*.tar.gz
|
||||
missing
|
||||
patch-stamp
|
||||
stamp-h
|
||||
stamp-h.in
|
||||
stamp-h1
|
||||
*~
|
62
Makefile.am
62
Makefile.am
|
@ -2,11 +2,59 @@ SUBDIRS = src
|
|||
bin_SCRIPTS = get-cert
|
||||
EXTRA_DIST = debian isync.spec $(bin_SCRIPTS)
|
||||
|
||||
log:
|
||||
@perl -p -e "s/^(\\S+)\\s+(\\S.+\\S)\\s+(\\S+)\\s*\$$/\$$1:'\$$2 <\$$3>'\\n/" < ../CVSROOT/accounts > .usermap
|
||||
cvs2cl -U .usermap --no-wrap --separate-header -I ChangeLog -I NEWS -I TODO -I debian/
|
||||
@rm -f .usermap ChangeLog.bak
|
||||
LOG_PL = \
|
||||
use POSIX qw(strftime); \
|
||||
use Date::Parse; \
|
||||
use Text::Wrap; \
|
||||
$$Text::Wrap::columns = 72; \
|
||||
while (defined($$_ = <>)) { \
|
||||
/^commit / or die "commit missing: $$_"; \
|
||||
<> =~ /^log size (\d+)$$/ or die "wrong size"; \
|
||||
$$len = $$1; \
|
||||
read(STDIN, $$log, $$len) == $$len or die "unexpected EOF"; \
|
||||
$$log =~ s/^Author: ([^>]+>)\nDate: (\d{4}-\d\d-\d\d \d\d:\d\d:\d\d [-+]\d{4})\n(.*)$$/$$3/s or die "unexpected log format"; \
|
||||
$$author = $$1; $$date = str2time($$2); \
|
||||
scalar(<>); \
|
||||
@files = (); \
|
||||
$$pfx = ""; \
|
||||
while (defined($$l = <>) and $$l ne "\n") { \
|
||||
chomp $$l; \
|
||||
next if ($$l =~ m,^(ChangeLog$$|NEWS$$|TODO$$|debian/),); \
|
||||
if (!@files) { \
|
||||
$$pfx = $$l; \
|
||||
$$pfx =~ s,/?[^/]+$$,,; \
|
||||
} else { \
|
||||
while (length($$pfx)) { \
|
||||
$$l =~ m,^\Q$$pfx/\E, and last; \
|
||||
$$pfx =~ s,/?[^/]+$$,,; \
|
||||
} \
|
||||
} \
|
||||
push @files, $$l; \
|
||||
} \
|
||||
next if (!@files); \
|
||||
print strftime("%F %H:%M", gmtime($$date))." ".$$author."\n\n"; \
|
||||
if (@files > 1 and ($$len = length($$pfx))) { \
|
||||
@efiles = (); \
|
||||
for $$f (@files) { push @efiles, substr($$f, $$len + 1); } \
|
||||
$$fstr = $$pfx."/: "; \
|
||||
} else { \
|
||||
@efiles = @files; \
|
||||
$$fstr = ""; \
|
||||
} \
|
||||
print wrap("\t* ", "\t ", $$fstr.join(", ", @efiles).":")."\n"; \
|
||||
$$log =~ s, +$$,,gm; \
|
||||
$$log =~ s,^ ,\t,gm; \
|
||||
print $$log."\n"; \
|
||||
}
|
||||
|
||||
$(srcdir)/ChangeLog: log
|
||||
log:
|
||||
@test -z "$(srcdir)" || cd $(srcdir) && \
|
||||
( ! test -d .git || \
|
||||
git log --date=iso --log-size --name-only | \
|
||||
perl -e '$(LOG_PL)' > ChangeLog )
|
||||
|
||||
if in_source_build
|
||||
deb:
|
||||
CFLAGS="-O2 -mcpu=i686" fakeroot debian/rules binary
|
||||
|
||||
|
@ -17,7 +65,11 @@ deb-clean:
|
|||
distdir distclean: deb-clean
|
||||
|
||||
dist-hook:
|
||||
find $(distdir)/debian \( -name CVS -o -name .cvsignore -o -name .#\*# -o -type l \) -print0 | xargs -0r rm -rf
|
||||
find $(distdir)/debian \( -name .git -o -name .gitignore -o -name .#\*# -o -type l \) -print0 | xargs -0r rm -rf
|
||||
endif
|
||||
|
||||
dist-sign: dist
|
||||
gpg -b -a $(PACKAGE)-$(VERSION).tar.gz
|
||||
|
||||
rpm:
|
||||
make dist
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#! /bin/sh
|
||||
set -e -v
|
||||
make -f Makefile.am log
|
||||
aclocal
|
||||
autoheader
|
||||
automake --add-missing
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
AC_INIT(src/isync.h)
|
||||
AM_CONFIG_HEADER(config.h)
|
||||
AM_INIT_AUTOMAKE(isync, 1.0.1)
|
||||
AM_INIT_AUTOMAKE(isync, 1.0.5)
|
||||
|
||||
AM_MAINTAINER_MODE
|
||||
|
||||
|
@ -9,6 +9,7 @@ if test "$GCC" = yes; then
|
|||
CFLAGS="$CFLAGS -pipe -W -Wall -Wshadow -Wstrict-prototypes"
|
||||
fi
|
||||
|
||||
AC_CHECK_HEADERS([sys/filio.h])
|
||||
AC_CHECK_FUNCS(vasprintf)
|
||||
|
||||
AC_CHECK_LIB(socket, socket, [SOCK_LIBS="-lsocket"])
|
||||
|
@ -93,6 +94,8 @@ if test "x$ob_cv_enable_compat" != xno; then
|
|||
fi
|
||||
AM_CONDITIONAL(with_compat, test "x$ob_cv_enable_compat" != xno)
|
||||
|
||||
AM_CONDITIONAL(in_source_build, test "x$srcdir" = x.)
|
||||
|
||||
AC_OUTPUT(Makefile src/Makefile src/compat/Makefile isync.spec)
|
||||
|
||||
if test -n "$have_ssl_paths"; then
|
||||
|
|
1
src/.cvsignore → src/.gitignore
vendored
1
src/.cvsignore → src/.gitignore
vendored
|
@ -3,3 +3,4 @@ Makefile
|
|||
Makefile.in
|
||||
mbsync
|
||||
mdconvert
|
||||
*.o
|
|
@ -2,3 +2,4 @@
|
|||
Makefile
|
||||
Makefile.in
|
||||
isync
|
||||
*.o
|
|
@ -250,8 +250,9 @@ write_imap_server( FILE *fp, config_t *cfg )
|
|||
cfg->server_name, cfg->tunnel );
|
||||
} else {
|
||||
if (sscanf( cfg->host, "%d.%d.%d.%d", &a1, &a2, &a3, &a4 ) == 4)
|
||||
/* XXX this does not avoid clashes. add port? */
|
||||
cfg->server_name = nfstrdup( cfg->host );
|
||||
else {
|
||||
else if (cfg->host) {
|
||||
p = strrchr( cfg->host, '.' );
|
||||
if (!p)
|
||||
hl = nfsnprintf( buf, sizeof(buf), "%s", cfg->host );
|
||||
|
@ -270,6 +271,9 @@ write_imap_server( FILE *fp, config_t *cfg )
|
|||
cfg->server_name = nfstrdup( buf );
|
||||
cfg->servers = 1;
|
||||
gotsrv: ;
|
||||
} else {
|
||||
fprintf( stderr, "ERROR: Neither host nor tunnel specified for mailbox %s.\n", cfg->path );
|
||||
exit( 1 );
|
||||
}
|
||||
fprintf( fp, "IMAPAccount %s\n", cfg->server_name );
|
||||
if (cfg->use_imaps)
|
||||
|
@ -279,7 +283,7 @@ write_imap_server( FILE *fp, config_t *cfg )
|
|||
fprintf( fp, "Port %d\n", cfg->port );
|
||||
}
|
||||
if (cfg->user)
|
||||
fprintf( fp, "User %s\n", cfg->user );
|
||||
fprintf( fp, "User \"%s\"\n", cfg->user );
|
||||
if (cfg->pass)
|
||||
fprintf( fp, "Pass \"%s\"\n", cfg->pass );
|
||||
fprintf( fp, "RequireCRAM %s\nRequireSSL %s\n"
|
||||
|
@ -350,7 +354,8 @@ write_config( int fd )
|
|||
|
||||
fprintf( fp, "SyncState *\n\n" );
|
||||
if (local_home || o2o)
|
||||
fprintf( fp, "MaildirStore local\nPath \"%s/\"\nAltMap %s\n\n", maildir, tb( altmap > 0 ) );
|
||||
fprintf( fp, "MaildirStore local\nPath \"%s/\"\nInbox \"%s/INBOX\"\nAltMap %s\n\n",
|
||||
maildir, maildir, tb( altmap > 0 ) );
|
||||
if (local_root)
|
||||
fprintf( fp, "MaildirStore local_root\nPath /\nAltMap %s\n\n", tb( altmap > 0 ) );
|
||||
if (o2o) {
|
||||
|
|
|
@ -145,7 +145,7 @@ convert( config_t *box )
|
|||
fputs( "dbcreate failed\n", stderr );
|
||||
goto err2;
|
||||
}
|
||||
if (db->open( db, 0, iumname, 0, DB_HASH, 0, 0 )) {
|
||||
if ((db->open)( db, 0, iumname, 0, DB_HASH, 0, 0 )) {
|
||||
fputs( "cannot open db\n", stderr );
|
||||
db->close( db, 0 );
|
||||
goto err2;
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/param.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
@ -167,6 +168,11 @@ main( int argc, char **argv )
|
|||
/* defaults */
|
||||
/* XXX the precedence is borked:
|
||||
it's defaults < cmdline < file instead of defaults < file < cmdline */
|
||||
#ifdef BSD
|
||||
global.user = getenv( "USER" );
|
||||
#else
|
||||
global.user = getenv( "LOGNAME" );
|
||||
#endif
|
||||
global.port = 143;
|
||||
global.box = "INBOX";
|
||||
global.use_namespace = 1;
|
||||
|
@ -331,8 +337,8 @@ main( int argc, char **argv )
|
|||
while ((de = readdir( dir ))) {
|
||||
if (*de->d_name == '.')
|
||||
continue;
|
||||
nfsnprintf( path1, sizeof(path1), "%s/%s/cur", xmaildir, de->d_name );
|
||||
if (stat( path1, &st ) || !S_ISDIR( st.st_mode ))
|
||||
nfsnprintf( path2, sizeof(path2), "%s/%s/cur", xmaildir, de->d_name );
|
||||
if (stat( path2, &st ) || !S_ISDIR( st.st_mode ))
|
||||
continue;
|
||||
global.path = de->d_name;
|
||||
global.box = (inbox && !strcmp( inbox, global.path )) ?
|
||||
|
|
127
src/drv_imap.c
127
src/drv_imap.c
|
@ -31,11 +31,15 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stddef.h>
|
||||
#include <limits.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#ifdef HAVE_SYS_FILIO_H
|
||||
# include <sys/filio.h>
|
||||
#endif
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <arpa/inet.h>
|
||||
|
@ -250,11 +254,9 @@ init_ssl_ctx( imap_store_t *ctx )
|
|||
if (!srvc->cert_file) {
|
||||
fprintf( stderr, "Error, CertificateFile not defined\n" );
|
||||
return -1;
|
||||
} else if (access( srvc->cert_file, R_OK ))
|
||||
warn( "*** Warning: can't read CertificateFile, so can't verify server certificates\n" );
|
||||
else if (!SSL_CTX_load_verify_locations( imap->SSLContext, srvc->cert_file, NULL )) {
|
||||
fprintf( stderr, "Error, SSL_CTX_load_verify_locations: %s\n",
|
||||
ERR_error_string( ERR_get_error(), 0 ) );
|
||||
} 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 ) );
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -374,7 +376,7 @@ buffer_gets( buffer_t * b, char **s )
|
|||
n = b->bytes - start;
|
||||
|
||||
if (n)
|
||||
memcpy( b->buf, b->buf + start, n );
|
||||
memmove( b->buf, b->buf + start, n );
|
||||
b->offset -= start;
|
||||
b->bytes = n;
|
||||
start = 0;
|
||||
|
@ -815,7 +817,7 @@ static int
|
|||
parse_response_code( imap_store_t *ctx, struct imap_cmd_cb *cb, char *s )
|
||||
{
|
||||
imap_t *imap = ctx->imap;
|
||||
char *arg, *p;
|
||||
char *arg, *earg, *p;
|
||||
|
||||
if (*s != '[')
|
||||
return RESP_OK; /* no response code */
|
||||
|
@ -827,12 +829,14 @@ parse_response_code( imap_store_t *ctx, struct imap_cmd_cb *cb, char *s )
|
|||
*p++ = 0;
|
||||
arg = next_arg( &s );
|
||||
if (!strcmp( "UIDVALIDITY", arg )) {
|
||||
if (!(arg = next_arg( &s )) || !(ctx->gen.uidvalidity = atoi( arg ))) {
|
||||
if (!(arg = next_arg( &s )) ||
|
||||
(ctx->gen.uidvalidity = strtoll( arg, &earg, 10 ), *earg))
|
||||
{
|
||||
fprintf( stderr, "IMAP error: malformed UIDVALIDITY status\n" );
|
||||
return RESP_BAD;
|
||||
}
|
||||
} else if (!strcmp( "UIDNEXT", arg )) {
|
||||
if (!(arg = next_arg( &s )) || !(imap->uidnext = atoi( arg ))) {
|
||||
if (!(arg = next_arg( &s )) || (imap->uidnext = strtol( arg, &p, 10 ), *p)) {
|
||||
fprintf( stderr, "IMAP error: malformed NEXTUID status\n" );
|
||||
return RESP_BAD;
|
||||
}
|
||||
|
@ -845,7 +849,8 @@ parse_response_code( imap_store_t *ctx, struct imap_cmd_cb *cb, char *s )
|
|||
for (; isspace( (unsigned char)*p ); p++);
|
||||
fprintf( stderr, "*** IMAP ALERT *** %s\n", p );
|
||||
} else if (cb && cb->ctx && !strcmp( "APPENDUID", arg )) {
|
||||
if (!(arg = next_arg( &s )) || !(ctx->gen.uidvalidity = atoi( arg )) ||
|
||||
if (!(arg = next_arg( &s )) ||
|
||||
(ctx->gen.uidvalidity = strtoll( arg, &earg, 10 ), *earg) ||
|
||||
!(arg = next_arg( &s )) || !(*(int *)cb->ctx = atoi( arg )))
|
||||
{
|
||||
fprintf( stderr, "IMAP error: malformed APPENDUID status\n" );
|
||||
|
@ -863,7 +868,9 @@ parse_search( imap_t *imap, char *cmd )
|
|||
int uid;
|
||||
|
||||
arg = next_arg( &cmd );
|
||||
if (!arg || !(uid = atoi( arg ))) {
|
||||
if (!arg)
|
||||
return;
|
||||
if (!(uid = atoi( arg ))) {
|
||||
fprintf( stderr, "IMAP error: malformed SEARCH response\n" );
|
||||
return;
|
||||
}
|
||||
|
@ -1240,7 +1247,11 @@ imap_open_store( store_conf_t *conf, store_t *oldctx )
|
|||
info( "ok\n" );
|
||||
} else {
|
||||
memset( &addr, 0, sizeof(addr) );
|
||||
addr.sin_port = htons( srvc->port );
|
||||
addr.sin_port = srvc->port ? htons( srvc->port ) :
|
||||
#ifdef HAVE_LIBSSL
|
||||
srvc->use_imaps ? htons( 993 ) :
|
||||
#endif
|
||||
htons( 143 );
|
||||
addr.sin_family = AF_INET;
|
||||
|
||||
info( "Resolving %s... ", srvc->host );
|
||||
|
@ -1264,15 +1275,15 @@ imap_open_store( store_conf_t *conf, store_t *oldctx )
|
|||
info( "ok\n" );
|
||||
|
||||
imap->buf.sock.fd = s;
|
||||
}
|
||||
|
||||
#if HAVE_LIBSSL
|
||||
if (srvc->use_imaps) {
|
||||
if (start_tls( ctx ))
|
||||
goto bail;
|
||||
use_ssl = 1;
|
||||
}
|
||||
#endif
|
||||
if (srvc->use_imaps) {
|
||||
if (start_tls( ctx ))
|
||||
goto ssl_bail;
|
||||
use_ssl = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* read the greeting string */
|
||||
if (buffer_gets( &imap->buf, &rsp )) {
|
||||
|
@ -1303,7 +1314,7 @@ imap_open_store( store_conf_t *conf, store_t *oldctx )
|
|||
if (imap_exec( ctx, 0, "STARTTLS" ) != RESP_OK)
|
||||
goto bail;
|
||||
if (start_tls( ctx ))
|
||||
goto bail;
|
||||
goto ssl_bail;
|
||||
use_ssl = 1;
|
||||
|
||||
if (imap_exec( ctx, 0, "CAPABILITY" ) != RESP_OK)
|
||||
|
@ -1388,6 +1399,12 @@ imap_open_store( store_conf_t *conf, store_t *oldctx )
|
|||
ctx->trashnc = 1;
|
||||
return (store_t *)ctx;
|
||||
|
||||
#if HAVE_LIBSSL
|
||||
ssl_bail:
|
||||
/* This avoids that we try to send LOGOUT to an unusable socket. */
|
||||
close( imap->buf.sock.fd );
|
||||
imap->buf.sock.fd = -1;
|
||||
#endif
|
||||
bail:
|
||||
imap_close_store( &ctx->gen );
|
||||
return 0;
|
||||
|
@ -1420,6 +1437,8 @@ imap_select( store_t *gctx, int minuid, int maxuid, int *excs, int nexcs )
|
|||
prefix = ctx->prefix;
|
||||
}
|
||||
|
||||
imap->uidnext = -1;
|
||||
|
||||
memset( &cb, 0, sizeof(cb) );
|
||||
cb.create = (gctx->opts & OPEN_CREATE) != 0;
|
||||
cb.trycreate = 1;
|
||||
|
@ -1445,7 +1464,7 @@ imap_select( store_t *gctx, int minuid, int maxuid, int *excs, int nexcs )
|
|||
goto bail;
|
||||
}
|
||||
if (maxuid == INT_MAX)
|
||||
maxuid = imap->uidnext ? imap->uidnext - 1 : 1000000000;
|
||||
maxuid = imap->uidnext >= 0 ? imap->uidnext - 1 : 1000000000;
|
||||
if (maxuid >= minuid &&
|
||||
(ret = imap_exec_b( ctx, 0, "UID FETCH %d:%d (UID%s%s)", minuid, maxuid,
|
||||
(gctx->opts & OPEN_FLAGS) ? " FLAGS" : "",
|
||||
|
@ -1575,6 +1594,7 @@ imap_store_msg( store_t *gctx, msg_data_t *data, int *uid )
|
|||
}
|
||||
/* invalid message */
|
||||
free( fmap );
|
||||
fprintf( stderr, "IMAP warning: storing message with incomplete header.\n" );
|
||||
return DRV_MSG_BAD;
|
||||
mktid:
|
||||
for (j = 0; j < TUIDL; j++)
|
||||
|
@ -1691,6 +1711,7 @@ imap_parse_store( conffile_t *cfg, store_conf_t **storep, int *err )
|
|||
{
|
||||
imap_store_conf_t *store;
|
||||
imap_server_conf_t *server, *srv, sserver;
|
||||
int acc_opt = 0;
|
||||
|
||||
if (!strcasecmp( "IMAPAccount", cfg->cmd )) {
|
||||
server = nfcalloc( sizeof(*server) );
|
||||
|
@ -1698,11 +1719,13 @@ imap_parse_store( conffile_t *cfg, store_conf_t **storep, int *err )
|
|||
*serverapp = server;
|
||||
serverapp = &server->next;
|
||||
store = 0;
|
||||
*storep = 0;
|
||||
} else if (!strcasecmp( "IMAPStore", cfg->cmd )) {
|
||||
store = nfcalloc( sizeof(*store) );
|
||||
store->gen.driver = &imap_driver;
|
||||
store->gen.name = nfstrdup( cfg->val );
|
||||
store->use_namespace = 1;
|
||||
*storep = &store->gen;
|
||||
memset( &sserver, 0, sizeof(sserver) );
|
||||
server = &sserver;
|
||||
} else
|
||||
|
@ -1717,32 +1740,19 @@ imap_parse_store( conffile_t *cfg, store_conf_t **storep, int *err )
|
|||
#endif
|
||||
|
||||
while (getcline( cfg ) && cfg->cmd) {
|
||||
if (!strcasecmp( "Account", cfg->cmd )) {
|
||||
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 );
|
||||
*err = 1;
|
||||
continue;
|
||||
gotsrv:
|
||||
store->server = srv;
|
||||
} else if (!strcasecmp( "Host", cfg->cmd )) {
|
||||
if (!strcasecmp( "Host", cfg->cmd )) {
|
||||
/* The imap[s]: syntax is just a backwards compat hack. */
|
||||
#if HAVE_LIBSSL
|
||||
if (!memcmp( "imaps:", cfg->val, 6 )) {
|
||||
cfg->val += 6;
|
||||
server->use_imaps = 1;
|
||||
server->use_sslv2 = 1;
|
||||
server->use_sslv3 = 1;
|
||||
if (!server->port)
|
||||
server->port = 993;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
if (!memcmp( "imap:", cfg->val, 5 ))
|
||||
cfg->val += 5;
|
||||
if (!server->port)
|
||||
server->port = 143;
|
||||
}
|
||||
if (!memcmp( "//", cfg->val, 2 ))
|
||||
cfg->val += 2;
|
||||
|
@ -1755,10 +1765,17 @@ imap_parse_store( conffile_t *cfg, store_conf_t **storep, int *err )
|
|||
else if (!strcasecmp( "Port", cfg->cmd ))
|
||||
server->port = parse_int( cfg );
|
||||
#if HAVE_LIBSSL
|
||||
else if (!strcasecmp( "CertificateFile", cfg->cmd ))
|
||||
else if (!strcasecmp( "CertificateFile", cfg->cmd )) {
|
||||
server->cert_file = expand_strdup( cfg->val );
|
||||
else if (!strcasecmp( "RequireSSL", cfg->cmd ))
|
||||
if (access( server->cert_file, R_OK )) {
|
||||
fprintf( stderr, "%s:%d: CertificateFile '%s': %s\n",
|
||||
cfg->file, cfg->line, server->cert_file, strerror( errno ) );
|
||||
*err = 1;
|
||||
}
|
||||
} else if (!strcasecmp( "RequireSSL", cfg->cmd ))
|
||||
server->require_ssl = parse_bool( cfg );
|
||||
else if (!strcasecmp( "UseIMAPS", cfg->cmd ))
|
||||
server->use_imaps = parse_bool( cfg );
|
||||
else if (!strcasecmp( "UseSSLv2", cfg->cmd ))
|
||||
server->use_sslv2 = parse_bool( cfg );
|
||||
else if (!strcasecmp( "UseSSLv3", cfg->cmd ))
|
||||
|
@ -1771,34 +1788,50 @@ imap_parse_store( conffile_t *cfg, store_conf_t **storep, int *err )
|
|||
else if (!strcasecmp( "Tunnel", cfg->cmd ))
|
||||
server->tunnel = nfstrdup( cfg->val );
|
||||
else if (store) {
|
||||
if (!strcasecmp( "UseNamespace", cfg->cmd ))
|
||||
if (!strcasecmp( "Account", cfg->cmd )) {
|
||||
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 );
|
||||
*err = 1;
|
||||
continue;
|
||||
gotsrv:
|
||||
store->server = srv;
|
||||
} else if (!strcasecmp( "UseNamespace", cfg->cmd ))
|
||||
store->use_namespace = parse_bool( cfg );
|
||||
else if (!strcasecmp( "Path", cfg->cmd ))
|
||||
store->gen.path = nfstrdup( cfg->val );
|
||||
else
|
||||
parse_generic_store( &store->gen, cfg, err );
|
||||
continue;
|
||||
} else {
|
||||
fprintf( stderr, "%s:%d: unknown keyword '%s'\n",
|
||||
fprintf( stderr, "%s:%d: unknown/misplaced keyword '%s'\n",
|
||||
cfg->file, cfg->line, cfg->cmd );
|
||||
*err = 1;
|
||||
continue;
|
||||
}
|
||||
acc_opt = 1;
|
||||
}
|
||||
if (!store || !store->server) {
|
||||
if (!server->tunnel && !server->host) {
|
||||
if (store)
|
||||
fprintf( stderr, "IMAP store '%s' has incomplete connection details\n", store->gen.name );
|
||||
fprintf( stderr, "IMAP store '%s' has incomplete/missing connection details\n", store->gen.name );
|
||||
else
|
||||
fprintf( stderr, "IMAP account '%s' has incomplete connection details\n", server->name );
|
||||
fprintf( stderr, "IMAP account '%s' has incomplete/missing connection details\n", server->name );
|
||||
*err = 1;
|
||||
/* leaking server/store */
|
||||
*storep = 0;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
*storep = &store->gen;
|
||||
if (store && !store->server) {
|
||||
store->server = nfmalloc( sizeof(sserver) );
|
||||
memcpy( store->server, &sserver, sizeof(sserver) );
|
||||
if (store) {
|
||||
if (!store->server) {
|
||||
store->server = nfmalloc( sizeof(sserver) );
|
||||
memcpy( store->server, &sserver, sizeof(sserver) );
|
||||
store->server->name = store->gen.name;
|
||||
} else if (acc_opt) {
|
||||
fprintf( stderr, "IMAP store '%s' has both Account and account-specific options\n", store->gen.name );
|
||||
*err = 1;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -161,15 +161,17 @@ maildir_list( store_t *gctx, string_list_t **retb )
|
|||
}
|
||||
*retb = 0;
|
||||
while ((de = readdir( dir ))) {
|
||||
const char *inbox = ((maildir_store_conf_t *)gctx->conf)->inbox;
|
||||
int bl;
|
||||
struct stat st;
|
||||
char buf[PATH_MAX];
|
||||
|
||||
if (*de->d_name == '.')
|
||||
continue;
|
||||
nfsnprintf( buf, sizeof(buf), "%s%s/cur", gctx->conf->path, de->d_name );
|
||||
bl = nfsnprintf( buf, sizeof(buf), "%s%s/cur", gctx->conf->path, de->d_name );
|
||||
if (stat( buf, &st ) || !S_ISDIR(st.st_mode))
|
||||
continue;
|
||||
add_string_list( retb, de->d_name );
|
||||
add_string_list( retb, !memcmp( buf, inbox, bl - 4 ) && !inbox[bl - 4] ? "INBOX" : de->d_name );
|
||||
}
|
||||
closedir (dir);
|
||||
|
||||
|
@ -345,7 +347,8 @@ maildir_init_uid( maildir_store_t *ctx, const char *msg )
|
|||
ctx->uvok = 0;
|
||||
#ifdef USE_DB
|
||||
if (ctx->db) {
|
||||
ctx->db->truncate( ctx->db, 0, 0 /* &u_int32_t_dummy */, 0 );
|
||||
u_int32_t count;
|
||||
ctx->db->truncate( ctx->db, 0, &count, 0 );
|
||||
return maildir_set_uid( ctx, 0, 0 );
|
||||
}
|
||||
#endif /* USE_DB */
|
||||
|
@ -475,7 +478,7 @@ maildir_scan( maildir_store_t *ctx, msglist_t *msglist )
|
|||
DBC *dbc;
|
||||
#endif /* USE_DB */
|
||||
msg_t *entry;
|
||||
int i, j, uid, bl, ml, fnl, ret;
|
||||
int i, j, uid, bl, fnl, ret;
|
||||
struct stat st;
|
||||
char buf[_POSIX_PATH_MAX], nbuf[_POSIX_PATH_MAX];
|
||||
|
||||
|
@ -496,7 +499,7 @@ maildir_scan( maildir_store_t *ctx, msglist_t *msglist )
|
|||
fputs( "Maildir error: db_create() failed\n", stderr );
|
||||
return DRV_BOX_BAD;
|
||||
}
|
||||
if (tdb->open( tdb, 0, 0, 0, DB_HASH, DB_CREATE, 0 )) {
|
||||
if ((tdb->open)( tdb, 0, 0, 0, DB_HASH, DB_CREATE, 0 )) {
|
||||
fputs( "Maildir error: tdb->open() failed\n", stderr );
|
||||
tdb->close( tdb, 0 );
|
||||
return DRV_BOX_BAD;
|
||||
|
@ -637,11 +640,10 @@ maildir_scan( maildir_store_t *ctx, msglist_t *msglist )
|
|||
for (ru = u + 3; isdigit( (unsigned char)*ru ); ru++);
|
||||
else
|
||||
u = ru = strchr( entry->base, ':' );
|
||||
if (u)
|
||||
ml = u - entry->base;
|
||||
else
|
||||
ru = "", ml = INT_MAX;
|
||||
fnl = nfsnprintf( buf + bl, sizeof(buf) - bl, "%s/%.*s,U=%d%s", subdirs[entry->recent], ml, entry->base, uid, ru ) + 1 - 4;
|
||||
fnl = (u ?
|
||||
nfsnprintf( buf + bl, sizeof(buf) - bl, "%s/%.*s,U=%d%s", subdirs[entry->recent], u - entry->base, entry->base, uid, ru ) :
|
||||
nfsnprintf( buf + bl, sizeof(buf) - bl, "%s/%s,U=%d", subdirs[entry->recent], entry->base, uid ))
|
||||
+ 1 - 4;
|
||||
memcpy( nbuf, buf, bl + 4 );
|
||||
nfsnprintf( nbuf + bl + 4, sizeof(nbuf) - bl - 4, "%s", entry->base );
|
||||
if (rename( nbuf, buf )) {
|
||||
|
@ -781,7 +783,7 @@ maildir_select( store_t *gctx, int minuid, int maxuid, int *excs, int nexcs )
|
|||
fputs( "Maildir error: db_create() failed\n", stderr );
|
||||
goto bork;
|
||||
}
|
||||
if ((ret = ctx->db->open( ctx->db, 0, uvpath, 0, DB_HASH, DB_CREATE, 0 ))) {
|
||||
if ((ret = (ctx->db->open)( ctx->db, 0, uvpath, 0, DB_HASH, DB_CREATE, 0 ))) {
|
||||
ctx->db->err( ctx->db, ret, "Maildir error: db->open(%s)", uvpath );
|
||||
dbork:
|
||||
ctx->db->close( ctx->db, 0 );
|
||||
|
|
|
@ -178,8 +178,10 @@ main( int argc, char **argv )
|
|||
}
|
||||
arc4_init();
|
||||
|
||||
for (oind = 1, ochar = 0; oind < argc; ) {
|
||||
for (oind = 1, ochar = 0; ; ) {
|
||||
if (!ochar || !*ochar) {
|
||||
if (oind >= argc)
|
||||
break;
|
||||
if (argv[oind][0] != '-')
|
||||
break;
|
||||
if (argv[oind][1] == '-') {
|
||||
|
|
27
src/mbsync.1
27
src/mbsync.1
|
@ -210,17 +210,13 @@ The location of the \fBINBOX\fR. This is \fInot\fR relative to \fBPath\fR.
|
|||
Define the IMAP4 Account \fIname\fR, opening a section for its parameters.
|
||||
..
|
||||
.TP
|
||||
\fBHost\fR [\fBimaps:\fR]\fIhost\fR
|
||||
Specify the DNS name or IP address of the IMAP server. If \fIhost\fR is
|
||||
prefixed with \fBimaps:\fR the connection is assumed to be an SSL connection
|
||||
to port 993.
|
||||
Note that modern servers support SSL on the default port 143 via the
|
||||
STARTTLS extension, which will be used automatically by default.
|
||||
\fBHost\fR \fIhost\fR
|
||||
Specify the DNS name or IP address of the IMAP server.
|
||||
..
|
||||
.TP
|
||||
\fBPort\fR \fIport\fR
|
||||
Specify the TCP port number of the IMAP server. (Default: 143 for imap,
|
||||
993 for imaps)
|
||||
Specify the TCP port number of the IMAP server. (Default: 143 for IMAP,
|
||||
993 for IMAPS)
|
||||
..
|
||||
.TP
|
||||
\fBUser\fR \fIusername\fR
|
||||
|
@ -245,6 +241,15 @@ If set to \fIyes\fR, \fBmbsync\fR will abort the connection if no CRAM-MD5
|
|||
authentication is possible. (Default: \fIno\fR)
|
||||
..
|
||||
.TP
|
||||
\fBUseIMAPS\fR \fIyes\fR|\fIno\fR
|
||||
If set to \fIyes\fR, the default for \fBPort\fR is changed to 993 and
|
||||
\fBmbsync\fR will start SSL negotiation immediately after establishing
|
||||
the connection to the server.
|
||||
.br
|
||||
Note that modern servers support SSL on the regular IMAP port 143 via the
|
||||
STARTTLS extension, which will be used automatically by default.
|
||||
..
|
||||
.TP
|
||||
\fBRequireSSL\fR \fIyes\fR|\fIno\fR
|
||||
\fBmbsync\fR will abort the connection if a TLS/SSL session cannot be
|
||||
established with the IMAP server. (Default: \fIyes\fR)
|
||||
|
@ -257,12 +262,14 @@ This option is \fImandatory\fR if SSL is used. See \fBSSL CERTIFICATES\fR below.
|
|||
.TP
|
||||
\fBUseSSLv2\fR \fIyes\fR|\fIno\fR
|
||||
Use SSLv2 for communication with the IMAP server over SSL?
|
||||
(Default: \fIyes\fR if an imaps \fBHost\fR is used, otherwise \fIno\fR)
|
||||
.br
|
||||
Note that this option is deprecated for security reasons.
|
||||
(Default: \fIno\fR)
|
||||
..
|
||||
.TP
|
||||
\fBUseSSLv3\fR \fIyes\fR|\fIno\fR
|
||||
Use SSLv3 for communication with the IMAP server over SSL?
|
||||
(Default: \fIyes\fR if an imaps \fBHost\fR is used, otherwise \fIno\fR)
|
||||
(Default: \fIno\fR)
|
||||
..
|
||||
.TP
|
||||
\fBUseTLSv1\fR \fIyes\fR|\fIno\fR
|
||||
|
|
|
@ -96,7 +96,7 @@ convert( const char *box, int altmap )
|
|||
fputs( "Error: db_create() failed\n", stderr );
|
||||
goto tbork;
|
||||
}
|
||||
if ((ret = db->open( db, 0, dbpath, 0, DB_HASH, DB_CREATE, 0 ))) {
|
||||
if ((ret = (db->open)( db, 0, dbpath, 0, DB_HASH, DB_CREATE, 0 ))) {
|
||||
db->err( db, ret, "Error: db->open(%s)", dbpath );
|
||||
dbork:
|
||||
db->close( db, 0 );
|
||||
|
@ -154,7 +154,7 @@ convert( const char *box, int altmap )
|
|||
if (u)
|
||||
ml = u - e->d_name;
|
||||
else
|
||||
ru = "", ml = INT_MAX;
|
||||
ru = "", ml = sizeof(buf);
|
||||
if (altmap) {
|
||||
if (!p)
|
||||
continue;
|
||||
|
|
56
src/sync.c
56
src/sync.c
|
@ -251,7 +251,7 @@ sync_old( int tops, store_t *sctx, store_t *tctx, store_conf_t *tconf, FILE *jfp
|
|||
{
|
||||
driver_t *tdriver = tctx->conf->driver, *sdriver = sctx->conf->driver;
|
||||
int uid, tuid, unex;
|
||||
unsigned char sflags, aflags, dflags, rflags;
|
||||
unsigned char sflags, aflags, dflags;
|
||||
msg_data_t msgdata;
|
||||
|
||||
/* excludes (push) c.3) d.2) d.3) d.4) / (pull) b.3) d.7) d.8) d.9) */
|
||||
|
@ -301,6 +301,13 @@ sync_old( int tops, store_t *sctx, store_t *tctx, store_conf_t *tconf, FILE *jfp
|
|||
case DRV_OK:
|
||||
smsg->flags = msgdata.flags;
|
||||
switch (tdriver->store_msg( tctx, &msgdata, &uid )) {
|
||||
case DRV_MSG_BAD:
|
||||
warn( pull ?
|
||||
"Warning: Slave refuses to store message %d from master.\n" :
|
||||
"Warning: Master refuses to store message %d from slave.\n",
|
||||
smsg->uid );
|
||||
smsg->status |= M_NOT_SYNCED;
|
||||
break;
|
||||
case DRV_STORE_BAD: return pull ? SYNC_SLAVE_BAD : SYNC_MASTER_BAD;
|
||||
default: return SYNC_FAIL;
|
||||
case DRV_OK:
|
||||
|
@ -332,20 +339,18 @@ sync_old( int tops, store_t *sctx, store_t *tctx, store_conf_t *tconf, FILE *jfp
|
|||
unex = 0;
|
||||
if (srec->status & S_EXPIRED) {
|
||||
if (!pull) {
|
||||
if (sflags & F_DELETED) {
|
||||
if (!(sflags & F_FLAGGED))
|
||||
aflags &= ~F_DELETED;
|
||||
} else
|
||||
unex = 1;
|
||||
if ((aflags & ~F_DELETED) || dflags)
|
||||
info( "Info: Flags of expired message changed in (%d,%d)\n", srec->muid, srec->suid );
|
||||
return SYNC_OK;
|
||||
} else {
|
||||
if ((sflags & F_FLAGGED) && !(sflags & F_DELETED)) {
|
||||
unex = 1;
|
||||
dflags |= F_DELETED;
|
||||
}
|
||||
} else
|
||||
return SYNC_OK;
|
||||
}
|
||||
}
|
||||
rflags = (*nflags | aflags) & ~dflags;
|
||||
if ((tops & OP_EXPUNGE) && (rflags & F_DELETED) &&
|
||||
if ((tops & OP_EXPUNGE) && (sflags & F_DELETED) &&
|
||||
(!tctx->conf->trash || tctx->conf->trash_only_new))
|
||||
{
|
||||
aflags &= F_DELETED;
|
||||
|
@ -356,7 +361,7 @@ sync_old( int tops, store_t *sctx, store_t *tctx, store_conf_t *tconf, FILE *jfp
|
|||
case DRV_BOX_BAD: return SYNC_FAIL;
|
||||
default: /* ok */ break;
|
||||
case DRV_OK:
|
||||
*nflags = rflags;
|
||||
*nflags = (*nflags | aflags) & ~dflags;
|
||||
if (unex) {
|
||||
debug( "unexpiring pair(%d,%d)\n", srec->muid, srec->suid );
|
||||
/* log last, so deletion can't be misinterpreted! */
|
||||
|
@ -401,6 +406,13 @@ sync_new( int tops, store_t *sctx, store_t *tctx, store_conf_t *tconf, FILE *jfp
|
|||
}
|
||||
msg->flags = msgdata.flags;
|
||||
switch (tdriver->store_msg( tctx, &msgdata, &uid )) {
|
||||
case DRV_MSG_BAD:
|
||||
warn( pull ?
|
||||
"Warning: Slave refuses to store message %d from master.\n" :
|
||||
"Warning: Master refuses to store message %d from slave.\n",
|
||||
msg->uid );
|
||||
msg->status |= M_NOT_SYNCED;
|
||||
continue;
|
||||
case DRV_STORE_BAD: return pull ? SYNC_SLAVE_BAD : SYNC_MASTER_BAD;
|
||||
default: return SYNC_FAIL;
|
||||
case DRV_OK: break;
|
||||
|
@ -476,7 +488,7 @@ sync_boxes( store_t *mctx, const char *mname,
|
|||
|
||||
nmmsg = nsmsg = 0;
|
||||
|
||||
mctx->uidvalidity = sctx->uidvalidity = 0;
|
||||
mctx->uidvalidity = sctx->uidvalidity = -1;
|
||||
mopts = sopts = 0;
|
||||
makeopts( chan->sops, chan->slave, &sopts, chan->master, &mopts );
|
||||
makeopts( chan->mops, chan->master, &mopts, chan->slave, &sopts );
|
||||
|
@ -512,7 +524,8 @@ sync_boxes( store_t *mctx, const char *mname,
|
|||
nfasprintf( &jname, "%s.journal", dname );
|
||||
nfasprintf( &nname, "%s.new", dname );
|
||||
nfasprintf( &lname, "%s.lock", dname );
|
||||
muidval = suidval = smaxxuid = mmaxuid = smaxuid = 0;
|
||||
muidval = suidval = -1;
|
||||
smaxxuid = mmaxuid = smaxuid = 0;
|
||||
memset( &lck, 0, sizeof(lck) );
|
||||
#if SEEK_SET != 0
|
||||
lck.l_whence = SEEK_SET;
|
||||
|
@ -699,7 +712,7 @@ sync_boxes( store_t *mctx, const char *mname,
|
|||
} else
|
||||
maxwuid = 0;
|
||||
info( "Selecting slave %s... ", sname );
|
||||
debug( "selecting slave [1,%d]\n", maxwuid );
|
||||
debug( maxwuid == INT_MAX ? "selecting slave [1,inf]\n" : "selecting slave [1,%d]\n", maxwuid );
|
||||
switch (sdriver->select( sctx, (sctx->opts & OPEN_OLD) ? 1 : smaxuid + 1, maxwuid, 0, 0 )) {
|
||||
case DRV_STORE_BAD: ret = SYNC_SLAVE_BAD; goto bail;
|
||||
case DRV_BOX_BAD: ret = SYNC_FAIL; goto bail;
|
||||
|
@ -707,16 +720,17 @@ sync_boxes( store_t *mctx, const char *mname,
|
|||
info( "%d messages, %d recent\n", sctx->count, sctx->recent );
|
||||
dump_box( sctx );
|
||||
|
||||
if (suidval && suidval != sctx->uidvalidity) {
|
||||
if (suidval >= 0 && suidval != sctx->uidvalidity) {
|
||||
fprintf( stderr, "Error: UIDVALIDITY of slave changed\n" );
|
||||
ret = SYNC_FAIL;
|
||||
goto bail;
|
||||
}
|
||||
|
||||
s = strrchr( dname, '/' );
|
||||
*s = 0;
|
||||
mkdir( dname, 0700 );
|
||||
*s = '/';
|
||||
if ((s = strrchr( dname, '/' ))) {
|
||||
*s = 0;
|
||||
mkdir( dname, 0700 );
|
||||
*s = '/';
|
||||
}
|
||||
if (lfd < 0) {
|
||||
if ((lfd = open( lname, O_WRONLY|O_CREAT, 0666 )) < 0)
|
||||
goto lferr;
|
||||
|
@ -802,7 +816,7 @@ sync_boxes( store_t *mctx, const char *mname,
|
|||
} else
|
||||
maxwuid = 0;
|
||||
info( "Selecting master %s... ", mname );
|
||||
debug( "selecting master [%d,%d]\n", minwuid, maxwuid );
|
||||
debug( maxwuid == INT_MAX ? "selecting master [%d,inf]\n" : "selecting master [%d,%d]\n", minwuid, maxwuid );
|
||||
switch (mdriver->select( mctx, minwuid, maxwuid, mexcs, nmexcs )) {
|
||||
case DRV_STORE_BAD: ret = SYNC_MASTER_BAD; goto finish;
|
||||
case DRV_BOX_BAD: ret = SYNC_FAIL; goto finish;
|
||||
|
@ -810,13 +824,13 @@ sync_boxes( store_t *mctx, const char *mname,
|
|||
info( "%d messages, %d recent\n", mctx->count, mctx->recent );
|
||||
dump_box( mctx );
|
||||
|
||||
if (muidval && muidval != mctx->uidvalidity) {
|
||||
if (muidval >= 0 && muidval != mctx->uidvalidity) {
|
||||
fprintf( stderr, "Error: UIDVALIDITY of master changed\n" );
|
||||
ret = SYNC_FAIL;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (!muidval || !suidval) {
|
||||
if (muidval < 0 || suidval < 0) {
|
||||
muidval = mctx->uidvalidity;
|
||||
suidval = sctx->uidvalidity;
|
||||
Fprintf( jfp, "| %d %d\n", muidval, suidval );
|
||||
|
|
|
@ -41,6 +41,7 @@ debug( const char *msg, ... )
|
|||
va_start( va, msg );
|
||||
vprintf( msg, va );
|
||||
va_end( va );
|
||||
fflush( stdout );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue