The Big Rewrite. too many change to list them all.
as opposed to earlier threats, BerkDB was not entirely dropped; i suppose the isync 0.7 -> 0.8 change had a reason, so i added an alternative UID storage scheme. note that BDB 4.0 is not sufficient, as the db->open function changed in an incompatible way ... i updated the debian packaging except for a changelog entry. note that i removed the upgrade blurb, as upstream now has a smooth upgrade path down to at least isync 0.4.
This commit is contained in:
parent
8d1b26aebe
commit
130664b622
|
@ -7,12 +7,16 @@ build-stamp
|
||||||
config.h
|
config.h
|
||||||
config.h.in
|
config.h.in
|
||||||
config.cache
|
config.cache
|
||||||
|
config.guess
|
||||||
config.log
|
config.log
|
||||||
config.status
|
config.status
|
||||||
|
config.sub
|
||||||
configure
|
configure
|
||||||
configure.lineno
|
configure.lineno
|
||||||
configure-stamp
|
configure-stamp
|
||||||
isync.spec
|
isync.spec
|
||||||
isync-*.tar.gz
|
isync-*.tar.gz
|
||||||
patch-stamp
|
patch-stamp
|
||||||
|
stamp-h
|
||||||
|
stamp-h.in
|
||||||
stamp-h1
|
stamp-h1
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
SUBDIRS = src
|
SUBDIRS = src
|
||||||
man_MANS = isync.1
|
bin_SCRIPTS = get-cert
|
||||||
EXTRA_DIST = debian isyncrc.sample isync.spec $(man_MANS)
|
EXTRA_DIST = debian isync.spec $(bin_SCRIPTS)
|
||||||
|
|
||||||
log:
|
log:
|
||||||
@perl -p -e "s/^(\\S+)\\s+(\\S.+\\S)\\s+(\\S+)\\s*\$$/\$$1:'\$$2 <\$$3>'\\n/" < ../CVSROOT/accounts > .usermap
|
@perl -p -e "s/^(\\S+)\\s+(\\S.+\\S)\\s+(\\S+)\\s*\$$/\$$1:'\$$2 <\$$3>'\\n/" < ../CVSROOT/accounts > .usermap
|
||||||
|
@ -16,6 +16,9 @@ deb-clean:
|
||||||
|
|
||||||
distdir distclean: 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
|
||||||
|
|
||||||
rpm:
|
rpm:
|
||||||
make dist
|
make dist
|
||||||
cp $(PACKAGE)-$(VERSION).tar.gz /usr/src/rpm/SOURCES
|
cp $(PACKAGE)-$(VERSION).tar.gz /usr/src/rpm/SOURCES
|
||||||
|
|
24
NEWS
24
NEWS
|
@ -1,3 +1,27 @@
|
||||||
|
[1.0.0]
|
||||||
|
|
||||||
|
Essentially a rewrite. Synchronization state storage concept, configuration
|
||||||
|
and command line changed entirely.
|
||||||
|
But you needn't to worry about the upgrade, as a fully automated migration
|
||||||
|
path is provided, even for users of isync 0.7 and below.
|
||||||
|
Still, you should re-read the manual to be able to take full advantage of the
|
||||||
|
new features:
|
||||||
|
|
||||||
|
The supported mailbox types can be freely paired.
|
||||||
|
A possible application of this is using a local IMAP server to access
|
||||||
|
mailboxes that are not natively supported yet.
|
||||||
|
|
||||||
|
Message deletions (expunges) are now propagated both ways, so there is no need
|
||||||
|
for using mutt with maildir_trash any more.
|
||||||
|
|
||||||
|
Additional trash options added.
|
||||||
|
|
||||||
|
`OneToOne' replaced by something more flexible.
|
||||||
|
|
||||||
|
Partial support for IMAP pipelining (streaming, parallelization) added.
|
||||||
|
Makes flag change propagation much faster - this affects every message that
|
||||||
|
becomes Seen/Read.
|
||||||
|
|
||||||
[0.9]
|
[0.9]
|
||||||
|
|
||||||
Added Tunnel directive to allow the user to specify a shell command to run
|
Added Tunnel directive to allow the user to specify a shell command to run
|
||||||
|
|
69
README
69
README
|
@ -4,52 +4,69 @@
|
||||||
| \__ \ |_| | | | | (__
|
| \__ \ |_| | | | | (__
|
||||||
|_|___/\__, |_| |_|\___|
|
|_|___/\__, |_| |_|\___|
|
||||||
|___/
|
|___/
|
||||||
isync - IMAP4 to maildir mailbox synchronization program
|
isync/mbsync - free (GPL) mailbox synchronization program
|
||||||
http://isync.sf.net/
|
http://isync.sf.net/
|
||||||
|
|
||||||
Author: Michael Elkins <me@mutt.org>
|
See AUTHORS for contact information.
|
||||||
Current maintainer: Oswald Buddenhagen <ossi@users.sf.net>
|
|
||||||
|
|
||||||
``isync'' is a command line application which synchronizes a local
|
``mbsync'' is a command line application which synchronizes mailboxes;
|
||||||
maildir-style mailbox with a remote IMAP4 mailbox, suitable for use in
|
currently Maildir and IMAP4 mailboxes are supported. New messages, message
|
||||||
IMAP-disconnected mode. Multiple copies of the remote IMAP4 mailbox can be
|
deletions and flag changes can be propagated both ways.
|
||||||
maintained, and all flags are synchronized.
|
``mbsync'' is suitable for use in IMAP-disconnected mode.
|
||||||
|
|
||||||
* Features:
|
Synchronization is based on unique message identifiers (UIDs), so no
|
||||||
|
identification conflicts can occur (as opposed to some other mail
|
||||||
|
synchronizers).
|
||||||
|
Synchronization state is kept in one local text file per mailbox pair;
|
||||||
|
multiple replicas of a mailbox can be maintained.
|
||||||
|
|
||||||
* Fast mode for fetching new mail only
|
isync is the project name, while mbsync is the current executable name; this
|
||||||
* Supports imaps: (port 993) TLS/SSL connections
|
change was necessary because of massive changes in the user interface. An
|
||||||
* Supports STARTTLS (RFC2595) for confidentiality
|
isync executable still exists; it is a compatibility wrapper around mbsync.
|
||||||
* Supports NAMESPACE (RFC2342)
|
|
||||||
* Supports CRAM-MD5 (RFC2095) for authentication
|
* Features
|
||||||
|
|
||||||
|
* Fine-grained selection of synchronization operations to perform
|
||||||
|
* Synchronizes single mailboxes or entire mailbox collections
|
||||||
|
* Partial mirrors possible: keep only the latest messages locally
|
||||||
|
* Trash functionality: backup messages before removing them
|
||||||
|
* IMAP features:
|
||||||
|
* Supports TLS/SSL via imaps: (port 993) and STARTTLS (RFC2595)
|
||||||
|
* Supports CRAM-MD5 (RFC2195) for authentication
|
||||||
|
* Supports NAMESPACE (RFC2342) for simplified configuration
|
||||||
|
* Pipelining for maximum speed (currently only partially implemented)
|
||||||
|
|
||||||
* Compatibility
|
* Compatibility
|
||||||
|
|
||||||
``isync'' has been tested with the following IMAP servers:
|
isync should work fairly well with any IMAP4 compliant server;
|
||||||
|
particularily efficient with those that support the UIDPLUS and LITERAL+
|
||||||
|
extensions.
|
||||||
|
|
||||||
* Microsoft Exchange 2000 IMAP4rev1 server version 6.0.4417.0
|
Courier 1.4.3 is known to be buggy, version 1.7.3 works fine.
|
||||||
* Courier-IMAP 1.2.3
|
|
||||||
* WU-IMAP 2000
|
c-client (UW-IMAP, Pine) is mostly fine, but tends to change UIDVALIDITY
|
||||||
* Domino IMAP4 Server Release 5.0.8
|
pretty often when used with unix/mbox mailboxes, making isync refuse
|
||||||
|
synchronization.
|
||||||
|
The "cure" is to simply copy the new UIDVALIDITY from the affected
|
||||||
|
mailbox to mbsync's state file. This is a Bad Hack (TM), but it works -
|
||||||
|
use at your own risk (if the UIDVALIDITY change was genuine, this will
|
||||||
|
delete all messages in the affected mailbox - not that this ever
|
||||||
|
happened to me).
|
||||||
|
|
||||||
* Platforms
|
* Platforms
|
||||||
|
|
||||||
``isync'' has successfully been compiled on:
|
At some point, ``isync'' has successfully run on:
|
||||||
|
Linux, Solaris 2.7, OpenBSD 2.8, FreeBSD 4.3, Cygwin
|
||||||
* Linux
|
|
||||||
* Solaris 2.7
|
|
||||||
* OpenBSD 2.8
|
|
||||||
* FreeBSD 4.3
|
|
||||||
|
|
||||||
* Requirements
|
* Requirements
|
||||||
|
|
||||||
OpenSSL for TLS/SSL support (optional)
|
OpenSSL for TLS/SSL support (optional)
|
||||||
|
|
||||||
* INSTALLING
|
* Installation
|
||||||
|
|
||||||
./configure
|
./configure
|
||||||
make install
|
make install
|
||||||
|
|
||||||
* HELP
|
* Help
|
||||||
|
|
||||||
Please see the man page for complete documentation.
|
Please see the man page for complete documentation.
|
||||||
|
|
62
TODO
62
TODO
|
@ -1,39 +1,51 @@
|
||||||
change of UIDVALIDITY shouldn't be considered fatal for the imap connection.
|
make SSL certificate validation more automatic.
|
||||||
maybe the error handling needs to be cleaned up in general.
|
|
||||||
|
|
||||||
don't require maildir_trash. currently MaxMessages gets into the way of
|
add asynchronous operation to remote mailbox drivers. this is actually
|
||||||
simply removing it; that is fixable with some shuffling, though.
|
what prevents us from simply using c-client and thus becoming mailsync.
|
||||||
|
|
||||||
refactor mailbox support. create proper mailbox drivers; handle imap and
|
handle custom flags (keywords).
|
||||||
maildir (and anything else) symmetrically; decouple UID->message mapping
|
|
||||||
from sync database - should use the same UID storing schemes as c-client
|
|
||||||
(pine, uw-imap) does, at least optionally, i think.
|
|
||||||
|
|
||||||
add asynchrounous operation to remote mailbox drivers. this is actually
|
fix maildir_{open_store,list} to handle partial names (last char not slash).
|
||||||
what prevents us from simply using c-client for the previous point and
|
|
||||||
thus simply becoming mailsync.
|
|
||||||
|
|
||||||
store message flags in sync database, so _un_setting them will be properly
|
add a way to automatically create and sync subfolders.
|
||||||
synced as well.
|
|
||||||
|
|
||||||
handle custom imap flags. currently, isync just fails horribly if it
|
could store TUID even when UIDPLUS is supported. would avoid duplicated
|
||||||
encounters some.
|
messages after abort before new UID arrives.
|
||||||
|
|
||||||
add options for fine-grained control of syncing operations (--new, --delete &
|
decouple TUID search from append. that's a prerequisite for usable
|
||||||
--flags) and direction (--push & --pull).
|
MULTIAPPEND, and is generally good for async. should be way faster, too,
|
||||||
|
as it saves repeated mailbox rescans with single-file formats.
|
||||||
|
|
||||||
add support for syncing with other: and shared: via NAMESPACE
|
use MULTIAPPEND and FETCH with multiple messages.
|
||||||
|
|
||||||
isync ignores asynchronous notifications (untagged responses), so mail
|
create dummies describing MIME structure of messages bigger than MaxSize.
|
||||||
arriving during a fetch will not be fetched in the current run any more.
|
flagging the dummy would fetch the real message. possibly remove --renew.
|
||||||
|
|
||||||
add a way to automatically create and sync IMAP subfolders.
|
don't SELECT boxes unless really needed; in particular not for appending,
|
||||||
|
and in write-only mode not before changes are made.
|
||||||
|
|
||||||
make the command line take precedence over the config file.
|
possibly request message attributes on a per-message basis from the drivers.
|
||||||
|
considerations:
|
||||||
|
- record non-existing UID ranges in the sync database, so IMAP FETCHes needn't
|
||||||
|
to exclude anyway non-existing messages explicitly.
|
||||||
|
- when detect unborn pairs and orphaned messages being gone? implied by expunge:
|
||||||
|
with trashing, by local driver, or of messages we deleted in this run. the
|
||||||
|
remaining cases could be handled by automatic periodical cleanup passes, an
|
||||||
|
explicit --cleanup action, or be implied by one of the other actions.
|
||||||
|
- the benefit of this is questionable, as fine-grained requests will result
|
||||||
|
in sending huge amounts of data, and upstream is often way slower than
|
||||||
|
downstream.
|
||||||
|
|
||||||
possibly timestamp mails with remote arrival date.
|
maildir: possibly timestamp mails with remote arrival date.
|
||||||
|
|
||||||
possibly recover from UIDVALIDITY change by resyncing according to message
|
maybe throw out the ctx->recent stuff - it's used only for one info message.
|
||||||
IDs - this is a pretty common condition with uw-imap.
|
|
||||||
|
|
||||||
possibly use ^[[1m to highlight error messages.
|
possibly use ^[[1m to highlight error messages.
|
||||||
|
|
||||||
|
consider alternative trash implementation: trash only messages we delete,
|
||||||
|
and trash before marking them deleted in the mailbox. downside: all other
|
||||||
|
programs have to do the same. and what if the deleted flag is unset?
|
||||||
|
|
||||||
|
items out of scope of purely UID based approach:
|
||||||
|
- detect message moves between folders
|
||||||
|
- recovering from UIDVALIDITY change (uw-imap does this a lot)
|
||||||
|
|
43
configure.in
43
configure.in
|
@ -1,22 +1,23 @@
|
||||||
AC_INIT(src/isync.h)
|
AC_INIT(src/isync.h)
|
||||||
AM_CONFIG_HEADER(config.h)
|
AM_CONFIG_HEADER(config.h)
|
||||||
AM_INIT_AUTOMAKE(isync, 0.9.2)
|
AM_INIT_AUTOMAKE(isync, 1.0.0alpha)
|
||||||
|
|
||||||
AM_MAINTAINER_MODE
|
AM_MAINTAINER_MODE
|
||||||
|
|
||||||
AM_PROG_CC_STDC
|
AM_PROG_CC_STDC
|
||||||
if test "$GCC" = yes; then
|
if test "$GCC" = yes; then
|
||||||
CFLAGS="$CFLAGS -pipe -W -Wall -Wshadow -Wmissing-prototypes"
|
CFLAGS="$CFLAGS -pipe -W -Wall -Wshadow -Wstrict-prototypes"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
AC_CHECK_FUNCS(getopt_long)
|
AC_CHECK_FUNCS(vasprintf)
|
||||||
|
|
||||||
AC_CHECK_LIB(socket, socket)
|
AC_CHECK_LIB(socket, socket, [SOCK_LIBS="-lsocket"])
|
||||||
AC_CHECK_LIB(nsl, inet_ntoa)
|
AC_CHECK_LIB(nsl, inet_ntoa, [SOCK_LIBS="$SOCK_LIBS -lnsl"])
|
||||||
|
AC_SUBST(SOCK_LIBS)
|
||||||
|
|
||||||
ssl=false
|
ssl=false
|
||||||
AC_ARG_WITH(ssl,
|
AC_ARG_WITH(ssl,
|
||||||
[ --with-ssl=DIR yes/no/OpenSSL installation root [detect]],
|
AS_HELP_STRING([--with-ssl=DIR], [yes/no/OpenSSL installation root [detect]]),
|
||||||
[ob_cv_with_ssl=$withval])
|
[ob_cv_with_ssl=$withval])
|
||||||
if test "x$ob_cv_with_ssl" != xno; then
|
if test "x$ob_cv_with_ssl" != xno; then
|
||||||
if test -d "$ob_cv_with_ssl/lib"; then
|
if test -d "$ob_cv_with_ssl/lib"; then
|
||||||
|
@ -25,7 +26,7 @@ if test "x$ob_cv_with_ssl" != xno; then
|
||||||
fi
|
fi
|
||||||
AC_CHECK_LIB(crypto, ERR_error_string, [cryptolib=" -lcrypto"])
|
AC_CHECK_LIB(crypto, ERR_error_string, [cryptolib=" -lcrypto"])
|
||||||
AC_CHECK_LIB(ssl, SSL_library_init, [
|
AC_CHECK_LIB(ssl, SSL_library_init, [
|
||||||
LIBS="-lssl$cryptolib $LIBS"
|
SSL_LIBS="-lssl$cryptolib"
|
||||||
AC_DEFINE(HAVE_LIBSSL, 1, [Define if you want SSL support])
|
AC_DEFINE(HAVE_LIBSSL, 1, [Define if you want SSL support])
|
||||||
ssl=true
|
ssl=true
|
||||||
],[
|
],[
|
||||||
|
@ -34,19 +35,29 @@ if test "x$ob_cv_with_ssl" != xno; then
|
||||||
fi
|
fi
|
||||||
])
|
])
|
||||||
fi
|
fi
|
||||||
|
AC_SUBST(SSL_LIBS)
|
||||||
|
|
||||||
AC_CACHE_CHECK(for db_create in -ldb, ac_cv_db_db_create,
|
AC_CACHE_CHECK([for Berkley DB 4.2], ac_cv_berkdb4,
|
||||||
[ac_cv_db_dbcreate=no
|
[ac_cv_berkdb4=no
|
||||||
AC_TRY_LINK([#include <db.h>],
|
AC_TRY_LINK([#include <db.h>],
|
||||||
[db_create();],[ac_cv_db_db_create=yes])])
|
[DB *db;
|
||||||
if test $ac_cv_db_db_create=yes; then
|
db->truncate(db, 0, 0, 0);
|
||||||
LIBS="$LIBS -ldb"
|
db->open(db, 0, "foo", "foo", DB_HASH, DB_CREATE, 0)],
|
||||||
else
|
[ac_cv_berkdb4=yes])])
|
||||||
AC_MSG_ERROR([Berkley DB not found.
|
if test "x$ac_cv_berkdb4" = xno; then
|
||||||
You must install libdb including the respective development files/headers.])
|
AC_MSG_ERROR([Berkley DB 4.2 not found.
|
||||||
|
You must install libdb4.2 including the respective development files/headers.])
|
||||||
fi
|
fi
|
||||||
|
|
||||||
AC_OUTPUT(Makefile src/Makefile isync.spec)
|
AC_ARG_ENABLE(compat,
|
||||||
|
AS_HELP_STRING([--disable-compat], [don't include isync compatibility wrapper [no]]),
|
||||||
|
[ob_cv_enable_compat=$enableval])
|
||||||
|
if test "x$ob_cv_enable_compat" != xno; then
|
||||||
|
AC_CHECK_FUNCS(getopt_long)
|
||||||
|
fi
|
||||||
|
AM_CONDITIONAL(with_compat, test "x$ob_cv_enable_compat" != xno)
|
||||||
|
|
||||||
|
AC_OUTPUT(Makefile src/Makefile src/compat/Makefile isync.spec)
|
||||||
|
|
||||||
if $ssl; then
|
if $ssl; then
|
||||||
AC_MSG_RESULT([
|
AC_MSG_RESULT([
|
||||||
|
|
16
debian/NEWS
vendored
16
debian/NEWS
vendored
|
@ -1,16 +0,0 @@
|
||||||
isync (0.8-1) unstable; urgency=low
|
|
||||||
|
|
||||||
IMPORTANT upgrade note:
|
|
||||||
|
|
||||||
This version includes a change to the way the UID for each message is
|
|
||||||
stored in the local mailbox. You need to remove all the messages in your
|
|
||||||
local folder if you were previously using another version of isync or else
|
|
||||||
you will end up with duplicate messages on your IMAP server.
|
|
||||||
|
|
||||||
A suggested upgrade procedure is to use isync version 0.7 to synchronize
|
|
||||||
any local changes in isync-managed mailboxes with your IMAP server, and
|
|
||||||
then remove the contents of the local mailboxes, before upgrading to this
|
|
||||||
version. Then run isync again to pull down the mail again. You must do
|
|
||||||
this manually, the Debian package will not do this for you.
|
|
||||||
|
|
||||||
-- Joey Hess <joeyh@debian.org> Tue, 29 Oct 2002 13:50:40 -0500
|
|
22
debian/README.Debian
vendored
22
debian/README.Debian
vendored
|
@ -1,22 +0,0 @@
|
||||||
A note from isync's web site:
|
|
||||||
|
|
||||||
To use this command effectively, you need a mail client that sets the T
|
|
||||||
(trashed) flag when it deletes a message from a maildir mailbox, instead of
|
|
||||||
just removing it altogether. Currently, only Mutt 1.3.27 supports this. Without
|
|
||||||
such a client, isync will refetch the locally deleted messages from the server
|
|
||||||
since they will never get expunged. Be sure to put
|
|
||||||
|
|
||||||
set maildir_trash
|
|
||||||
|
|
||||||
in your ~/.muttrc when using Mutt.
|
|
||||||
|
|
||||||
isync can be integrated into Mutt fairly easily with a few hooks:
|
|
||||||
|
|
||||||
folder-hook ~A bind index $ <sync-mailbox>
|
|
||||||
folder-hook +maildir 'macro index $ "<sync-mailbox>!isync -e maildir\n"'
|
|
||||||
|
|
||||||
where maildir is the name of the local mailbox (or its alias). This works well
|
|
||||||
so long as you are not modifying the IMAP mailbox outside of Mutt. However, if
|
|
||||||
you are using another mail program simultaneously Mutt will have the wrong idea
|
|
||||||
of the local mailbox flags and messages will start disappearing from its index
|
|
||||||
display (don't worry, they are still on disk).
|
|
8
debian/config
vendored
8
debian/config
vendored
|
@ -1,8 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
set -e
|
|
||||||
. /usr/share/debconf/confmodule
|
|
||||||
if [ "$1" = "configure" -a ! -z "$2" ] && \
|
|
||||||
dpkg --compare-versions "$2" lt 0.8; then
|
|
||||||
db_input critical isync/upgrade_0.8 || true
|
|
||||||
db_go || true
|
|
||||||
fi
|
|
27
debian/control
vendored
27
debian/control
vendored
|
@ -4,21 +4,26 @@ Priority: optional
|
||||||
Maintainer: Nicolas Boullis <nboullis@debian.org>
|
Maintainer: Nicolas Boullis <nboullis@debian.org>
|
||||||
Uploaders: Nicolas Boullis <nboullis@debian.org>, Theodore Y. Ts'o <tytso@mit.edu>
|
Uploaders: Nicolas Boullis <nboullis@debian.org>, Theodore Y. Ts'o <tytso@mit.edu>
|
||||||
Standards-Version: 3.6.1
|
Standards-Version: 3.6.1
|
||||||
Build-Depends: libssl-dev, debhelper (>= 4.1.16), dpkg-dev (>= 1.9.0), libdb4.0-dev, dpatch
|
Build-Depends: libssl-dev, debhelper (>= 4.1.16), dpkg-dev (>= 1.9.0), libdb4.2-dev, dpatch
|
||||||
|
|
||||||
Package: isync
|
Package: isync
|
||||||
Architecture: any
|
Architecture: any
|
||||||
Depends: ${shlibs:Depends}, ${misc:Depends}
|
Depends: ${shlibs:Depends}, ${misc:Depends}
|
||||||
Suggests: mutt
|
Suggests: mutt
|
||||||
Description: Synchronize a local maildir with a remote IMAP4 mailbox
|
Description: Synchronize Maildir and IMAP4 mailboxes
|
||||||
A command line application which synchronizes a local maildir-style
|
A command line application which synchronizes mailboxes; currently
|
||||||
mailbox with a remote IMAP4 mailbox, suitable for use in disconnected
|
Maildir and IMAP4 mailboxes are supported.
|
||||||
mode. Multiple copies of the remote IMAP4 mailbox can be maintained,
|
New messages, message deletions and flag changes can be propagated both ways.
|
||||||
and all flags and messages are synchronized.
|
It is useful for working in disconnected mode, such as on a laptop or with a
|
||||||
|
non-permanent internet collection (dIMAP).
|
||||||
.
|
.
|
||||||
Features:
|
Features:
|
||||||
* Fast mode for fetching new mail only
|
* Fine-grained selection of synchronization operations to perform
|
||||||
* Supports imaps: (port 993) TLS/SSL connections
|
* Synchronizes single mailboxes or entire mailbox collections
|
||||||
* Supports STARTTLS (RFC2595) for confidentiality
|
* Partial mirrors possible: keep only the latest messages locally
|
||||||
* Supports NAMESPACE (RFC2342)
|
* Trash functionality: backup messages before removing them
|
||||||
* Supports CRAM-MD5 (RFC2095) for authentication
|
* IMAP features:
|
||||||
|
* Supports TLS/SSL via imaps: (port 993) and STARTTLS (RFC2595)
|
||||||
|
* Supports CRAM-MD5 (RFC2195) for authentication
|
||||||
|
* Supports NAMESPACE (RFC2342) for simplified configuration
|
||||||
|
* Pipelining for maximum speed (currently only partially implemented)
|
||||||
|
|
1
debian/patches/00list
vendored
1
debian/patches/00list
vendored
|
@ -1 +0,0 @@
|
||||||
20-cleanup
|
|
146
debian/patches/20-cleanup.dpatch
vendored
146
debian/patches/20-cleanup.dpatch
vendored
|
@ -1,146 +0,0 @@
|
||||||
#! /bin/sh -e
|
|
||||||
## 20-cleanup.dpatch by Theodore Ts'o <tytso@mit.edu>
|
|
||||||
##
|
|
||||||
## DP: Make sure the database store and the imap database is closed
|
|
||||||
## DP: if isync is aborted.
|
|
||||||
|
|
||||||
[ -f debian/patches/00patch-opts ] && . debian/patches/00patch-opts
|
|
||||||
patch_opts="${patch_opts:--f --no-backup-if-mismatch}"
|
|
||||||
|
|
||||||
if [ $# -ne 1 ]; then
|
|
||||||
echo >&2 "`basename $0`: script expects -patch|-unpatch as argument"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
case "$1" in
|
|
||||||
-patch) patch $patch_opts -p1 < $0;;
|
|
||||||
-unpatch) patch $patch_opts -p1 -R < $0;;
|
|
||||||
*)
|
|
||||||
echo >&2 "`basename $0`: script expects -patch|-unpatch as argument"
|
|
||||||
exit 1;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
exit 0
|
|
||||||
@DPATCH@
|
|
||||||
|
|
||||||
Problem description:
|
|
||||||
|
|
||||||
>> If isync dies in the middle of synchronization, or the network
|
|
||||||
>> connection breaks while it is synchronizing a mailbox, new messages
|
|
||||||
>> which are downloaded from the IMAP server do not have their UID saved
|
|
||||||
>> to the maildir directory. This is REALLY, REALLY BAD, because it
|
|
||||||
>> means that on the next isync, the downloaded messages are re-uploaded
|
|
||||||
>> to the imap server, resulting in duplicate messages in the IMAP store.
|
|
||||||
>>
|
|
||||||
>> This takes means the network download takes longer, and if the network
|
|
||||||
>> connection is unrealible, it means it's more likely the the IMAP
|
|
||||||
>> connection will break, resulting in more duplicate messages being
|
|
||||||
>> uploaded to the servers. (The first time, 14 messages were uploaded
|
|
||||||
>> to the server. The second time I re-isynced, 65 messages were
|
|
||||||
>> uploaded to the server, resulting in some 79 duplicate messages that I
|
|
||||||
>> had to manually weed out. Grr, grr, grr, grr.)
|
|
||||||
|
|
||||||
Problem solution:
|
|
||||||
|
|
||||||
Actually, I managed to figure out the solution a while ago, and got
|
|
||||||
hung up trying to figure out the right way to submit the patches back
|
|
||||||
to upstream (there's no mailing list that I can find; so do you just
|
|
||||||
communicate directly with the developers). Anyway, I got busy and I
|
|
||||||
never had a chance to send the patches a while ago.
|
|
||||||
|
|
||||||
This patch is not the best, but it does seem to work. Perhaps a
|
|
||||||
better approach would be to use the more advanced API's available with
|
|
||||||
berkdb, so you can actually force a sync to the db/dbm files after
|
|
||||||
the mail message has been downloaded. Fundamentally, that's the
|
|
||||||
problem. The id has been added to the db file, but the changes don't
|
|
||||||
get forced out to disk, so in the case of an abnormal termination of
|
|
||||||
the program, the id's never get written to disk.
|
|
||||||
|
|
||||||
The patch enclosed below solves the problem by establishing a signal
|
|
||||||
handler, which cleans up in the case of the user typing ^C (after the
|
|
||||||
network connection has gone away, say because your GSM phone's GPRS
|
|
||||||
connection has gotten flakey, for example). However, it doesn't solve
|
|
||||||
the problem in case of an abrupt system crash. In order to address
|
|
||||||
that problem, the overall program interfaces would have to be changed
|
|
||||||
to use the newer berkdb interfaces directly, but that would mean
|
|
||||||
dropping compatibility with the ancient dbm interface. Personally, I
|
|
||||||
don't think that to be any great loss, but the changes would be much
|
|
||||||
more invasive, and would require agreement with the upstream
|
|
||||||
maintainer that this is the right way to go.
|
|
||||||
|
|
||||||
Also, for bonus points, perhaps there should be an inactivity timer so
|
|
||||||
that isync can automatically figure out when the network connection
|
|
||||||
has gone away, and can do a clean shutdown and exit automatically,
|
|
||||||
instead of requiring the user to type ^C.
|
|
||||||
|
|
||||||
- Ted
|
|
||||||
|
|
||||||
|
|
||||||
Patched files: src/main.c
|
|
||||||
===================================================================
|
|
||||||
RCS file: isync-0.9.2/src/RCS/main.c,v
|
|
||||||
retrieving revision 1.3
|
|
||||||
diff -u -r1.3 isync-0.9.2/src/main.c
|
|
||||||
--- isync-0.9.2/src/main.c 2004/01/10 01:13:38 1.3
|
|
||||||
+++ isync-0.9.2/src/main.c 2004/01/10 01:14:34
|
|
||||||
@@ -35,6 +35,7 @@
|
|
||||||
#include <string.h>
|
|
||||||
#include <ctype.h>
|
|
||||||
#include <dirent.h>
|
|
||||||
+#include <signal.h>
|
|
||||||
|
|
||||||
int Quiet;
|
|
||||||
|
|
||||||
@@ -92,6 +93,22 @@
|
|
||||||
unsigned int Tag = 0;
|
|
||||||
char Hostname[256];
|
|
||||||
int Verbose = 0;
|
|
||||||
+mailbox_t *CleanupMail = 0;
|
|
||||||
+imap_t *CleanupImap = 0;
|
|
||||||
+int CleanupValid = 0;
|
|
||||||
+
|
|
||||||
+static void signal_exit(int sig)
|
|
||||||
+{
|
|
||||||
+ info("Abort received\n");
|
|
||||||
+ if (CleanupValid) {
|
|
||||||
+ info("Aborting, cleaning up\n");
|
|
||||||
+ if (CleanupMail)
|
|
||||||
+ maildir_close (CleanupMail);
|
|
||||||
+ if (CleanupImap)
|
|
||||||
+ imap_close (CleanupImap);
|
|
||||||
+ }
|
|
||||||
+ exit (1);
|
|
||||||
+}
|
|
||||||
|
|
||||||
static void
|
|
||||||
version (void)
|
|
||||||
@@ -319,6 +336,10 @@
|
|
||||||
usage (1);
|
|
||||||
}
|
|
||||||
|
|
||||||
+ signal(SIGTERM, signal_exit);
|
|
||||||
+ signal(SIGHUP, signal_exit);
|
|
||||||
+ signal(SIGINT, signal_exit);
|
|
||||||
+
|
|
||||||
gethostname (Hostname, sizeof (Hostname));
|
|
||||||
|
|
||||||
load_config (config, &o2o);
|
|
||||||
@@ -410,6 +431,9 @@
|
|
||||||
ret = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
+ CleanupValid = 1;
|
|
||||||
+ CleanupMail = mail;
|
|
||||||
+ CleanupImap = imap;
|
|
||||||
|
|
||||||
info ("Synchronizing\n");
|
|
||||||
i = (delete || box->delete) ? SYNC_DELETE : 0;
|
|
||||||
@@ -460,6 +484,8 @@
|
|
||||||
|
|
||||||
} while (0);
|
|
||||||
|
|
||||||
+ CleanupValid = 0;
|
|
||||||
+
|
|
||||||
/* we never sync the same mailbox twice, so close it now */
|
|
||||||
if (mail)
|
|
||||||
maildir_close (mail);
|
|
||||||
|
|
458
debian/patches/30-async-imap.dpatch
vendored
458
debian/patches/30-async-imap.dpatch
vendored
|
@ -1,458 +0,0 @@
|
||||||
#!/bin/sh -e
|
|
||||||
## 30-aysnc-imap.dpatch by Theodore Y. Ts'o <tytso@mit.edu>
|
|
||||||
##
|
|
||||||
## DP: Add the beginnings of asynchronous IMAP support. So far, we only
|
|
||||||
## DP: support asynchronous flag setting, since that's the easist.
|
|
||||||
## DP: Eventually we need to support asynchronous message fetches and
|
|
||||||
## DP: uploads.
|
|
||||||
|
|
||||||
if [ $# -ne 1 ]; then
|
|
||||||
echo >&2 "`basename $0`: script expects -patch|-unpatch as argument"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
[ -f debian/patches/00patch-opts ] && . debian/patches/00patch-opts
|
|
||||||
patch_opts="${patch_opts:--f --no-backup-if-mismatch}"
|
|
||||||
|
|
||||||
case "$1" in
|
|
||||||
-patch) patch $patch_opts -p1 < $0;;
|
|
||||||
-unpatch) patch $patch_opts -p1 -R < $0;;
|
|
||||||
*)
|
|
||||||
echo >&2 "`basename $0`: script expects -patch|-unpatch as argument"
|
|
||||||
exit 1;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
exit 0
|
|
||||||
|
|
||||||
@DPATCH@
|
|
||||||
diff -urNad /usr/projects/isync/SF-cvs/isync/src/imap.c isync/src/imap.c
|
|
||||||
--- /usr/projects/isync/SF-cvs/isync/src/imap.c 2004-01-15 14:24:40.000000000 -0500
|
|
||||||
+++ isync/src/imap.c 2004-01-15 20:36:15.000000000 -0500
|
|
||||||
@@ -3,6 +3,7 @@
|
|
||||||
* isync - IMAP4 to maildir mailbox synchronizer
|
|
||||||
* Copyright (C) 2000-2002 Michael R. Elkins <me@mutt.org>
|
|
||||||
* Copyright (C) 2002-2003 Oswald Buddenhagen <ossi@users.sf.net>
|
|
||||||
+ * Copyright (C) 2004 Theodore Ts'o <tytso@alum.mit.edu>
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
@@ -35,13 +36,33 @@
|
|
||||||
#include <string.h>
|
|
||||||
#include <ctype.h>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
+#include <sys/ioctl.h>
|
|
||||||
#include <netinet/in.h>
|
|
||||||
+#include <netinet/tcp.h>
|
|
||||||
#include <arpa/inet.h>
|
|
||||||
#include <netdb.h>
|
|
||||||
#if HAVE_LIBSSL
|
|
||||||
# include <openssl/err.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
+struct imap_cmd {
|
|
||||||
+ unsigned int tag;
|
|
||||||
+ char *cmd;
|
|
||||||
+ int flags;
|
|
||||||
+ int response;
|
|
||||||
+ struct imap_cmd *next;
|
|
||||||
+ int (*complete_fn) (imap_t *imap, struct imap_cmd * cmd);
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+#define IMAP_FLAG_DONE 0x0001
|
|
||||||
+
|
|
||||||
+static struct imap_cmd *in_progress = NULL;
|
|
||||||
+static int num_in_progress = 0;
|
|
||||||
+int max_in_progress_high = 50;
|
|
||||||
+int max_in_progress_low = 10;
|
|
||||||
+
|
|
||||||
+static struct imap_cmd *get_cmd_result(imap_t *imap);
|
|
||||||
+
|
|
||||||
const char *Flags[] = {
|
|
||||||
"\\Seen",
|
|
||||||
"\\Answered",
|
|
||||||
@@ -199,6 +220,22 @@
|
|
||||||
return write (sock->fd, buf, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
+static int
|
|
||||||
+socket_pending(Socket_t *sock)
|
|
||||||
+{
|
|
||||||
+ int num = -1;
|
|
||||||
+
|
|
||||||
+ if (ioctl(sock->fd, FIONREAD, &num) < 0)
|
|
||||||
+ return -1;
|
|
||||||
+ if (num > 0)
|
|
||||||
+ return num;
|
|
||||||
+#if HAVE_LIBSSL
|
|
||||||
+ if (sock->use_ssl)
|
|
||||||
+ return SSL_pending (sock->ssl);
|
|
||||||
+#endif
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
static void
|
|
||||||
socket_perror (const char *func, Socket_t *sock, int ret)
|
|
||||||
{
|
|
||||||
@@ -301,16 +338,20 @@
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
-parse_fetch (imap_t * imap, list_t * list)
|
|
||||||
+parse_fetch (imap_t * imap, char *cmd)
|
|
||||||
{
|
|
||||||
- list_t *tmp;
|
|
||||||
+ list_t *tmp, *list;
|
|
||||||
unsigned int uid = 0;
|
|
||||||
unsigned int mask = 0;
|
|
||||||
unsigned int size = 0;
|
|
||||||
message_t *cur;
|
|
||||||
|
|
||||||
- if (!is_list (list))
|
|
||||||
+ list = parse_list (cmd, 0);
|
|
||||||
+
|
|
||||||
+ if (!is_list (list)) {
|
|
||||||
+ free_list(list);
|
|
||||||
return -1;
|
|
||||||
+ }
|
|
||||||
|
|
||||||
for (tmp = list->child; tmp; tmp = tmp->next)
|
|
||||||
{
|
|
||||||
@@ -325,6 +366,7 @@
|
|
||||||
if (uid < imap->minuid)
|
|
||||||
{
|
|
||||||
/* already saw this message */
|
|
||||||
+ free_list(list);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
else if (uid > imap->maxuid)
|
|
||||||
@@ -387,6 +429,7 @@
|
|
||||||
cur->flags = mask;
|
|
||||||
cur->size = size;
|
|
||||||
|
|
||||||
+ free_list(list);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -415,39 +458,121 @@
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
-static int
|
|
||||||
-imap_exec (imap_t * imap, const char *fmt, ...)
|
|
||||||
+static void print_imap_command(const char *cmd, FILE *f)
|
|
||||||
+{
|
|
||||||
+ if (strncmp(cmd, "LOGIN", 5))
|
|
||||||
+ fputs(cmd, f);
|
|
||||||
+ else
|
|
||||||
+ fputs("LOGIN USERNAME PASSWORD", f);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static struct imap_cmd *issue_imap_cmd(imap_t *imap,
|
|
||||||
+ const char *fmt, ...)
|
|
||||||
{
|
|
||||||
va_list ap;
|
|
||||||
- char tmp[256];
|
|
||||||
- char buf[256];
|
|
||||||
- char *cmd;
|
|
||||||
- char *arg;
|
|
||||||
- char *arg1;
|
|
||||||
- config_t *box;
|
|
||||||
+ char tmp[1024];
|
|
||||||
+ char buf[1024];
|
|
||||||
+ struct imap_cmd *cmd;
|
|
||||||
int n;
|
|
||||||
|
|
||||||
+ cmd = malloc(sizeof(struct imap_cmd));
|
|
||||||
+ if (!cmd)
|
|
||||||
+ return NULL;
|
|
||||||
+
|
|
||||||
+ cmd->tag = ++Tag;
|
|
||||||
+ cmd->flags = 0;
|
|
||||||
+ cmd->response = 0;
|
|
||||||
+ cmd->complete_fn = 0;
|
|
||||||
+
|
|
||||||
va_start (ap, fmt);
|
|
||||||
vsnprintf (tmp, sizeof (tmp), fmt, ap);
|
|
||||||
va_end (ap);
|
|
||||||
|
|
||||||
- snprintf (buf, sizeof (buf), "%d %s\r\n", ++Tag, tmp);
|
|
||||||
+ cmd->cmd = malloc(strlen(tmp)+1);
|
|
||||||
+ if (cmd->cmd)
|
|
||||||
+ strcpy(cmd->cmd, tmp);
|
|
||||||
+
|
|
||||||
+ snprintf (buf, sizeof (buf), "%d %s\r\n", cmd->tag, tmp);
|
|
||||||
if (Verbose) {
|
|
||||||
- printf (">>> %s", buf);
|
|
||||||
+ if (num_in_progress)
|
|
||||||
+ printf("(%d in progress) ", num_in_progress);
|
|
||||||
+ printf(">>> %d ", cmd->tag);
|
|
||||||
+ print_imap_command(tmp, stdout);
|
|
||||||
+ fputc('\n', stdout);
|
|
||||||
fflush (stdout);
|
|
||||||
}
|
|
||||||
n = socket_write (imap->sock, buf, strlen (buf));
|
|
||||||
if (n <= 0)
|
|
||||||
{
|
|
||||||
socket_perror ("write", imap->sock, n);
|
|
||||||
- return -1;
|
|
||||||
+ free(cmd);
|
|
||||||
+ return NULL;
|
|
||||||
}
|
|
||||||
+ cmd->next = in_progress;
|
|
||||||
+ in_progress = cmd;
|
|
||||||
+ num_in_progress++;
|
|
||||||
+ if ((num_in_progress > max_in_progress_high) ||
|
|
||||||
+ socket_pending(imap->sock)) {
|
|
||||||
+ while ((num_in_progress > max_in_progress_low) ||
|
|
||||||
+ socket_pending(imap->sock)) {
|
|
||||||
+ if (Verbose && socket_pending(imap->sock))
|
|
||||||
+ printf("(Socket input pending)\n");
|
|
||||||
+ get_cmd_result(imap);
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ return cmd;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static struct imap_cmd *find_imap_cmd(unsigned int tag)
|
|
||||||
+{
|
|
||||||
+ struct imap_cmd *cmd, *prev;
|
|
||||||
+
|
|
||||||
+ for (prev=NULL, cmd=in_progress; cmd; cmd = cmd->next) {
|
|
||||||
+ if (tag == cmd->tag) {
|
|
||||||
+ return cmd;
|
|
||||||
+ }
|
|
||||||
+ prev = cmd;
|
|
||||||
+ }
|
|
||||||
+ return NULL;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static void dequeue_imap_cmd(unsigned int tag)
|
|
||||||
+{
|
|
||||||
+ struct imap_cmd *cmd, *prev;
|
|
||||||
+
|
|
||||||
+ for (prev=NULL, cmd=in_progress; cmd; cmd = cmd->next) {
|
|
||||||
+ if (tag != cmd->tag) {
|
|
||||||
+ prev = cmd;
|
|
||||||
+ continue;
|
|
||||||
+ }
|
|
||||||
+ if (prev)
|
|
||||||
+ prev->next = cmd->next;
|
|
||||||
+ else
|
|
||||||
+ in_progress = cmd->next;
|
|
||||||
+ cmd->next = 0;
|
|
||||||
+ if (cmd->cmd)
|
|
||||||
+ free(cmd->cmd);
|
|
||||||
+ cmd->cmd = 0;
|
|
||||||
+ free(cmd);
|
|
||||||
+ break;
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static struct imap_cmd *get_cmd_result(imap_t *imap)
|
|
||||||
+{
|
|
||||||
+ char *cmd;
|
|
||||||
+ char *arg;
|
|
||||||
+ char *arg1;
|
|
||||||
+ config_t *box;
|
|
||||||
+ int n;
|
|
||||||
+ unsigned int tag;
|
|
||||||
+ struct imap_cmd *cmdp;
|
|
||||||
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
next:
|
|
||||||
if (buffer_gets (imap->buf, &cmd))
|
|
||||||
- return -1;
|
|
||||||
+ return NULL;
|
|
||||||
|
|
||||||
arg = next_arg (&cmd);
|
|
||||||
if (*arg == '*')
|
|
||||||
@@ -456,7 +581,7 @@
|
|
||||||
if (!arg)
|
|
||||||
{
|
|
||||||
fprintf (stderr, "IMAP error: unable to parse untagged response\n");
|
|
||||||
- return -1;
|
|
||||||
+ return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!strcmp ("NAMESPACE", arg))
|
|
||||||
@@ -528,23 +653,14 @@
|
|
||||||
imap->recent = atoi (arg);
|
|
||||||
else if (!strcmp ("FETCH", arg1))
|
|
||||||
{
|
|
||||||
- list_t *list;
|
|
||||||
-
|
|
||||||
- list = parse_list (cmd, 0);
|
|
||||||
-
|
|
||||||
- if (parse_fetch (imap, list))
|
|
||||||
- {
|
|
||||||
- free_list (list);
|
|
||||||
- return -1;
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
- free_list (list);
|
|
||||||
+ if (parse_fetch (imap, cmd))
|
|
||||||
+ return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
fprintf (stderr, "IMAP error: unable to parse untagged response\n");
|
|
||||||
- return -1;
|
|
||||||
+ return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#if HAVE_LIBSSL
|
|
||||||
@@ -555,7 +671,7 @@
|
|
||||||
if (!imap->cram)
|
|
||||||
{
|
|
||||||
fprintf (stderr, "IMAP error, not doing CRAM-MD5 authentication\n");
|
|
||||||
- return -1;
|
|
||||||
+ return NULL;
|
|
||||||
}
|
|
||||||
resp = cram (cmd, imap->box->user, imap->box->pass);
|
|
||||||
|
|
||||||
@@ -568,34 +684,94 @@
|
|
||||||
if (n <= 0)
|
|
||||||
{
|
|
||||||
socket_perror ("write", imap->sock, n);
|
|
||||||
- return -1;
|
|
||||||
+ return NULL;
|
|
||||||
}
|
|
||||||
n = socket_write (imap->sock, "\r\n", 2);
|
|
||||||
if (n <= 0)
|
|
||||||
{
|
|
||||||
socket_perror ("write", imap->sock, n);
|
|
||||||
- return -1;
|
|
||||||
+ return NULL;
|
|
||||||
}
|
|
||||||
imap->cram = 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
- else if ((size_t) atol (arg) != Tag)
|
|
||||||
- {
|
|
||||||
- fprintf (stderr, "IMAP error: wrong tag\n");
|
|
||||||
- return -1;
|
|
||||||
- }
|
|
||||||
- else
|
|
||||||
- {
|
|
||||||
- arg = next_arg (&cmd);
|
|
||||||
- parse_response_code (imap, cmd);
|
|
||||||
- if (!strcmp ("OK", arg))
|
|
||||||
- return 0;
|
|
||||||
- return -1;
|
|
||||||
+ else {
|
|
||||||
+ tag = (unsigned int) atol (arg);
|
|
||||||
+ cmdp = find_imap_cmd(tag);
|
|
||||||
+ if (!cmdp) {
|
|
||||||
+ fprintf(stderr, "IMAP error: sent unknown tag: %u\n",
|
|
||||||
+ tag);
|
|
||||||
+ return NULL;
|
|
||||||
+ }
|
|
||||||
+ arg = next_arg (&cmd);
|
|
||||||
+ if (strncmp("OK", arg, 2)) {
|
|
||||||
+ if (cmdp->cmd) {
|
|
||||||
+ fputc('\'', stderr);
|
|
||||||
+ print_imap_command(cmdp->cmd, stderr);
|
|
||||||
+ fputc('\'', stderr);
|
|
||||||
+ } else
|
|
||||||
+ fprintf(stderr, "tag %u", tag);
|
|
||||||
+ fprintf(stderr, " returned an error (%s): %s\n",
|
|
||||||
+ arg, cmd ? cmd : "");
|
|
||||||
+ cmdp->response = -1;
|
|
||||||
+ }
|
|
||||||
+ parse_response_code (imap, cmd);
|
|
||||||
+ num_in_progress--;
|
|
||||||
+ cmdp->flags |= IMAP_FLAG_DONE;
|
|
||||||
+ if (Verbose)
|
|
||||||
+ printf("Tag %u completed with response %d\n",
|
|
||||||
+ cmdp->tag, cmdp->response);
|
|
||||||
+ return cmdp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* not reached */
|
|
||||||
}
|
|
||||||
|
|
||||||
+static void flush_imap_cmds(imap_t *imap)
|
|
||||||
+{
|
|
||||||
+ struct imap_cmd *cmdp;
|
|
||||||
+
|
|
||||||
+ while (num_in_progress) {
|
|
||||||
+ if (in_progress && in_progress->flags & IMAP_FLAG_DONE) {
|
|
||||||
+ dequeue_imap_cmd(in_progress->tag);
|
|
||||||
+ continue;
|
|
||||||
+ }
|
|
||||||
+ cmdp = get_cmd_result(imap);
|
|
||||||
+ if (!cmdp)
|
|
||||||
+ printf("Error trying to flush pending imap cmds\n");
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int
|
|
||||||
+imap_exec (imap_t * imap, const char *fmt, ...)
|
|
||||||
+{
|
|
||||||
+ va_list ap;
|
|
||||||
+ char tmp[1024];
|
|
||||||
+ struct imap_cmd *cmdp, *waitp;
|
|
||||||
+ int result;
|
|
||||||
+
|
|
||||||
+ va_start (ap, fmt);
|
|
||||||
+ vsnprintf (tmp, sizeof (tmp), fmt, ap);
|
|
||||||
+ va_end (ap);
|
|
||||||
+
|
|
||||||
+ cmdp = issue_imap_cmd(imap, "%s", tmp);
|
|
||||||
+ if (!cmdp)
|
|
||||||
+ return -1;
|
|
||||||
+
|
|
||||||
+ if (cmdp->flags & IMAP_FLAG_DONE)
|
|
||||||
+ return cmdp->response;
|
|
||||||
+
|
|
||||||
+ do {
|
|
||||||
+ waitp = get_cmd_result(imap);
|
|
||||||
+ } while (waitp->tag != cmdp->tag);
|
|
||||||
+
|
|
||||||
+ result = cmdp->response;
|
|
||||||
+ dequeue_imap_cmd(cmdp->tag);
|
|
||||||
+
|
|
||||||
+ return cmdp->response;
|
|
||||||
+
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
#ifdef HAVE_LIBSSL
|
|
||||||
static int
|
|
||||||
start_tls (imap_t *imap, config_t * cfg)
|
|
||||||
@@ -1039,6 +1215,7 @@
|
|
||||||
size_t n;
|
|
||||||
char buf[1024];
|
|
||||||
|
|
||||||
+ flush_imap_cmds(imap);
|
|
||||||
send_server (imap->sock, "UID FETCH %d BODY.PEEK[]", uid);
|
|
||||||
|
|
||||||
for (;;)
|
|
||||||
@@ -1160,7 +1337,9 @@
|
|
||||||
(buf[0] != 0) ? " " : "", Flags[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
- return imap_exec (imap, "UID STORE %d +FLAGS.SILENT (%s)", uid, buf);
|
|
||||||
+ if (issue_imap_cmd(imap, "UID STORE %d +FLAGS.SILENT (%s)", uid, buf))
|
|
||||||
+ return 0;
|
|
||||||
+ return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
@@ -1249,6 +1428,7 @@
|
|
||||||
strcat (flagstr,") ");
|
|
||||||
}
|
|
||||||
|
|
||||||
+ flush_imap_cmds(imap);
|
|
||||||
send_server (imap->sock, "APPEND %s%s %s{%d}",
|
|
||||||
imap->prefix, imap->box->box, flagstr, len + extra);
|
|
||||||
|
|
||||||
@@ -1341,6 +1521,7 @@
|
|
||||||
}
|
|
||||||
|
|
||||||
/* didn't receive an APPENDUID */
|
|
||||||
+ flush_imap_cmds(imap);
|
|
||||||
send_server (imap->sock,
|
|
||||||
"UID SEARCH HEADER X-TUID %08lx%05lx%04x",
|
|
||||||
tv.tv_sec, tv.tv_usec, pid);
|
|
1
debian/po/POTFILES.in
vendored
1
debian/po/POTFILES.in
vendored
|
@ -1 +0,0 @@
|
||||||
[type: gettext/rfc822deb] templates
|
|
74
debian/po/fr.po
vendored
74
debian/po/fr.po
vendored
|
@ -1,74 +0,0 @@
|
||||||
#
|
|
||||||
# Translators, if you are not familiar with the PO format, gettext
|
|
||||||
# documentation is worth reading, especially sections dedicated to
|
|
||||||
# this format, e.g. by running:
|
|
||||||
# info -n '(gettext)PO Files'
|
|
||||||
# info -n '(gettext)Header Entry'
|
|
||||||
#
|
|
||||||
# Some information specific to po-debconf are available at
|
|
||||||
# /usr/share/doc/po-debconf/README-trans
|
|
||||||
# or http://www.debian.org/intl/l10n/po-debconf/README-trans
|
|
||||||
#
|
|
||||||
# Developers do not need to manually edit POT or PO files.
|
|
||||||
#
|
|
||||||
msgid ""
|
|
||||||
msgstr ""
|
|
||||||
"Project-Id-Version: isync 0.9.1-1\n"
|
|
||||||
"POT-Creation-Date: 2003-10-14 21:55+0200\n"
|
|
||||||
"PO-Revision-Date: 2003-10-27 11:52+0100\n"
|
|
||||||
"Last-Translator: Christian Perrier <bubulle@debian.org>\n"
|
|
||||||
"Language-Team: French <debian-l10n-french@lists.debian.org>\n"
|
|
||||||
"MIME-Version: 1.0\n"
|
|
||||||
"Content-Type: text/plain; charset=iso-8859-15\n"
|
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
|
||||||
|
|
||||||
#. Description
|
|
||||||
#: ../templates:4
|
|
||||||
msgid "Abort isync upgrade"
|
|
||||||
msgstr "Interrompre la mise à jour d'isync"
|
|
||||||
|
|
||||||
#. Description
|
|
||||||
#: ../templates:4
|
|
||||||
msgid ""
|
|
||||||
"You are upgrading from an older version of isync that stored the UID of each "
|
|
||||||
"message in a way that is not compatable with the new version. You need to "
|
|
||||||
"remove all the messages in local folders downloaded with the old version of "
|
|
||||||
"isync. Otherwise isync will get confused and upload duplicate messages to "
|
|
||||||
"the IMAP server."
|
|
||||||
msgstr ""
|
|
||||||
"Vous mettez isync à jour à partir d'une version qui utilise une méthode de "
|
|
||||||
"stockage des identifiants des messages incompatible avec la nouvelle "
|
|
||||||
"version. Il faut supprimer des répertoires locaux tous les messages "
|
|
||||||
"téléchargés avec l'ancienne version ; sinon, isync fonctionnera "
|
|
||||||
"incorrectement et enverra au serveur IMAP des doublons des messages."
|
|
||||||
|
|
||||||
#. Description
|
|
||||||
#: ../templates:4
|
|
||||||
msgid ""
|
|
||||||
"A suggested upgrade procedure is to use the isync version 0.7 to synchronize "
|
|
||||||
"any local changes in isync-managed mailboxes with your IMAP server (if there "
|
|
||||||
"are any local changes to synchronise), and then remove the contents of the "
|
|
||||||
"local mailboxes, before upgrading to version 0.8 or above. Then run isync "
|
|
||||||
"again to pull down the mail again. You must do this manually; the Debian "
|
|
||||||
"package will not do this for you."
|
|
||||||
msgstr ""
|
|
||||||
"La méthode suggérée pour la mise à jour est la suivante : en utilisant "
|
|
||||||
"la version 0.7 d'isync, synchronisez avec le serveur IMAP les éventuelles modifications locales "
|
|
||||||
"des boîtes aux lettres gérées par isync ; puis "
|
|
||||||
"supprimez le contenu des boîtes aux lettres locales. Ensuite, effectuez la "
|
|
||||||
"mise à jour vers une version supérieure ou égale à 0.8. Enfin, utilisez à "
|
|
||||||
"nouveau isync pour récupérer les courriels. Vous devez effectuer cette "
|
|
||||||
"opération vous-même : le paquet Debian ne la fera pas automatiquement."
|
|
||||||
|
|
||||||
#. Description
|
|
||||||
#: ../templates:4
|
|
||||||
msgid ""
|
|
||||||
"If you want, the upgrade of isync can be aborted to let you deal with this "
|
|
||||||
"issue. Or you can just suspend the upgrade or switch to a different virtual "
|
|
||||||
"console to take care of it. Do not continue past this point before manually "
|
|
||||||
"resolving this issue!"
|
|
||||||
msgstr ""
|
|
||||||
"Si vous le souhaitez, la mise à jour d'isync peut être interrompue pour vous "
|
|
||||||
"permettre d'effectuer cette opération. Vous pouvez également basculer vers "
|
|
||||||
"une autre console virtuelle pour vous en occuper, puis reprendre la mise à jour. Ne continuez pas "
|
|
||||||
"sans faire cette correction."
|
|
60
debian/po/templates.pot
vendored
60
debian/po/templates.pot
vendored
|
@ -1,60 +0,0 @@
|
||||||
#
|
|
||||||
# Translators, if you are not familiar with the PO format, gettext
|
|
||||||
# documentation is worth reading, especially sections dedicated to
|
|
||||||
# this format, e.g. by running:
|
|
||||||
# info -n '(gettext)PO Files'
|
|
||||||
# info -n '(gettext)Header Entry'
|
|
||||||
#
|
|
||||||
# Some information specific to po-debconf are available at
|
|
||||||
# /usr/share/doc/po-debconf/README-trans
|
|
||||||
# or http://www.debian.org/intl/l10n/po-debconf/README-trans
|
|
||||||
#
|
|
||||||
# Developers do not need to manually edit POT or PO files.
|
|
||||||
#
|
|
||||||
#, fuzzy
|
|
||||||
msgid ""
|
|
||||||
msgstr ""
|
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
|
||||||
"Report-Msgid-Bugs-To: \n"
|
|
||||||
"POT-Creation-Date: 2003-10-14 21:55+0200\n"
|
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
|
||||||
"MIME-Version: 1.0\n"
|
|
||||||
"Content-Type: text/plain; charset=CHARSET\n"
|
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
|
||||||
|
|
||||||
#. Description
|
|
||||||
#: ../templates:4
|
|
||||||
msgid "Abort isync upgrade"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#. Description
|
|
||||||
#: ../templates:4
|
|
||||||
msgid ""
|
|
||||||
"You are upgrading from an older version of isync that stored the UID of each "
|
|
||||||
"message in a way that is not compatable with the new version. You need to "
|
|
||||||
"remove all the messages in local folders downloaded with the old version of "
|
|
||||||
"isync. Otherwise isync will get confused and upload duplicate messages to "
|
|
||||||
"the IMAP server."
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#. Description
|
|
||||||
#: ../templates:4
|
|
||||||
msgid ""
|
|
||||||
"A suggested upgrade procedure is to use the isync version 0.7 to synchronize "
|
|
||||||
"any local changes in isync-managed mailboxes with your IMAP server (if there "
|
|
||||||
"are any local changes to synchronise), and then remove the contents of the "
|
|
||||||
"local mailboxes, before upgrading to version 0.8 or above. Then run isync "
|
|
||||||
"again to pull down the mail again. You must do this manually; the Debian "
|
|
||||||
"package will not do this for you."
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#. Description
|
|
||||||
#: ../templates:4
|
|
||||||
msgid ""
|
|
||||||
"If you want, the upgrade of isync can be aborted to let you deal with this "
|
|
||||||
"issue. Or you can just suspend the upgrade or switch to a different virtual "
|
|
||||||
"console to take care of it. Do not continue past this point before manually "
|
|
||||||
"resolving this issue!"
|
|
||||||
msgstr ""
|
|
19
debian/preinst
vendored
19
debian/preinst
vendored
|
@ -1,19 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
set -e
|
|
||||||
|
|
||||||
if [ "$1" = "upgrade" ] && dpkg --compare-versions "$2" lt "0.8"; then
|
|
||||||
# Do not do debconf stuff if debconf is not there.
|
|
||||||
# I don't want to have to pre-depend on debconf.
|
|
||||||
if [ -e /usr/share/debconf/confmodule ]; then
|
|
||||||
. /usr/share/debconf/confmodule
|
|
||||||
db_get isync/upgrade_0.8
|
|
||||||
if [ "$RET" = true ]; then
|
|
||||||
echo "Aborting isync upgrade at your request so you can manually resolve upgrade issue." >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo "WARNING: Read NEWS.Debian file about manual upgrade issues from isync 0.7." >&2
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
#DEBHELPER#
|
|
3
debian/rules
vendored
3
debian/rules
vendored
|
@ -41,9 +41,8 @@ binary-arch: build install
|
||||||
dh_testroot
|
dh_testroot
|
||||||
dh_installchangelogs ChangeLog
|
dh_installchangelogs ChangeLog
|
||||||
dh_installdocs AUTHORS NEWS README TODO
|
dh_installdocs AUTHORS NEWS README TODO
|
||||||
dh_installexamples isyncrc.sample
|
dh_installexamples src/mbsyncrc.sample src/compat/isyncrc.sample
|
||||||
dh_installman
|
dh_installman
|
||||||
dh_installdebconf
|
|
||||||
dh_strip
|
dh_strip
|
||||||
dh_compress
|
dh_compress
|
||||||
dh_fixperms
|
dh_fixperms
|
||||||
|
|
21
debian/templates
vendored
21
debian/templates
vendored
|
@ -1,21 +0,0 @@
|
||||||
Template: isync/upgrade_0.8
|
|
||||||
Type: boolean
|
|
||||||
Default: false
|
|
||||||
_Description: Abort isync upgrade
|
|
||||||
You are upgrading from an older version of isync that stored the UID of
|
|
||||||
each message in a way that is not compatable with the new version. You
|
|
||||||
need to remove all the messages in local folders downloaded with the old
|
|
||||||
version of isync. Otherwise isync will get confused and upload duplicate
|
|
||||||
messages to the IMAP server.
|
|
||||||
.
|
|
||||||
A suggested upgrade procedure is to use the isync version 0.7 to
|
|
||||||
synchronize any local changes in isync-managed mailboxes with your IMAP
|
|
||||||
server (if there are any local changes to synchronise), and then remove
|
|
||||||
the contents of the local mailboxes, before upgrading to version 0.8 or
|
|
||||||
above. Then run isync again to pull down the mail again. You must do this
|
|
||||||
manually; the Debian package will not do this for you.
|
|
||||||
.
|
|
||||||
If you want, the upgrade of isync can be aborted to let you deal with this
|
|
||||||
issue. Or you can just suspend the upgrade or switch to a different
|
|
||||||
virtual console to take care of it. Do not continue past this point before
|
|
||||||
manually resolving this issue!
|
|
|
@ -10,16 +10,16 @@ Packager: Oswald Buddenhagen <ossi@users.sf.net>
|
||||||
BuildRoot: /var/tmp/%{name}-buildroot
|
BuildRoot: /var/tmp/%{name}-buildroot
|
||||||
|
|
||||||
%description
|
%description
|
||||||
isync is a command line utility for synchronizing a remote IMAP mailbox with a
|
isync is a command line utility which synchronizes mailboxes; currently
|
||||||
local maildir-style mailbox. This is useful for working in disconnected mode,
|
Maildir and IMAP4 mailboxes are supported.
|
||||||
such as on a laptop. Modifications made locally and remotely are synchronized
|
New messages, message deletions and flag changes can be propagated both ways.
|
||||||
so that no message status flags are lost.
|
It is useful for working in disconnected mode, such as on a laptop or with a
|
||||||
|
non-permanent internet collection (dIMAP).
|
||||||
|
|
||||||
%prep
|
%prep
|
||||||
%setup
|
%setup
|
||||||
%build
|
%build
|
||||||
./configure --prefix=/usr
|
./configure --prefix=/usr
|
||||||
make RPM_OPT_FLAGS="$RPM_OPT_FLAGS"
|
|
||||||
|
|
||||||
%install
|
%install
|
||||||
make DESTDIR=$RPM_BUILD_ROOT install
|
make DESTDIR=$RPM_BUILD_ROOT install
|
||||||
|
@ -28,6 +28,11 @@ make DESTDIR=$RPM_BUILD_ROOT install
|
||||||
rm -rf $RPM_BUILD_ROOT
|
rm -rf $RPM_BUILD_ROOT
|
||||||
|
|
||||||
%files
|
%files
|
||||||
%doc AUTHORS COPYING README TODO ChangeLog isyncrc.sample
|
%doc AUTHORS COPYING NEWS README TODO ChangeLog src/mbsyncrc.sample src/compat/isyncrc.sample
|
||||||
/usr/bin/isync
|
/usr/bin/isync
|
||||||
|
/usr/bin/mbsync
|
||||||
|
/usr/bin/mdconvert
|
||||||
|
/usr/bin/get-cert
|
||||||
/usr/man/man1/isync.1.gz
|
/usr/man/man1/isync.1.gz
|
||||||
|
/usr/man/man1/mbsync.1.gz
|
||||||
|
/usr/man/man1/mdconvert.1.gz
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
.deps
|
.deps
|
||||||
Makefile
|
Makefile
|
||||||
Makefile.in
|
Makefile.in
|
||||||
isync
|
mbsync
|
||||||
|
mdconvert
|
||||||
|
|
|
@ -1,5 +1,16 @@
|
||||||
bin_PROGRAMS = isync
|
if with_compat
|
||||||
isync_SOURCES = main.c imap.c sync.c maildir.c list.c cram.c config.c dotlock.c
|
compat_dir = compat
|
||||||
noinst_HEADERS = isync.h dotlock.h
|
endif
|
||||||
INCLUDES=$(RPM_OPT_FLAGS)
|
SUBDIRS = $(compat_dir)
|
||||||
DISTCLEANFILES = *~
|
|
||||||
|
bin_PROGRAMS = mbsync mdconvert
|
||||||
|
|
||||||
|
mbsync_SOURCES = main.c sync.c config.c util.c drv_imap.c drv_maildir.c
|
||||||
|
mbsync_LDADD = -ldb $(SSL_LIBS) $(SOCK_LIBS)
|
||||||
|
noinst_HEADERS = isync.h
|
||||||
|
|
||||||
|
mdconvert_SOURCES = mdconvert.c
|
||||||
|
mdconvert_LDADD = -ldb
|
||||||
|
|
||||||
|
man_MANS = mbsync.1 mdconvert.1
|
||||||
|
EXTRA_DIST = mbsyncrc.sample $(man_MANS)
|
||||||
|
|
4
src/compat/.cvsignore
Normal file
4
src/compat/.cvsignore
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
.deps
|
||||||
|
Makefile
|
||||||
|
Makefile.in
|
||||||
|
isync
|
8
src/compat/Makefile.am
Normal file
8
src/compat/Makefile.am
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
bin_PROGRAMS = isync
|
||||||
|
|
||||||
|
isync_SOURCES = main.c config.c convert.c util.c
|
||||||
|
isync_LDADD = -ldb
|
||||||
|
noinst_HEADERS = isync.h
|
||||||
|
|
||||||
|
man_MANS = isync.1
|
||||||
|
EXTRA_DIST = isyncrc.sample $(man_MANS)
|
443
src/compat/config.c
Normal file
443
src/compat/config.c
Normal file
|
@ -0,0 +1,443 @@
|
||||||
|
/*
|
||||||
|
* isync - mbsync wrapper: IMAP4 to maildir mailbox synchronizer
|
||||||
|
* Copyright (C) 2000-2002 Michael R. Elkins <me@mutt.org>
|
||||||
|
* Copyright (C) 2002-2004 Oswald Buddenhagen <ossi@users.sf.net>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "isync.h"
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <pwd.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
static char *
|
||||||
|
my_strndup( const char *s, size_t nchars )
|
||||||
|
{
|
||||||
|
char *r = nfmalloc( sizeof(char) * (nchars + 1) );
|
||||||
|
memcpy( r, s, nchars );
|
||||||
|
r[nchars] = 0;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
expand_strdup( const char *s )
|
||||||
|
{
|
||||||
|
struct passwd *pw;
|
||||||
|
const char *p, *q;
|
||||||
|
char *r;
|
||||||
|
|
||||||
|
if (*s == '~') {
|
||||||
|
s++;
|
||||||
|
if (!*s) {
|
||||||
|
p = 0;
|
||||||
|
q = Home;
|
||||||
|
} else if (*s == '/') {
|
||||||
|
p = s + 1;
|
||||||
|
q = Home;
|
||||||
|
} else {
|
||||||
|
if ((p = strchr( s, '/' ))) {
|
||||||
|
r = my_strndup( s, (int)(p - s) );
|
||||||
|
pw = getpwnam( r );
|
||||||
|
free( r );
|
||||||
|
p++;
|
||||||
|
} else
|
||||||
|
pw = getpwnam( s );
|
||||||
|
if (!pw)
|
||||||
|
return 0;
|
||||||
|
q = pw->pw_dir;
|
||||||
|
}
|
||||||
|
nfasprintf( &r, "%s/%s", q, p ? p : "" );
|
||||||
|
return r;
|
||||||
|
} else if (*s != '/' && xmaildir) {
|
||||||
|
nfasprintf( &r, "%s/%s", xmaildir, s );
|
||||||
|
return r;
|
||||||
|
} else
|
||||||
|
return nfstrdup( s );
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
is_true( const char *val )
|
||||||
|
{
|
||||||
|
return
|
||||||
|
!strcasecmp( val, "yes" ) ||
|
||||||
|
!strcasecmp( val, "true" ) ||
|
||||||
|
!strcasecmp( val, "on" ) ||
|
||||||
|
!strcmp( val, "1" );
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
load_config( const char *path, config_t ***stor )
|
||||||
|
{
|
||||||
|
config_t **sstor, *cfg;
|
||||||
|
FILE *fp;
|
||||||
|
char *p, *cmd, *val;
|
||||||
|
int line = 0;
|
||||||
|
char buf[1024];
|
||||||
|
|
||||||
|
if (!(fp = fopen( path, "r" ))) {
|
||||||
|
if (errno != ENOENT)
|
||||||
|
perror( "fopen" );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!Quiet && !Debug && !Verbose)
|
||||||
|
printf( "Reading configuration file %s\n", path );
|
||||||
|
buf[sizeof(buf) - 1] = 0;
|
||||||
|
cfg = &global;
|
||||||
|
while (fgets( buf, sizeof(buf) - 1, fp )) {
|
||||||
|
p = buf;
|
||||||
|
cmd = next_arg( &p );
|
||||||
|
val = next_arg( &p );
|
||||||
|
line++;
|
||||||
|
if (!cmd || *cmd == '#')
|
||||||
|
continue;
|
||||||
|
if (!val) {
|
||||||
|
fprintf( stderr, "%s:%d: parameter missing\n", path, line );
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!strcasecmp( "Mailbox", cmd )) {
|
||||||
|
if (o2o)
|
||||||
|
break;
|
||||||
|
cfg = **stor = nfmalloc( sizeof(config_t) );
|
||||||
|
*stor = &cfg->next;
|
||||||
|
memcpy( cfg, &global, sizeof(config_t) );
|
||||||
|
/* not expanded at this point */
|
||||||
|
cfg->path = nfstrdup( val );
|
||||||
|
} else if (!strcasecmp( "OneToOne", cmd )) {
|
||||||
|
if (boxes) {
|
||||||
|
forbid:
|
||||||
|
fprintf( stderr,
|
||||||
|
"%s:%d: keyword '%s' allowed only in global section\n",
|
||||||
|
path, line, cmd );
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
o2o = is_true( val );
|
||||||
|
} else if (!strcasecmp( "Maildir", cmd )) {
|
||||||
|
if (boxes)
|
||||||
|
goto forbid;
|
||||||
|
maildir = nfstrdup( val );
|
||||||
|
xmaildir = expand_strdup( val );
|
||||||
|
} else if (!strcasecmp( "Folder", cmd )) {
|
||||||
|
if (boxes)
|
||||||
|
goto forbid;
|
||||||
|
folder = nfstrdup( val );
|
||||||
|
} else if (!strcasecmp( "Inbox", cmd )) {
|
||||||
|
if (boxes)
|
||||||
|
goto forbid;
|
||||||
|
inbox = nfstrdup( val );
|
||||||
|
} else if (!strcasecmp( "Host", cmd )) {
|
||||||
|
if (!memcmp( "imaps:", val, 6 )) {
|
||||||
|
val += 6;
|
||||||
|
cfg->use_imaps = 1;
|
||||||
|
cfg->port = 993;
|
||||||
|
cfg->use_sslv2 = 1;
|
||||||
|
cfg->use_sslv3 = 1;
|
||||||
|
}
|
||||||
|
cfg->host = nfstrdup( val );
|
||||||
|
} else if (!strcasecmp( "User", cmd ))
|
||||||
|
cfg->user = nfstrdup( val );
|
||||||
|
else if (!strcasecmp( "Pass", cmd ))
|
||||||
|
cfg->pass = nfstrdup( val );
|
||||||
|
else if (!strcasecmp ( "Port", cmd ))
|
||||||
|
cfg->port = atoi( val );
|
||||||
|
else if (!strcasecmp ( "Box", cmd ))
|
||||||
|
cfg->box = nfstrdup( val );
|
||||||
|
else if (!strcasecmp ( "Alias", cmd )) {
|
||||||
|
if (!boxes) {
|
||||||
|
fprintf( stderr,
|
||||||
|
"%s:%d: keyword 'Alias' allowed only in mailbox specification\n",
|
||||||
|
path, line );
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
cfg->alias = nfstrdup( val );
|
||||||
|
} else if (!strcasecmp( "MaxSize", cmd ))
|
||||||
|
cfg->max_size = atol( val );
|
||||||
|
else if (!strcasecmp ( "MaxMessages", cmd ))
|
||||||
|
cfg->max_messages = atol( val );
|
||||||
|
else if (!strcasecmp ( "UseNamespace", cmd ))
|
||||||
|
cfg->use_namespace = is_true( val );
|
||||||
|
else if (!strcasecmp ( "CopyDeletedTo", cmd ))
|
||||||
|
cfg->copy_deleted_to = nfstrdup( val );
|
||||||
|
else if (!strcasecmp ( "Tunnel", cmd ))
|
||||||
|
cfg->tunnel = nfstrdup( val );
|
||||||
|
else if (!strcasecmp ( "Expunge", cmd ))
|
||||||
|
cfg->expunge = is_true( val );
|
||||||
|
else if (!strcasecmp( "Delete", cmd ))
|
||||||
|
cfg->delete = is_true( val );
|
||||||
|
else if (!strcasecmp( "CertificateFile", cmd ))
|
||||||
|
cfg->cert_file = expand_strdup( val );
|
||||||
|
else if (!strcasecmp( "RequireSSL", cmd ))
|
||||||
|
cfg->require_ssl = is_true( val );
|
||||||
|
else if (!strcasecmp( "UseSSLv2", cmd ))
|
||||||
|
cfg->use_sslv2 = is_true( val );
|
||||||
|
else if (!strcasecmp( "UseSSLv3", cmd ))
|
||||||
|
cfg->use_sslv3 = is_true( val );
|
||||||
|
else if (!strcasecmp( "UseTLSv1", cmd ))
|
||||||
|
cfg->use_tlsv1 = is_true( val );
|
||||||
|
else if (!strcasecmp( "RequireCRAM", cmd ))
|
||||||
|
cfg->require_cram = is_true( val );
|
||||||
|
else if (buf[0])
|
||||||
|
fprintf( stderr, "%s:%d: unknown keyword '%s'\n", path, line, cmd );
|
||||||
|
}
|
||||||
|
fclose( fp );
|
||||||
|
if (o2o) {
|
||||||
|
if (!global.host && !global.tunnel) {
|
||||||
|
fprintf( stderr, "Neither Host nor Tunnel given to OneToOne. Aborting.\n" );
|
||||||
|
exit( 1 );
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
for (sstor = &boxes; (cfg = *sstor); ) {
|
||||||
|
if (!cfg->host && !cfg->tunnel) {
|
||||||
|
fprintf( stderr, "Mailbox '%s' has neither Host nor Tunnel. Skipping.\n",
|
||||||
|
cfg->alias ? cfg->alias : cfg->path );
|
||||||
|
if (&cfg->next == *stor)
|
||||||
|
*stor = sstor;
|
||||||
|
*sstor = cfg->next;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
sstor = &cfg->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *
|
||||||
|
tb( int on )
|
||||||
|
{
|
||||||
|
return on ? "yes" : "no";
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
write_imap_server( FILE *fp, config_t *cfg )
|
||||||
|
{
|
||||||
|
config_t *pbox;
|
||||||
|
char *p, *p2;
|
||||||
|
int hl, a1, a2, a3, a4;
|
||||||
|
char buf[128];
|
||||||
|
static int tunnels;
|
||||||
|
|
||||||
|
if (cfg->tunnel) {
|
||||||
|
nfasprintf( (char **)&cfg->server_name, "tunnel%d", ++tunnels );
|
||||||
|
fprintf( fp, "IMAPAccount %s\nTunnel \"%s\"\n",
|
||||||
|
cfg->server_name, cfg->tunnel );
|
||||||
|
} else {
|
||||||
|
if (sscanf( cfg->host, "%d.%d.%d.%d", &a1, &a2, &a3, &a4 ) == 4)
|
||||||
|
cfg->server_name = nfstrdup( cfg->host );
|
||||||
|
else {
|
||||||
|
p = strrchr( cfg->host, '.' );
|
||||||
|
if (!p)
|
||||||
|
hl = nfsnprintf( buf, sizeof(buf), "%s", cfg->host );
|
||||||
|
else {
|
||||||
|
hl = nfsnprintf( buf, sizeof(buf), "%.*s", p - cfg->host, cfg->host );
|
||||||
|
p2 = strrchr( buf, '.' );
|
||||||
|
if (p2)
|
||||||
|
hl = sprintf( buf, "%s", p2 + 1 );
|
||||||
|
}
|
||||||
|
if (boxes) /* !o2o */
|
||||||
|
for (pbox = boxes; pbox != cfg; pbox = pbox->next)
|
||||||
|
if (!memcmp( pbox->server_name, buf, hl + 1 )) {
|
||||||
|
nfasprintf( (char **)&cfg->server_name, "%s-%d", buf, ++pbox->servers );
|
||||||
|
goto gotsrv;
|
||||||
|
}
|
||||||
|
cfg->server_name = nfstrdup( buf );
|
||||||
|
cfg->servers = 1;
|
||||||
|
gotsrv: ;
|
||||||
|
}
|
||||||
|
fprintf( fp, "IMAPAccount %s\n", cfg->server_name );
|
||||||
|
if (cfg->use_imaps)
|
||||||
|
fprintf( fp, "Host imaps:%s\n", cfg->host );
|
||||||
|
else
|
||||||
|
fprintf( fp, "Host %s\n", cfg->host );
|
||||||
|
fprintf( fp, "Port %d\n", cfg->port );
|
||||||
|
}
|
||||||
|
if (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"
|
||||||
|
"UseSSLv2 %s\nUseSSLv3 %s\nUseTLSv1 %s\n",
|
||||||
|
tb(cfg->require_cram), tb(cfg->require_ssl),
|
||||||
|
tb(cfg->use_sslv2), tb(cfg->use_sslv3), tb(cfg->use_tlsv1) );
|
||||||
|
if ((cfg->use_imaps || cfg->use_sslv2 || cfg->use_sslv3 || cfg->use_tlsv1) &&
|
||||||
|
cfg->cert_file)
|
||||||
|
fprintf( fp, "CertificateFile %s\n", cfg->cert_file );
|
||||||
|
fputc( '\n', fp );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
write_imap_store( FILE *fp, config_t *cfg )
|
||||||
|
{
|
||||||
|
if (cfg->stores > 1)
|
||||||
|
nfasprintf( (char **)&cfg->store_name, "%s-%d", cfg->server_name, cfg->stores );
|
||||||
|
else
|
||||||
|
cfg->store_name = cfg->server_name;
|
||||||
|
fprintf( fp, "IMAPStore %s\nAccount %s\n",
|
||||||
|
cfg->store_name, cfg->server_name );
|
||||||
|
if (*folder)
|
||||||
|
fprintf( fp, "Path \"%s\"\n", folder );
|
||||||
|
else
|
||||||
|
fprintf( fp, "UseNamespace %s\n", tb(cfg->use_namespace) );
|
||||||
|
if (inbox)
|
||||||
|
fprintf( fp, "MapInbox \"%s\"\n", inbox );
|
||||||
|
if (cfg->copy_deleted_to)
|
||||||
|
fprintf( fp, "Trash \"%s\"\n", cfg->copy_deleted_to );
|
||||||
|
fputc( '\n', fp );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
write_channel_parm( FILE *fp, config_t *cfg )
|
||||||
|
{
|
||||||
|
if (cfg->max_size)
|
||||||
|
fprintf( fp, "MaxSize %d\n", cfg->max_size );
|
||||||
|
if (cfg->max_messages)
|
||||||
|
fprintf( fp, "MaxMessages %d\n", cfg->max_messages );
|
||||||
|
if (!cfg->delete)
|
||||||
|
fputs( "Sync New ReNew Flags\n", fp );
|
||||||
|
if (cfg->expunge)
|
||||||
|
fputs( "Expunge Both\n", fp );
|
||||||
|
fputc( '\n', fp );
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
mstrcmp( const char *s1, const char *s2 )
|
||||||
|
{
|
||||||
|
if (s1 == s2)
|
||||||
|
return 0;
|
||||||
|
if (!s1 || !s2)
|
||||||
|
return 1;
|
||||||
|
return strcmp( s1, s2 );
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
write_config( int fd )
|
||||||
|
{
|
||||||
|
FILE *fp;
|
||||||
|
const char *cn, *scn;
|
||||||
|
config_t *box, *sbox, *pbox;
|
||||||
|
|
||||||
|
if (!(fp = fdopen( fd, "w" ))) {
|
||||||
|
perror( "fdopen" );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf( fp, "SyncState *\n\nMaildirStore local\nPath \"%s/\"\nAltMap %s\n\n", maildir, tb( altmap > 0 ) );
|
||||||
|
if (o2o) {
|
||||||
|
write_imap_server( fp, &global );
|
||||||
|
write_imap_store( fp, &global );
|
||||||
|
fprintf( fp, "Channel o2o\nMaster :%s:\nSlave :local:\nPattern %%\n", global.store_name );
|
||||||
|
write_channel_parm( fp, &global );
|
||||||
|
} else {
|
||||||
|
for (box = boxes; box; box = box->next) {
|
||||||
|
for (pbox = boxes; pbox != box; pbox = pbox->next) {
|
||||||
|
if (box->tunnel) {
|
||||||
|
if (mstrcmp( pbox->tunnel, box->tunnel ))
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
if (mstrcmp( pbox->host, box->host ) ||
|
||||||
|
pbox->use_imaps != box->use_imaps ||
|
||||||
|
pbox->port != box->port)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (mstrcmp( pbox->user, box->user ) ||
|
||||||
|
mstrcmp( pbox->pass, box->pass )) /* nonsense */
|
||||||
|
continue;
|
||||||
|
if ((box->use_imaps || box->use_sslv2 ||
|
||||||
|
box->use_sslv3 || box->use_tlsv1) &&
|
||||||
|
mstrcmp( pbox->cert_file, box->cert_file )) /* nonsense */
|
||||||
|
continue;
|
||||||
|
if (pbox->use_imaps != box->use_imaps ||
|
||||||
|
pbox->use_sslv2 != box->use_sslv2 ||
|
||||||
|
pbox->use_sslv3 != box->use_sslv3 ||
|
||||||
|
pbox->use_tlsv1 != box->use_tlsv1)
|
||||||
|
continue;
|
||||||
|
box->server_name = pbox->server_name;
|
||||||
|
for (sbox = boxes; sbox != box; sbox = sbox->next) {
|
||||||
|
if (sbox->server_name != box->server_name ||
|
||||||
|
mstrcmp( sbox->copy_deleted_to, box->copy_deleted_to ) ||
|
||||||
|
(!*folder && sbox->use_namespace != box->use_namespace))
|
||||||
|
continue;
|
||||||
|
box->store_name = sbox->store_name;
|
||||||
|
goto gotall;
|
||||||
|
}
|
||||||
|
box->stores = ++pbox->stores;
|
||||||
|
goto gotsrv;
|
||||||
|
}
|
||||||
|
write_imap_server( fp, box );
|
||||||
|
box->stores = 1;
|
||||||
|
gotsrv:
|
||||||
|
write_imap_store( fp, box );
|
||||||
|
gotall:
|
||||||
|
if (box->alias)
|
||||||
|
cn = box->alias;
|
||||||
|
else {
|
||||||
|
cn = strrchr( box->path, '/' );
|
||||||
|
if (cn)
|
||||||
|
cn++;
|
||||||
|
else
|
||||||
|
cn = box->path;
|
||||||
|
}
|
||||||
|
for (sbox = boxes; sbox != box; sbox = sbox->next) {
|
||||||
|
if (sbox->alias)
|
||||||
|
scn = sbox->alias;
|
||||||
|
else {
|
||||||
|
scn = strrchr( sbox->path, '/' );
|
||||||
|
if (scn)
|
||||||
|
scn++;
|
||||||
|
else
|
||||||
|
scn = sbox->path;
|
||||||
|
}
|
||||||
|
if (mstrcmp( cn, scn ))
|
||||||
|
continue;
|
||||||
|
nfasprintf( (char **)&box->channel_name, "%s-%d", cn, ++sbox->channels );
|
||||||
|
goto gotchan;
|
||||||
|
}
|
||||||
|
box->channels = 1;
|
||||||
|
box->channel_name = cn;
|
||||||
|
gotchan:
|
||||||
|
fprintf( fp, "Channel %s\nMaster :%s:%s\nSlave :local:%s\n",
|
||||||
|
box->channel_name, box->store_name, box->box, box->path );
|
||||||
|
write_channel_parm( fp, box );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose( fp );
|
||||||
|
}
|
||||||
|
|
||||||
|
config_t *
|
||||||
|
find_box( const char *s )
|
||||||
|
{
|
||||||
|
config_t *p;
|
||||||
|
char *t;
|
||||||
|
|
||||||
|
for (p = boxes; p; p = p->next) {
|
||||||
|
if (!strcmp( s, p->path ) || (p->alias && !strcmp( s, p->alias )))
|
||||||
|
return p;
|
||||||
|
/* check to see if the full pathname was specified on the
|
||||||
|
* command line.
|
||||||
|
*/
|
||||||
|
t = expand_strdup( p->path );
|
||||||
|
if (!strcmp( s, t )) {
|
||||||
|
free( t );
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
free( t );
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
259
src/compat/convert.c
Normal file
259
src/compat/convert.c
Normal file
|
@ -0,0 +1,259 @@
|
||||||
|
/*
|
||||||
|
* isync - mbsync wrapper: IMAP4 to maildir mailbox synchronizer
|
||||||
|
* Copyright (C) 2000-2002 Michael R. Elkins <me@mutt.org>
|
||||||
|
* Copyright (C) 2002-2004 Oswald Buddenhagen <ossi@users.sf.net>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "isync.h"
|
||||||
|
|
||||||
|
#include <limits.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#include <db.h>
|
||||||
|
|
||||||
|
static const char *subdirs[] = { "cur", "new", "tmp" };
|
||||||
|
|
||||||
|
static const char Flags[] = { 'D', 'F', 'R', 'S', 'T' };
|
||||||
|
|
||||||
|
static int
|
||||||
|
parse_info( const char *s )
|
||||||
|
{
|
||||||
|
unsigned i;
|
||||||
|
int flags;
|
||||||
|
|
||||||
|
flags = 0;
|
||||||
|
if (s && *(s + 1) == '2' && *(s + 2) == ',')
|
||||||
|
for (s += 3, i = 0; i < as(Flags); i++)
|
||||||
|
if (strchr( s, Flags[i] ))
|
||||||
|
flags |= (1 << i);
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int uid, flags;
|
||||||
|
} msg_t;
|
||||||
|
|
||||||
|
static int
|
||||||
|
compare_uids( const void *l, const void *r )
|
||||||
|
{
|
||||||
|
return ((msg_t *)l)->uid - ((msg_t *)r)->uid;
|
||||||
|
}
|
||||||
|
|
||||||
|
static DBT key, value;
|
||||||
|
static struct flock lck;
|
||||||
|
|
||||||
|
void
|
||||||
|
convert( config_t *box )
|
||||||
|
{
|
||||||
|
DIR *d;
|
||||||
|
struct dirent *e;
|
||||||
|
char *s, *p, *mboxdir;
|
||||||
|
FILE *fp;
|
||||||
|
msg_t *msgs;
|
||||||
|
DB *db;
|
||||||
|
int i, ret, fd, uidval, maxuid, bl, uid, rmsgs, nmsgs, uv[2];
|
||||||
|
unsigned u;
|
||||||
|
struct stat sb;
|
||||||
|
char buf[_POSIX_PATH_MAX], diumname[_POSIX_PATH_MAX],
|
||||||
|
uvname[_POSIX_PATH_MAX], sname[_POSIX_PATH_MAX],
|
||||||
|
iuvname[_POSIX_PATH_MAX], imuname[_POSIX_PATH_MAX],
|
||||||
|
ilname[_POSIX_PATH_MAX], iumname[_POSIX_PATH_MAX];
|
||||||
|
|
||||||
|
mboxdir = expand_strdup( box->path );
|
||||||
|
nfsnprintf( iuvname, sizeof(iuvname), "%s/isyncuidvalidity", mboxdir );
|
||||||
|
nfsnprintf( diumname, sizeof(iumname), "%s/.isyncuidmap.db", mboxdir );
|
||||||
|
nfsnprintf( uvname, sizeof(uvname), "%s/.uidvalidity", mboxdir );
|
||||||
|
if (stat( iuvname, &sb )) {
|
||||||
|
if (!stat( diumname, &sb ))
|
||||||
|
altmap++;
|
||||||
|
else if (!stat( uvname, &sb ))
|
||||||
|
altmap--;
|
||||||
|
err1:
|
||||||
|
free( mboxdir );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (i = 0; i < 3; i++) {
|
||||||
|
nfsnprintf( buf, sizeof(buf), "%s/%s", mboxdir, subdirs[i] );
|
||||||
|
if (stat( buf, &sb )) {
|
||||||
|
fprintf( stderr, "ERROR: stat %s: %s (errno %d)\n", buf,
|
||||||
|
strerror(errno), errno );
|
||||||
|
fprintf( stderr,
|
||||||
|
"ERROR: %s does not appear to be a valid maildir style mailbox\n",
|
||||||
|
mboxdir );
|
||||||
|
goto err1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nfsnprintf( iumname, sizeof(iumname), "%s/isyncuidmap.db", mboxdir );
|
||||||
|
nfsnprintf( imuname, sizeof(imuname), "%s/isyncmaxuid", mboxdir );
|
||||||
|
nfsnprintf( ilname, sizeof(ilname), "%s/isynclock", mboxdir );
|
||||||
|
nfsnprintf( sname, sizeof(sname), "%s/.mbsyncstate", mboxdir );
|
||||||
|
|
||||||
|
if ((fd = open( ilname, O_WRONLY|O_CREAT, 0600 )) < 0) {
|
||||||
|
perror( ilname );
|
||||||
|
goto err1;
|
||||||
|
}
|
||||||
|
#if SEEK_SET != 0
|
||||||
|
lck.l_whence = SEEK_SET;
|
||||||
|
#endif
|
||||||
|
#if F_WRLCK != 0
|
||||||
|
lck.l_type = F_WRLCK;
|
||||||
|
#endif
|
||||||
|
if (fcntl( fd, F_SETLKW, &lck )) {
|
||||||
|
perror( ilname );
|
||||||
|
err2:
|
||||||
|
close( fd );
|
||||||
|
goto err1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(fp = fopen( iuvname, "r" ))) {
|
||||||
|
perror( iuvname );
|
||||||
|
goto err2;
|
||||||
|
}
|
||||||
|
fscanf( fp, "%d", &uidval );
|
||||||
|
fclose( fp );
|
||||||
|
if (!(fp = fopen( imuname, "r" ))) {
|
||||||
|
perror( imuname );
|
||||||
|
goto err2;
|
||||||
|
}
|
||||||
|
fscanf( fp, "%d", &maxuid );
|
||||||
|
fclose( fp );
|
||||||
|
|
||||||
|
if (!stat( iumname, &sb )) {
|
||||||
|
if (db_create( &db, 0, 0 )) {
|
||||||
|
fputs( "dbcreate failed\n", stderr );
|
||||||
|
goto err2;
|
||||||
|
}
|
||||||
|
if (db->open( db, 0, iumname, 0, DB_HASH, 0, 0 )) {
|
||||||
|
fputs( "cannot open db\n", stderr );
|
||||||
|
db->close( db, 0 );
|
||||||
|
goto err2;
|
||||||
|
}
|
||||||
|
altmap++;
|
||||||
|
} else {
|
||||||
|
db = 0;
|
||||||
|
altmap--;
|
||||||
|
}
|
||||||
|
|
||||||
|
msgs = 0;
|
||||||
|
rmsgs = 0;
|
||||||
|
nmsgs = 0;
|
||||||
|
for (i = 0; i < 2; i++) {
|
||||||
|
bl = nfsnprintf( buf, sizeof(buf), "%s/%s/", mboxdir, subdirs[i] );
|
||||||
|
if (!(d = opendir( buf ))) {
|
||||||
|
perror( "opendir" );
|
||||||
|
err4:
|
||||||
|
if (msgs)
|
||||||
|
free( msgs );
|
||||||
|
if (db)
|
||||||
|
db->close( db, 0 );
|
||||||
|
goto err2;
|
||||||
|
}
|
||||||
|
while ((e = readdir( d ))) {
|
||||||
|
if (*e->d_name == '.')
|
||||||
|
continue;
|
||||||
|
s = strchr( e->d_name, ':' );
|
||||||
|
if (db) {
|
||||||
|
key.data = e->d_name;
|
||||||
|
key.size = s ? (size_t)(s - e->d_name) : strlen( e->d_name );
|
||||||
|
if ((ret = db->get( db, 0, &key, &value, 0 ))) {
|
||||||
|
if (ret != DB_NOTFOUND)
|
||||||
|
db->err( db, ret, "Maildir error: db->get()" );
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
uid = *(int *)value.data;
|
||||||
|
} else if ((p = strstr( e->d_name, ",U=" )))
|
||||||
|
uid = atoi( p + 3 );
|
||||||
|
else
|
||||||
|
continue;
|
||||||
|
if (nmsgs == rmsgs) {
|
||||||
|
rmsgs = rmsgs * 2 + 100;
|
||||||
|
msgs = nfrealloc( msgs, rmsgs * sizeof(msg_t) );
|
||||||
|
}
|
||||||
|
msgs[nmsgs].uid = uid;
|
||||||
|
msgs[nmsgs++].flags = parse_info( s );
|
||||||
|
}
|
||||||
|
closedir( d );
|
||||||
|
}
|
||||||
|
|
||||||
|
qsort( msgs, nmsgs, sizeof(msg_t), compare_uids );
|
||||||
|
|
||||||
|
if (!(fp = fopen( sname, "w" ))) {
|
||||||
|
perror( sname );
|
||||||
|
goto err4;
|
||||||
|
}
|
||||||
|
if (box->max_messages) {
|
||||||
|
if (!nmsgs)
|
||||||
|
i = maxuid;
|
||||||
|
else {
|
||||||
|
i = nmsgs - box->max_messages;
|
||||||
|
if (i < 0)
|
||||||
|
i = 0;
|
||||||
|
i = msgs[i].uid - 1;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
i = 0;
|
||||||
|
fprintf( fp, "%d:%d %d:%d:%d\n", uidval, maxuid, uidval, i, maxuid );
|
||||||
|
for (i = 0; i < nmsgs; i++) {
|
||||||
|
fprintf( fp, "%d %d ", msgs[i].uid, msgs[i].uid );
|
||||||
|
for (u = 0; u < as(Flags); u++)
|
||||||
|
if (msgs[i].flags & (1 << u))
|
||||||
|
fputc( Flags[u], fp );
|
||||||
|
fputc( '\n', fp );
|
||||||
|
}
|
||||||
|
fclose( fp );
|
||||||
|
|
||||||
|
if (db) {
|
||||||
|
key.data = (void *)"UIDVALIDITY";
|
||||||
|
key.size = 11;
|
||||||
|
uv[0] = uidval;
|
||||||
|
uv[1] = maxuid;
|
||||||
|
value.data = uv;
|
||||||
|
value.size = sizeof(uv);
|
||||||
|
if ((ret = db->put( db, 0, &key, &value, 0 ))) {
|
||||||
|
db->err( db, ret, "Maildir error: db->put()" );
|
||||||
|
goto err4;
|
||||||
|
}
|
||||||
|
db->close( db, 0 );
|
||||||
|
rename( iumname, diumname );
|
||||||
|
} else {
|
||||||
|
if (!(fp = fopen( uvname, "w" ))) {
|
||||||
|
perror( uvname );
|
||||||
|
goto err4;
|
||||||
|
}
|
||||||
|
fprintf( fp, "%d\n%d\n", uidval, maxuid );
|
||||||
|
fclose( fp );
|
||||||
|
}
|
||||||
|
|
||||||
|
unlink( iuvname );
|
||||||
|
unlink( imuname );
|
||||||
|
|
||||||
|
close( fd );
|
||||||
|
unlink( ilname );
|
||||||
|
|
||||||
|
if (msgs)
|
||||||
|
free( msgs );
|
||||||
|
free( mboxdir );
|
||||||
|
return;
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
.ig
|
.ig
|
||||||
\" isync - IMAP4 to maildir mailbox synchronizer
|
\" isync - mbsync wrapper: IMAP4 to Maildir mailbox synchronizer
|
||||||
\" Copyright (C) 2000-2002 Michael R. Elkins <me@mutt.org>
|
\" Copyright (C) 2000-2002 Michael R. Elkins <me@mutt.org>
|
||||||
|
\" Copyright (C) 2002-2004 Oswald Buddenhagen <ossi@users.sf.net>
|
||||||
\"
|
\"
|
||||||
\" This program is free software; you can redistribute it and/or modify
|
\" This program is free software; you can redistribute it and/or modify
|
||||||
\" it under the terms of the GNU General Public License as published by
|
\" it under the terms of the GNU General Public License as published by
|
||||||
|
@ -16,26 +17,27 @@
|
||||||
\" along with this program; if not, write to the Free Software
|
\" along with this program; if not, write to the Free Software
|
||||||
\" Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
\" Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
\"
|
\"
|
||||||
\" As a special exception, isync may be linked with the OpenSSL library,
|
|
||||||
\" despite that library's more restrictive license.
|
|
||||||
..
|
..
|
||||||
.TH isync 1 "2002 Dec 22"
|
.TH isync 1 "2004 Mar 27"
|
||||||
..
|
..
|
||||||
.SH NAME
|
.SH NAME
|
||||||
isync - synchronize IMAP4 and maildir mailboxes
|
isync - synchronize IMAP4 and Maildir mailboxes
|
||||||
..
|
..
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
\fBisync\fR [\fIoptions...\fR] \fImailbox\fR [\fImailbox ...\fR]
|
\fBisync\fR [\fIoptions\fR ...] {\fImailbox\fR ...|\fI-a\fR|\fI-l\fR}
|
||||||
.br
|
|
||||||
\fBisync\fR [\fIoptions...\fR] \fI-a\fR
|
|
||||||
.br
|
|
||||||
\fBisync\fR [\fIoptions...\fR] \fI-l\fR
|
|
||||||
..
|
..
|
||||||
.SH DESCRIPTION
|
.SH DESCRIPTION
|
||||||
\fBisync\fR is a command line application which synchronizes a local
|
\fBisync\fR is a command line application which synchronizes local
|
||||||
maildir-style mailbox with a remote IMAP4 mailbox, suitable for use in
|
Maildir mailboxes with remote IMAP4 mailboxes, suitable for use in
|
||||||
IMAP-disconnected mode. Multiple copies of the remote IMAP4 mailbox can
|
IMAP-disconnected mode. Multiple copies of the remote IMAP4 mailboxes can
|
||||||
be maintained, and all flags are synchronized.
|
be maintained, and all flags are synchronized.
|
||||||
|
.br
|
||||||
|
\fBisync\fR is only a wrapper binary around \fBmbsync\fR to simplify upgrades.
|
||||||
|
It will automatically migrate the UID mapping from previous versions of
|
||||||
|
\fBisync\fR (even before 0.8) to the new format, and transparently call
|
||||||
|
\fBmbsync\fR. If you were using \fBisync\fR version 0.8 or 0.9.x you might
|
||||||
|
want to use \fBmdconvert\fR to convert the mailboxes to the more efficient
|
||||||
|
\fBnative\fR UID storage scheme after migrating them.
|
||||||
..
|
..
|
||||||
.SH OPTIONS
|
.SH OPTIONS
|
||||||
.TP
|
.TP
|
||||||
|
@ -60,7 +62,7 @@ Synchronize all mailboxes (either specified in ~/.isyncrc or determined by the
|
||||||
Don't synchronize anything, but list all mailboxes and exit.
|
Don't synchronize anything, but list all mailboxes and exit.
|
||||||
.TP
|
.TP
|
||||||
\fB-L\fR, \fB--create-local\fR
|
\fB-L\fR, \fB--create-local\fR
|
||||||
Automatically create the local maildir-style mailbox if it doesn't already
|
Automatically create the local Maildir mailbox if it doesn't already
|
||||||
exist.
|
exist.
|
||||||
.TP
|
.TP
|
||||||
\fB-R\fR, \fB--create-remote\fR
|
\fB-R\fR, \fB--create-remote\fR
|
||||||
|
@ -71,25 +73,23 @@ Automatically create any mailboxes if they don't already exist.
|
||||||
This is simply a combination of -L and -R.
|
This is simply a combination of -L and -R.
|
||||||
.TP
|
.TP
|
||||||
\fB-d\fR, \fB--delete\fR
|
\fB-d\fR, \fB--delete\fR
|
||||||
Causes \fBisync\fR to delete messages from the local maildir mailbox
|
Causes \fBisync\fR to propagate message deletions.
|
||||||
which do not exist on the IMAP server. By default, \fIdead\fR messages
|
By default, \fIdead\fR messages are \fBnot\fR deleted.
|
||||||
are \fBnot\fR deleted.
|
|
||||||
.TP
|
.TP
|
||||||
\fB-e\fR, \fB--expunge\fR
|
\fB-e\fR, \fB--expunge\fR
|
||||||
Causes \fBisync\fR to permanently remove all messages marked for deletion
|
Causes \fBisync\fR to permanently remove all messages marked for deletion.
|
||||||
in both the local maildir mailbox and the remote IMAP mailbox. By default,
|
By default, \fIdeleted\fR messages are \fBnot\fR expunged.
|
||||||
\fIdeleted\fR messages are \fBnot\fR expunged.
|
|
||||||
.TP
|
.TP
|
||||||
\fB-f\fR, \fB--fast\fR
|
\fB-f\fR, \fB--fast\fR
|
||||||
Causes \fBisync\fR to skip the step of synchronzing message flags between the
|
Only fetch new messages existing on the server into the local mailbox.
|
||||||
local maildir mailbox and the IMAP mailbox. Only new messages existing on the
|
Message deletions and flag changes will not be propagated.
|
||||||
server will be fetched into the local mailbox.
|
|
||||||
.TP
|
.TP
|
||||||
\fB-h\fR, \fB--help\fR
|
\fB-h\fR, \fB--help\fR
|
||||||
Displays a summary of command line options
|
Displays a summary of command line options
|
||||||
.TP
|
.TP
|
||||||
\fB-p\fR, \fB--port\fR \fIport\fR
|
\fB-p\fR, \fB--port\fR \fIport\fR
|
||||||
Specifies the port on the IMAP server to connect to (default: 143)
|
Specifies the port on the IMAP server to connect to (default: 143 for imap,
|
||||||
|
993 for imaps)
|
||||||
.TP
|
.TP
|
||||||
\fB-q\fR, \fB--quiet\fR
|
\fB-q\fR, \fB--quiet\fR
|
||||||
Suppress informational messages.
|
Suppress informational messages.
|
||||||
|
@ -99,7 +99,7 @@ If specified twice, suppress warning messages as well.
|
||||||
Specifies the name of the remote IMAP mailbox to synchronize with
|
Specifies the name of the remote IMAP mailbox to synchronize with
|
||||||
(Default: INBOX)
|
(Default: INBOX)
|
||||||
.TP
|
.TP
|
||||||
\fB-s\fR, \fB--host\fR \fB[\fRimaps:\fB]\fR\fIhost\fR
|
\fB-s\fR, \fB--host\fR [\fBimaps:\fR]\fIhost\fR
|
||||||
Specifies the hostname of the IMAP server
|
Specifies the hostname of the IMAP server
|
||||||
.TP
|
.TP
|
||||||
\fB-u\fR, \fB--user\fR \fIuser\fR
|
\fB-u\fR, \fB--user\fR \fIuser\fR
|
||||||
|
@ -116,32 +116,49 @@ Displays \fBisync\fR version information.
|
||||||
.TP
|
.TP
|
||||||
\fB-V\fR, \fB--verbose\fR
|
\fB-V\fR, \fB--verbose\fR
|
||||||
Enables \fIverbose\fR mode, which displays the IMAP4 network traffic.
|
Enables \fIverbose\fR mode, which displays the IMAP4 network traffic.
|
||||||
|
.TP
|
||||||
|
\fB-D\fR, \fB--debug\fR
|
||||||
|
Enable printing of \fIdebug\fR messages.
|
||||||
|
.TP
|
||||||
|
\fB-w\fR, \fB--write\fR
|
||||||
|
Don't run \fBmbsync\fR, but instead write a permanent config file for it.
|
||||||
|
The UID mappings of all configured mailboxes will be migrated.
|
||||||
|
Note that some command line options that would affect an actual sync operation
|
||||||
|
will be incorporated into the new config file as well.
|
||||||
|
The name of the new config file is determined by replacing the last occurrence
|
||||||
|
of "isync" with "mbsync", or appending ".mbsync" if "isync" was not found.
|
||||||
|
.TP
|
||||||
|
\fB-W\fR, \fB--writeto\fR \fIfile\fR
|
||||||
|
Like \fB-w\fR, but use the specified name for the new config file.
|
||||||
..
|
..
|
||||||
.SH CONFIGURATION
|
.SH CONFIGURATION
|
||||||
\fBisync\fR reads \fI~/.isyncrc\fR to load default configuration data.
|
\fBisync\fR by default reads \fI~/.isyncrc\fR to load configuration data.
|
||||||
Each line of the configuration file consists of a command.
|
Each non-empty line of the configuration file that does not start with a
|
||||||
|
hash mark consists of a command.
|
||||||
The following commands are understood:
|
The following commands are understood:
|
||||||
.TP
|
.TP
|
||||||
\fBMailbox\fR \fIpath\fR
|
\fBMailbox\fR \fIpath\fR
|
||||||
Defines a local maildir mailbox. All configuration commands following this
|
Defines a local Maildir mailbox. All configuration commands following this
|
||||||
line, up until the next \fIMailbox\fR command, apply to this mailbox only.
|
line, up until the next \fIMailbox\fR command, apply to this mailbox only.
|
||||||
..
|
..
|
||||||
.TP
|
.TP
|
||||||
\fBHost\fR \fB[\fRimaps:\fB]\fR\fIname\fR
|
\fBHost\fR [\fBimaps:\fR]\fIname\fR
|
||||||
Defines the DNS name or IP address of the IMAP server. If the hostname is
|
Defines the DNS name or IP address of the IMAP server. If the hostname is
|
||||||
prefixed with \fIimaps:\fR the connection is assumed to be a SSL connection
|
prefixed with \fBimaps:\fR the connection is assumed to be a SSL connection
|
||||||
to port 993 (though you can change this by placing a \fBPort\fR command
|
to port 993 (though you can change this by placing a \fBPort\fR command
|
||||||
\fBafter\fR the \fBHost\fR command. Note that some servers support SSL on
|
\fBafter\fR the \fBHost\fR command).
|
||||||
the default port 143. \fBisync\fR will always attempt to use SSL if available.
|
Note that modern servers support SSL on the default port 143.
|
||||||
|
\fBisync\fR will always attempt to use SSL if available.
|
||||||
..
|
..
|
||||||
.TP
|
.TP
|
||||||
\fBPort\fR \fIport\fR
|
\fBPort\fR \fIport\fR
|
||||||
Defines the TCP port number on the IMAP server to use (Default: 143)
|
Defines the TCP port number of the IMAP server (Default: 143 for imap,
|
||||||
|
993 for imaps)
|
||||||
..
|
..
|
||||||
.TP
|
.TP
|
||||||
\fBBox\fR \fImailbox\fR
|
\fBBox\fR \fImailbox\fR
|
||||||
Defines the name of the remote IMAP mailbox associated with the local
|
Defines the name of the remote IMAP mailbox associated with the local
|
||||||
maildir mailbox (Default: INBOX)
|
Maildir mailbox (Default: INBOX)
|
||||||
..
|
..
|
||||||
.TP
|
.TP
|
||||||
\fBUser\fR \fIusername\fR
|
\fBUser\fR \fIusername\fR
|
||||||
|
@ -161,19 +178,18 @@ command line.
|
||||||
..
|
..
|
||||||
.TP
|
.TP
|
||||||
\fBCopyDeletedTo\fR \fImailbox\fR
|
\fBCopyDeletedTo\fR \fImailbox\fR
|
||||||
Specifies the remote IMAP mailbox to copy deleted messages prior to
|
Specifies the remote IMAP mailbox to copy deleted messages to prior to
|
||||||
expunging (Default: none).
|
expunging (Default: none).
|
||||||
..
|
..
|
||||||
.TP
|
.TP
|
||||||
\fBDelete\fR \fIyes\fR|\fIno\fR
|
\fBDelete\fR \fIyes\fR|\fIno\fR
|
||||||
Specifies whether messages in the local copy of the mailbox which don't
|
Specifies whether message deletions are propagated. (Default: no).
|
||||||
exist on the server are automatically deleted. (Default: no).
|
|
||||||
\fBNOTE:\fR The \fI-d\fR command line option overrides this setting when
|
\fBNOTE:\fR The \fI-d\fR command line option overrides this setting when
|
||||||
set to \fIno\fR.
|
set to \fIno\fR.
|
||||||
..
|
..
|
||||||
.TP
|
.TP
|
||||||
\fBExpunge\fR \fIyes\fR|\fIno\fR
|
\fBExpunge\fR \fIyes\fR|\fIno\fR
|
||||||
Specifies whether deleted messages are expunged by default (Default: no).
|
Specifies whether deleted messages are expunged. (Default: no).
|
||||||
\fBNOTE:\fR The \fI-e\fR command line option overrides this setting when
|
\fBNOTE:\fR The \fI-e\fR command line option overrides this setting when
|
||||||
set to \fIno\fR.
|
set to \fIno\fR.
|
||||||
..
|
..
|
||||||
|
@ -181,7 +197,7 @@ set to \fIno\fR.
|
||||||
\fBMailDir\fR \fIdirectory\fR
|
\fBMailDir\fR \fIdirectory\fR
|
||||||
Specifies the location of your local mailboxes if a relative path is
|
Specifies the location of your local mailboxes if a relative path is
|
||||||
specified in a \fIMailbox\fR command (Default: \fI~\fR).
|
specified in a \fIMailbox\fR command (Default: \fI~\fR).
|
||||||
\fBNOTE:\fR This directive is only meaningful in the \fIglobal\fR
|
\fBNOTE:\fR This directive is allowed only in the \fIglobal\fR
|
||||||
section (see below).
|
section (see below).
|
||||||
..
|
..
|
||||||
.TP
|
.TP
|
||||||
|
@ -190,28 +206,28 @@ Specifies the location of your IMAP mailboxes
|
||||||
specified in \fIBox\fR commands (Default: \fI""\fR).
|
specified in \fIBox\fR commands (Default: \fI""\fR).
|
||||||
\fBNOTE:\fR You \fBmust\fR append the hierarchy delimiter (usually
|
\fBNOTE:\fR You \fBmust\fR append the hierarchy delimiter (usually
|
||||||
a slash) to this specification.
|
a slash) to this specification.
|
||||||
\fBNOTE 2:\fR This directive is only meaningful in the \fIglobal\fR
|
\fBNOTE 2:\fR This directive is allowed only in the \fIglobal\fR
|
||||||
section (see below).
|
section (see below).
|
||||||
..
|
..
|
||||||
.TP
|
.TP
|
||||||
\fBMaxMessages\fR \fIcount\fR
|
\fBMaxMessages\fR \fIcount\fR
|
||||||
Sets the number of messages \fBisync\fR should keep in a mailbox.
|
Sets the number of messages \fBisync\fR should keep in the local copy of a
|
||||||
This is useful for mailboxes where you keep a complete archive on the
|
mailbox.
|
||||||
server, but want to mirror only the last messages (for instance, for mailing
|
This is useful for mailboxes where you keep a complete archive on the server,
|
||||||
lists.)
|
but want to mirror only the last messages (for instance, for mailing lists).
|
||||||
The messages that were the first to arrive in the mailbox (independent of the
|
The messages that were the first to arrive in the mailbox (independently of the
|
||||||
actual date of the message) will automatically be deleted if you
|
actual date of the message) will be deleted first.
|
||||||
pass \fBisync\fR the delete (-d, --delete) flag.
|
Messages that are flagged (marked as important) and recent messages will not be
|
||||||
Messages that are flagged (marked as important) will not be automatically
|
automatically deleted.
|
||||||
deleted.
|
If \fIcount\fR is 0, the maximum number of messages is \fBunlimited\fR.
|
||||||
If \fIcount\fR is 0, the maximum number of messages is \fBunlimited\fR
|
(Default: 0)
|
||||||
(Default: 0).
|
|
||||||
..
|
..
|
||||||
.TP
|
.TP
|
||||||
\fBMaxSize\fR \fIbytes\fR
|
\fBMaxSize\fR \fIbytes\fR
|
||||||
Sets a threshold for the maximum message size (in bytes) for which \fBisync\fR
|
Messages larger than that many bytes will not be transferred over the wire.
|
||||||
should transfer over the wire. This is useful for weeding out messages with
|
This is useful for weeding out messages with large attachments.
|
||||||
large attachments. If \fIbytes\fR is 0, the maximum file size is \fBunlimited\fR.
|
If \fIbytes\fR is 0, the maximum file size is \fBunlimited\fR.
|
||||||
|
(Default: 0)
|
||||||
..
|
..
|
||||||
.TP
|
.TP
|
||||||
\fBTunnel\fR \fIcommand\fR
|
\fBTunnel\fR \fIcommand\fR
|
||||||
|
@ -220,19 +236,20 @@ socket. This allows you to run an IMAP session over an SSH tunnel, for
|
||||||
example.
|
example.
|
||||||
.TP
|
.TP
|
||||||
\fBUseNamespace\fR \fIyes\fR|\fIno\fR
|
\fBUseNamespace\fR \fIyes\fR|\fIno\fR
|
||||||
Selects whether \fBisync\fR should select mailboxes using the namespace given
|
Selects whether the server's first "personal" NAMESPACE should be prefixed to
|
||||||
by the NAMESPACE command. This is useful with broken IMAP servers. (Default:
|
mailbox names. Disabling this makes sense for some broken IMAP servers.
|
||||||
\fIyes\fR)
|
This option is meaningless if a \fIFolder\fR was specified.
|
||||||
|
(Default: \fIyes\fR)
|
||||||
..
|
..
|
||||||
.TP
|
.TP
|
||||||
\fBRequireCRAM\fR \fIyes\fR|\fIno\fR
|
\fBRequireCRAM\fR \fIyes\fR|\fIno\fR
|
||||||
If set to \fIyes\fR, \fBisync\fR will require that the server accept CRAM-MD5
|
If set to \fIyes\fR, \fBisync\fR will abort the connection if no CRAM-MD5
|
||||||
intead of PLAIN to authenticate the user.
|
authentication is possible. (Default: \fIno\fR)
|
||||||
..
|
..
|
||||||
.TP
|
.TP
|
||||||
\fBRequireSSL\fR \fIyes\fR|\fIno\fR
|
\fBRequireSSL\fR \fIyes\fR|\fIno\fR
|
||||||
\fBisync\fR will abort the connection if a TLS/SSL session to the IMAP
|
\fBisync\fR will abort the connection if a TLS/SSL session cannot be
|
||||||
server can not be established. (Default: \fIyes\fR)
|
established with the IMAP server. (Default: \fIyes\fR)
|
||||||
..
|
..
|
||||||
.TP
|
.TP
|
||||||
\fBCertificateFile\fR \fIpath\fR
|
\fBCertificateFile\fR \fIpath\fR
|
||||||
|
@ -258,7 +275,7 @@ Should \fBisync\fR use TLSv1 for communication with the IMAP server over SSL?
|
||||||
\fBisync\fR will ignore any \fIMailbox\fR specifications and instead pick up
|
\fBisync\fR will ignore any \fIMailbox\fR specifications and instead pick up
|
||||||
all mailboxes from the local \fIMailDir\fR and remote \fIFolder\fR and map
|
all mailboxes from the local \fIMailDir\fR and remote \fIFolder\fR and map
|
||||||
them 1:1 onto each other according to their names.
|
them 1:1 onto each other according to their names.
|
||||||
\fBNOTE:\fR This directive is only meaningful in the \fIglobal\fR
|
\fBNOTE:\fR This directive is allowed only in the \fIglobal\fR
|
||||||
section (see below).
|
section (see below).
|
||||||
..
|
..
|
||||||
.TP
|
.TP
|
||||||
|
@ -278,63 +295,20 @@ the first \fBMailbox\fR command, and then leave out the \fBUser\fR command
|
||||||
in the sections for each mailbox.
|
in the sections for each mailbox.
|
||||||
\fBisync\fR will then use the global value by default.
|
\fBisync\fR will then use the global value by default.
|
||||||
..
|
..
|
||||||
.SH MAIL USER AGENT INTERACTION
|
|
||||||
To use \fBisync\fR effectively, you need a mail client that sets the T
|
|
||||||
(trashed) flag when it deletes a message from a maildir mailbox, instead of
|
|
||||||
just removing it altogether. Without such a client, \fBisync\fR will refetch the
|
|
||||||
locally deleted messages from the server since they will never get expunged.
|
|
||||||
Mutt (starting with version 1.3.27) is known to support this. Be sure to put
|
|
||||||
.IP "" 2
|
|
||||||
set maildir_trash
|
|
||||||
.PP
|
|
||||||
in your ~/.muttrc when using Mutt.
|
|
||||||
.br
|
|
||||||
\fBisync\fR can be integrated into Mutt fairly easily with a few hooks:
|
|
||||||
.IP "" 2
|
|
||||||
.nf
|
|
||||||
folder-hook ~A bind index $ <sync-mailbox>
|
|
||||||
.br
|
|
||||||
folder-hook +\fImdir\fR 'macro index $ "<sync-mailbox>!isync -e \fImdir\fR\\n"'
|
|
||||||
.fi
|
|
||||||
.PP
|
|
||||||
where \fImdir\fR is the name of the local mailbox (or its \fIalias\fR).
|
|
||||||
This works well so long as you are not modifying the IMAP mailbox outside of
|
|
||||||
Mutt. However, if you are using another mail program simultaneously Mutt
|
|
||||||
will have the wrong idea of the local mailbox flags and messages will start
|
|
||||||
disappearing from its index display (don't worry, they are still on disk).
|
|
||||||
..
|
|
||||||
.SH FILES
|
.SH FILES
|
||||||
.TP
|
.TP
|
||||||
.B ~/.isyncrc
|
.B ~/.isyncrc
|
||||||
Default configuration file
|
Default configuration file
|
||||||
..
|
..
|
||||||
.SH BUGS
|
.SH BUGS
|
||||||
No support for IMAP subfolders.
|
|
||||||
.P
|
|
||||||
\fBisync\fR does not use NFS-safe locking. It will correctly prevent
|
|
||||||
concurrent synchronization of a mailbox on the same host, but not across NFS.
|
|
||||||
.P
|
|
||||||
When synchronizing multiple mailboxes on the same IMAP server, it is not
|
|
||||||
possible to select different SSL options for each mailbox. Only the options
|
|
||||||
from the first mailbox are applied since the SSL session is reused.
|
|
||||||
.P
|
|
||||||
If new mail arrives in the IMAP mailbox after \fBisync\fR
|
|
||||||
has retrieved the initial message list, the new mail will not be fetched
|
|
||||||
until the next time \fBisync\fR is invoked.
|
|
||||||
.P
|
|
||||||
It is currently impossible to unset the \\Flagged attribute of a message
|
|
||||||
once it is set. It has to be manually unset everywhere since isync
|
|
||||||
doesn't have enough information to know which was the last status of the
|
|
||||||
message.
|
|
||||||
.P
|
|
||||||
The ndbm database created for each mailbox is not portable across different
|
|
||||||
architectures. It currently stores the UID in host byte order.
|
|
||||||
.P
|
|
||||||
The configuration file takes precedence over command line options.
|
The configuration file takes precedence over command line options.
|
||||||
.br
|
.br
|
||||||
Use -c /dev/null to work around.
|
Use -c /dev/null to work around.
|
||||||
|
.P
|
||||||
|
See the \fBINHERENT PROBLEMS\fR section in the \fBmbsync\fR man page, too.
|
||||||
|
..
|
||||||
.SH SEE ALSO
|
.SH SEE ALSO
|
||||||
mutt(1), maildir(5)
|
mbsync(1), mdconvert(1), mutt(1), maildir(5)
|
||||||
.P
|
.P
|
||||||
Up to date information on \fBisync\fR can be found at http://isync.sf.net/
|
Up to date information on \fBisync\fR can be found at http://isync.sf.net/
|
||||||
..
|
..
|
100
src/compat/isync.h
Normal file
100
src/compat/isync.h
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
/*
|
||||||
|
* isync - mbsync wrapper: IMAP4 to maildir mailbox synchronizer
|
||||||
|
* Copyright (C) 2000-2002 Michael R. Elkins <me@mutt.org>
|
||||||
|
* Copyright (C) 2002-2004 Oswald Buddenhagen <ossi@users.sf.net>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
#define as(ar) (sizeof(ar)/sizeof(ar[0]))
|
||||||
|
|
||||||
|
#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4)
|
||||||
|
# define ATTR_UNUSED __attribute__((unused))
|
||||||
|
# define ATTR_NORETURN __attribute__((noreturn))
|
||||||
|
# define ATTR_PRINTFLIKE(fmt,var) __attribute__((format(printf,fmt,var)))
|
||||||
|
#else
|
||||||
|
# define ATTR_UNUSED
|
||||||
|
# define ATTR_NORETURN
|
||||||
|
# define ATTR_PRINTFLIKE(fmt,var)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct config {
|
||||||
|
struct config *next;
|
||||||
|
|
||||||
|
const char *server_name;
|
||||||
|
int servers;
|
||||||
|
char *host;
|
||||||
|
int port;
|
||||||
|
char *user;
|
||||||
|
char *pass;
|
||||||
|
char *tunnel;
|
||||||
|
unsigned int require_cram:1;
|
||||||
|
unsigned int require_ssl:1;
|
||||||
|
unsigned int use_imaps:1;
|
||||||
|
unsigned int use_sslv2:1;
|
||||||
|
unsigned int use_sslv3:1;
|
||||||
|
unsigned int use_tlsv1:1;
|
||||||
|
char *cert_file;
|
||||||
|
|
||||||
|
const char *store_name;
|
||||||
|
int stores;
|
||||||
|
char *copy_deleted_to;
|
||||||
|
unsigned int use_namespace:1;
|
||||||
|
|
||||||
|
const char *channel_name;
|
||||||
|
int channels;
|
||||||
|
const char *alias;
|
||||||
|
const char *box;
|
||||||
|
const char *path; /* path relative to .maildir, or absolute path */
|
||||||
|
int max_size;
|
||||||
|
unsigned int max_messages;
|
||||||
|
unsigned int expunge:1;
|
||||||
|
unsigned int delete:1;
|
||||||
|
} config_t;
|
||||||
|
|
||||||
|
extern int Quiet, Verbose, Debug;
|
||||||
|
|
||||||
|
extern const char *Home;
|
||||||
|
|
||||||
|
extern config_t global, *boxes;
|
||||||
|
|
||||||
|
extern const char *maildir, *xmaildir, *folder, *inbox;
|
||||||
|
extern int o2o, altmap;
|
||||||
|
|
||||||
|
/* config.c */
|
||||||
|
void load_config( const char *, config_t *** );
|
||||||
|
void write_config( int );
|
||||||
|
char *expand_strdup( const char * );
|
||||||
|
config_t *find_box( const char * );
|
||||||
|
|
||||||
|
/* convert.c */
|
||||||
|
void convert( config_t * );
|
||||||
|
|
||||||
|
/* util.c */
|
||||||
|
char *next_arg( char ** );
|
||||||
|
void *nfmalloc( size_t sz );
|
||||||
|
void *nfrealloc( void *mem, size_t sz );
|
||||||
|
char *nfstrdup( const char *str );
|
||||||
|
int nfvasprintf( char **str, const char *fmt, va_list va );
|
||||||
|
int nfasprintf( char **str, const char *fmt, ... );
|
||||||
|
int nfsnprintf( char *buf, int blen, const char *fmt, ... );
|
||||||
|
void ATTR_NORETURN oob( void );
|
431
src/compat/main.c
Normal file
431
src/compat/main.c
Normal file
|
@ -0,0 +1,431 @@
|
||||||
|
/*
|
||||||
|
* isync - mbsync wrapper: IMAP4 to maildir mailbox synchronizer
|
||||||
|
* Copyright (C) 2000-2002 Michael R. Elkins <me@mutt.org>
|
||||||
|
* Copyright (C) 2002-2004 Oswald Buddenhagen <ossi@users.sf.net>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "isync.h"
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <pwd.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
|
||||||
|
#if HAVE_GETOPT_LONG
|
||||||
|
# define _GNU_SOURCE
|
||||||
|
# include <getopt.h>
|
||||||
|
struct option Opts[] = {
|
||||||
|
{"write", 0, NULL, 'w' },
|
||||||
|
{"writeto", 0, NULL, 'W' },
|
||||||
|
{"all", 0, NULL, 'a' },
|
||||||
|
{"list", 0, NULL, 'l'},
|
||||||
|
{"config", 1, NULL, 'c'},
|
||||||
|
{"create", 0, NULL, 'C'},
|
||||||
|
{"create-local", 0, NULL, 'L'},
|
||||||
|
{"create-remote", 0, NULL, 'R'},
|
||||||
|
{"delete", 0, NULL, 'd'},
|
||||||
|
{"expunge", 0, NULL, 'e'},
|
||||||
|
{"fast", 0, NULL, 'f'},
|
||||||
|
{"help", 0, NULL, 'h'},
|
||||||
|
{"remote", 1, NULL, 'r'},
|
||||||
|
{"folder", 1, NULL, 'F'},
|
||||||
|
{"maildir", 1, NULL, 'M'},
|
||||||
|
{"one-to-one", 0, NULL, '1'},
|
||||||
|
{"inbox", 1, NULL, 'I'},
|
||||||
|
{"host", 1, NULL, 's'},
|
||||||
|
{"port", 1, NULL, 'p'},
|
||||||
|
{"debug", 0, NULL, 'D'},
|
||||||
|
{"quiet", 0, NULL, 'q'},
|
||||||
|
{"user", 1, NULL, 'u'},
|
||||||
|
{"version", 0, NULL, 'v'},
|
||||||
|
{"verbose", 0, NULL, 'V'},
|
||||||
|
{0, 0, 0, 0}
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void
|
||||||
|
version( void )
|
||||||
|
{
|
||||||
|
puts( PACKAGE " " VERSION );
|
||||||
|
exit( 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
usage( int code )
|
||||||
|
{
|
||||||
|
fputs(
|
||||||
|
PACKAGE " " VERSION " - mbsync wrapper: IMAP4 to maildir synchronizer\n"
|
||||||
|
"Copyright (C) 2000-2002 Michael R. Elkins <me@mutt.org>\n"
|
||||||
|
"Copyright (C) 2002-2004 Oswald Buddenhagen <ossi@users.sf.net>\n"
|
||||||
|
"usage:\n"
|
||||||
|
" " PACKAGE " [ flags ] mailbox [mailbox ...]\n"
|
||||||
|
" " PACKAGE " [ flags ] -a\n"
|
||||||
|
" " PACKAGE " [ flags ] -l\n"
|
||||||
|
" -a, --all synchronize all defined mailboxes\n"
|
||||||
|
" -l, --list list all defined mailboxes and exit\n"
|
||||||
|
" -L, --create-local create local maildir mailbox if nonexistent\n"
|
||||||
|
" -R, --create-remote create remote imap mailbox if nonexistent\n"
|
||||||
|
" -C, --create create both local and remote mailboxes if nonexistent\n"
|
||||||
|
" -d, --delete delete local msgs that don't exist on the server\n"
|
||||||
|
" -e, --expunge expunge deleted messages\n"
|
||||||
|
" -f, --fast only fetch new messages\n"
|
||||||
|
" -r, --remote BOX remote mailbox\n"
|
||||||
|
" -F, --folder DIR remote IMAP folder containing mailboxes\n"
|
||||||
|
" -M, --maildir DIR local directory containing mailboxes\n"
|
||||||
|
" -1, --one-to-one map every IMAP <folder>/box to <maildir>/box\n"
|
||||||
|
" -I, --inbox BOX map IMAP INBOX to <maildir>/BOX (exception to -1)\n"
|
||||||
|
" -s, --host HOST IMAP server address\n"
|
||||||
|
" -p, --port PORT server IMAP port\n"
|
||||||
|
" -u, --user USER IMAP user name\n"
|
||||||
|
" -c, --config CONFIG read an alternate config file (default: ~/.isyncrc)\n"
|
||||||
|
" -D, --debug print debugging messages\n"
|
||||||
|
" -V, --verbose verbose mode (display network traffic)\n"
|
||||||
|
" -q, --quiet don't display progress info\n"
|
||||||
|
" -v, --version display version\n"
|
||||||
|
" -h, --help display this help message\n\n"
|
||||||
|
"Note that this is a wrapper binary only; the \"real\" isync is named \"mbsync\".\n"
|
||||||
|
"Options to permanently transform your old isync configuration:\n"
|
||||||
|
" -w, --write write permanent mbsync configuration\n"
|
||||||
|
" -W, --writeto FILE write permanent mbsync configuration to FILE\n",
|
||||||
|
code ? stderr : stdout );
|
||||||
|
exit( code );
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *
|
||||||
|
strrstr( const char *h, const char *n )
|
||||||
|
{
|
||||||
|
char *p = strstr( h, n );
|
||||||
|
if (!p)
|
||||||
|
return 0;
|
||||||
|
do {
|
||||||
|
h = p;
|
||||||
|
p = strstr( h + 1, n );
|
||||||
|
} while (p);
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
add_arg( char ***args, const char *arg )
|
||||||
|
{
|
||||||
|
int nu = 0;
|
||||||
|
if (*args)
|
||||||
|
for (; (*args)[nu]; nu++);
|
||||||
|
*args = nfrealloc( *args, sizeof(char *) * (nu + 2));
|
||||||
|
(*args)[nu] = nfstrdup( arg );
|
||||||
|
(*args)[nu + 1] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define OP_EXPUNGE (1<<0)
|
||||||
|
#define OP_DELETE (1<<1)
|
||||||
|
#define OP_FAST (1<<2)
|
||||||
|
#define OP_CREATE_REMOTE (1<<3)
|
||||||
|
#define OP_CREATE_LOCAL (1<<4)
|
||||||
|
|
||||||
|
int Quiet, Verbose, Debug;
|
||||||
|
config_t global, *boxes;
|
||||||
|
const char *maildir, *xmaildir, *folder, *inbox;
|
||||||
|
int o2o, altmap;
|
||||||
|
|
||||||
|
const char *Home;
|
||||||
|
|
||||||
|
int
|
||||||
|
main( int argc, char **argv )
|
||||||
|
{
|
||||||
|
config_t *box, **stor;
|
||||||
|
char *config = 0, *outconfig = 0, **args;
|
||||||
|
int i, pl, fd, mod, all, list, ops, writeout;
|
||||||
|
struct stat st;
|
||||||
|
char path1[_POSIX_PATH_MAX], path2[_POSIX_PATH_MAX];
|
||||||
|
|
||||||
|
if (!(Home = getenv("HOME"))) {
|
||||||
|
fputs( "Fatal: $HOME not set\n", stderr );
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* defaults */
|
||||||
|
/* XXX the precedence is borked:
|
||||||
|
it's defaults < cmdline < file instead of defaults < file < cmdline */
|
||||||
|
global.port = 143;
|
||||||
|
global.box = "INBOX";
|
||||||
|
global.use_namespace = 1;
|
||||||
|
global.require_ssl = 1;
|
||||||
|
global.use_tlsv1 = 1;
|
||||||
|
folder = "";
|
||||||
|
maildir = "~";
|
||||||
|
xmaildir = Home;
|
||||||
|
|
||||||
|
#define FLAGS "wW:alCLRc:defhp:qu:r:F:M:1I:s:vVD"
|
||||||
|
|
||||||
|
mod = all = list = ops = writeout = Quiet = Verbose = Debug = 0;
|
||||||
|
#if HAVE_GETOPT_LONG
|
||||||
|
while ((i = getopt_long( argc, argv, FLAGS, Opts, NULL )) != -1)
|
||||||
|
#else
|
||||||
|
while ((i = getopt( argc, argv, FLAGS )) != -1)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
switch (i) {
|
||||||
|
case 'W':
|
||||||
|
outconfig = optarg;
|
||||||
|
/* plopp */
|
||||||
|
case 'w':
|
||||||
|
writeout = 1;
|
||||||
|
break;
|
||||||
|
case 'l':
|
||||||
|
list = 1;
|
||||||
|
/* plopp */
|
||||||
|
case 'a':
|
||||||
|
all = 1;
|
||||||
|
break;
|
||||||
|
case '1':
|
||||||
|
o2o = 1;
|
||||||
|
mod = 1;
|
||||||
|
break;
|
||||||
|
case 'C':
|
||||||
|
ops |= OP_CREATE_REMOTE|OP_CREATE_LOCAL;
|
||||||
|
break;
|
||||||
|
case 'L':
|
||||||
|
ops |= OP_CREATE_LOCAL;
|
||||||
|
break;
|
||||||
|
case 'R':
|
||||||
|
ops |= OP_CREATE_REMOTE;
|
||||||
|
break;
|
||||||
|
case 'c':
|
||||||
|
config = optarg;
|
||||||
|
break;
|
||||||
|
case 'd':
|
||||||
|
ops |= OP_DELETE;
|
||||||
|
break;
|
||||||
|
case 'e':
|
||||||
|
ops |= OP_EXPUNGE;
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
ops |= OP_FAST;
|
||||||
|
break;
|
||||||
|
case 'p':
|
||||||
|
global.port = atoi( optarg );
|
||||||
|
mod = 1;
|
||||||
|
break;
|
||||||
|
case 'r':
|
||||||
|
global.box = optarg;
|
||||||
|
mod = 1;
|
||||||
|
break;
|
||||||
|
case 'F':
|
||||||
|
folder = optarg;
|
||||||
|
mod = 1;
|
||||||
|
break;
|
||||||
|
case 'M':
|
||||||
|
maildir = optarg;
|
||||||
|
mod = 1;
|
||||||
|
break;
|
||||||
|
case 'I':
|
||||||
|
inbox = optarg;
|
||||||
|
mod = 1;
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
#if HAVE_LIBSSL
|
||||||
|
if (!strncasecmp( "imaps:", optarg, 6 )) {
|
||||||
|
global.use_imaps = 1;
|
||||||
|
global.port = 993;
|
||||||
|
global.use_sslv2 = 1;
|
||||||
|
global.use_sslv3 = 1;
|
||||||
|
optarg += 6;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
global.host = optarg;
|
||||||
|
mod = 1;
|
||||||
|
break;
|
||||||
|
case 'u':
|
||||||
|
global.user = optarg;
|
||||||
|
mod = 1;
|
||||||
|
break;
|
||||||
|
case 'D':
|
||||||
|
Debug = 1;
|
||||||
|
break;
|
||||||
|
case 'V':
|
||||||
|
Verbose = 1;
|
||||||
|
break;
|
||||||
|
case 'q':
|
||||||
|
Quiet++;
|
||||||
|
break;
|
||||||
|
case 'v':
|
||||||
|
version();
|
||||||
|
case 'h':
|
||||||
|
usage( 0 );
|
||||||
|
default:
|
||||||
|
usage( 1 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config) {
|
||||||
|
if (*config != '/') {
|
||||||
|
if (!getcwd( path1, sizeof(path1) )) {
|
||||||
|
fprintf( stderr, "Can't obtain working directory\n" );
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
pl = strlen( path1 );
|
||||||
|
nfsnprintf( path1 + pl, sizeof(path1) - pl, "/%s", config );
|
||||||
|
config = path1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
nfsnprintf( path1, sizeof(path1), "%s/.isyncrc", Home );
|
||||||
|
config = path1;
|
||||||
|
}
|
||||||
|
stor = &boxes;
|
||||||
|
load_config( config, &stor );
|
||||||
|
|
||||||
|
if (!all && !o2o)
|
||||||
|
for (i = optind; argv[i]; i++)
|
||||||
|
if (!(box = find_box( argv[i] ))) {
|
||||||
|
box = nfmalloc( sizeof(config_t) );
|
||||||
|
memcpy( box, &global, sizeof(config_t) );
|
||||||
|
box->path = argv[i];
|
||||||
|
*stor = box;
|
||||||
|
stor = &box->next;
|
||||||
|
mod = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (writeout) {
|
||||||
|
all = 1;
|
||||||
|
if (mod)
|
||||||
|
fprintf( stderr,
|
||||||
|
"Warning: command line switches that influence the resulting config file\n"
|
||||||
|
"have been supplied.\n" );
|
||||||
|
} else {
|
||||||
|
if (!argv[optind] && !all) {
|
||||||
|
fprintf( stderr, "No mailbox specified. Try isync -h\n" );
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (all) {
|
||||||
|
if (o2o) {
|
||||||
|
DIR * dir;
|
||||||
|
struct dirent *de;
|
||||||
|
|
||||||
|
if (!(dir = opendir( xmaildir ))) {
|
||||||
|
fprintf( stderr, "%s: %s\n", xmaildir, strerror(errno) );
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
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 ))
|
||||||
|
continue;
|
||||||
|
global.path = de->d_name;
|
||||||
|
global.box = (inbox && !strcmp( inbox, global.path )) ?
|
||||||
|
"INBOX" : global.path;
|
||||||
|
convert( &global );
|
||||||
|
}
|
||||||
|
closedir( dir );
|
||||||
|
} else
|
||||||
|
for (box = boxes; box; box = box->next)
|
||||||
|
convert( box );
|
||||||
|
} else {
|
||||||
|
for (i = optind; argv[i]; i++)
|
||||||
|
if (o2o) {
|
||||||
|
global.path = argv[i];
|
||||||
|
global.box =
|
||||||
|
(inbox && !strcmp( global.path, inbox )) ?
|
||||||
|
"INBOX" : global.path;
|
||||||
|
convert( &global );
|
||||||
|
} else
|
||||||
|
convert( find_box( argv[i] ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
if (writeout) {
|
||||||
|
if (!outconfig) {
|
||||||
|
const char *p = strrchr( config, '/' );
|
||||||
|
if (!p)
|
||||||
|
p = config;
|
||||||
|
p = strrstr( p, "isync" );
|
||||||
|
if (!p)
|
||||||
|
nfsnprintf( path2, sizeof(path2), "%s.mbsync", config );
|
||||||
|
else
|
||||||
|
nfsnprintf( path2, sizeof(path2), "%.*smb%s", p - config, config, p + 1 );
|
||||||
|
outconfig = path2;
|
||||||
|
}
|
||||||
|
if ((fd = creat( outconfig, 0666 )) < 0) {
|
||||||
|
fprintf( stderr, "Error: cannot write new config %s: %s\n", outconfig, strerror(errno) );
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
strcpy( path2, "/tmp/mbsyncrcXXXXXX" );
|
||||||
|
if ((fd = mkstemp( path2 )) < 0) {
|
||||||
|
fprintf( stderr, "Can't create temp file\n" );
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
write_config( fd );
|
||||||
|
|
||||||
|
if (writeout)
|
||||||
|
return 0;
|
||||||
|
args = 0;
|
||||||
|
add_arg( &args, "mbsync" );
|
||||||
|
if (Verbose)
|
||||||
|
add_arg( &args, "-V" );
|
||||||
|
if (Debug)
|
||||||
|
add_arg( &args, "-D" );
|
||||||
|
for (; Quiet; Quiet--)
|
||||||
|
add_arg( &args, "-q" );
|
||||||
|
add_arg( &args, "-cT" );
|
||||||
|
add_arg( &args, path2 );
|
||||||
|
if (ops & OP_FAST)
|
||||||
|
add_arg( &args, "-Ln" );
|
||||||
|
else if (!(ops & OP_DELETE))
|
||||||
|
add_arg( &args, "-nNf" );
|
||||||
|
if (ops & OP_CREATE_REMOTE)
|
||||||
|
add_arg( &args, "-Cm" );
|
||||||
|
if (ops & OP_CREATE_LOCAL)
|
||||||
|
add_arg( &args, "-Cs" );
|
||||||
|
if (ops & OP_EXPUNGE)
|
||||||
|
add_arg( &args, "-X" );
|
||||||
|
if (list)
|
||||||
|
add_arg( &args, "-l" );
|
||||||
|
if (o2o) {
|
||||||
|
if (all)
|
||||||
|
add_arg( &args, "o2o" );
|
||||||
|
else {
|
||||||
|
char buf[1024];
|
||||||
|
strcpy( buf, "o2o:" );
|
||||||
|
strcat( buf, argv[optind] );
|
||||||
|
while (argv[++optind]) {
|
||||||
|
strcat( buf, "," );
|
||||||
|
strcat( buf, argv[optind] );
|
||||||
|
}
|
||||||
|
add_arg( &args, buf );
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (all)
|
||||||
|
add_arg( &args, "-a" );
|
||||||
|
else
|
||||||
|
for (; argv[optind]; optind++)
|
||||||
|
add_arg( &args, find_box( argv[optind] )->channel_name );
|
||||||
|
}
|
||||||
|
execvp( args[0], args );
|
||||||
|
perror( args[0] );
|
||||||
|
return 1;
|
||||||
|
}
|
156
src/compat/util.c
Normal file
156
src/compat/util.c
Normal file
|
@ -0,0 +1,156 @@
|
||||||
|
/*
|
||||||
|
* isync - mbsync wrapper: IMAP4 to maildir mailbox synchronizer
|
||||||
|
* Copyright (C) 2000-2002 Michael R. Elkins <me@mutt.org>
|
||||||
|
* Copyright (C) 2002-2004 Oswald Buddenhagen <ossi@users.sf.net>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "isync.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <pwd.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
char *
|
||||||
|
next_arg( char **s )
|
||||||
|
{
|
||||||
|
char *ret;
|
||||||
|
|
||||||
|
if (!s || !*s)
|
||||||
|
return 0;
|
||||||
|
while (isspace( (unsigned char) **s ))
|
||||||
|
(*s)++;
|
||||||
|
if (!**s) {
|
||||||
|
*s = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (**s == '"') {
|
||||||
|
++*s;
|
||||||
|
ret = *s;
|
||||||
|
*s = strchr( *s, '"' );
|
||||||
|
} else {
|
||||||
|
ret = *s;
|
||||||
|
while (**s && !isspace( (unsigned char) **s ))
|
||||||
|
(*s)++;
|
||||||
|
}
|
||||||
|
if (*s) {
|
||||||
|
if (**s)
|
||||||
|
*(*s)++ = 0;
|
||||||
|
if (!**s)
|
||||||
|
*s = 0;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef HAVE_VASPRINTF
|
||||||
|
static int
|
||||||
|
vasprintf( char **strp, const char *fmt, va_list ap )
|
||||||
|
{
|
||||||
|
int len;
|
||||||
|
char tmp[1024];
|
||||||
|
|
||||||
|
if ((len = vsnprintf( tmp, sizeof(tmp), fmt, ap) ) < 0)
|
||||||
|
*strp = 0;
|
||||||
|
else if ((*strp = malloc( len + 1 ))) {
|
||||||
|
if (len >= sizeof(tmp))
|
||||||
|
vsprintf( *strp, fmt, ap );
|
||||||
|
else
|
||||||
|
memcpy( *strp, tmp, len + 1 );
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void
|
||||||
|
oob( void )
|
||||||
|
{
|
||||||
|
fputs( "Fatal: buffer too small. Please report a bug.\n", stderr );
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
nfsnprintf( char *buf, int blen, const char *fmt, ... )
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
va_list va;
|
||||||
|
|
||||||
|
va_start( va, fmt );
|
||||||
|
if (blen <= 0 || (unsigned)(ret = vsnprintf( buf, blen, fmt, va )) >= (unsigned)blen)
|
||||||
|
oob();
|
||||||
|
va_end( va );
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ATTR_NORETURN
|
||||||
|
oom( void )
|
||||||
|
{
|
||||||
|
fputs( "Fatal: Out of memory\n", stderr );
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
nfmalloc( size_t sz )
|
||||||
|
{
|
||||||
|
void *ret;
|
||||||
|
|
||||||
|
if (!(ret = malloc( sz )))
|
||||||
|
oom();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
nfrealloc( void *mem, size_t sz )
|
||||||
|
{
|
||||||
|
char *ret;
|
||||||
|
|
||||||
|
if (!(ret = realloc( mem, sz )) && sz)
|
||||||
|
oom();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
nfstrdup( const char *str )
|
||||||
|
{
|
||||||
|
char *ret;
|
||||||
|
|
||||||
|
if (!(ret = strdup( str )))
|
||||||
|
oom();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
nfvasprintf( char **str, const char *fmt, va_list va )
|
||||||
|
{
|
||||||
|
int ret = vasprintf( str, fmt, va );
|
||||||
|
if (!*str)
|
||||||
|
oom();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
nfasprintf( char **str, const char *fmt, ... )
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
va_list va;
|
||||||
|
|
||||||
|
va_start( va, fmt );
|
||||||
|
ret = nfvasprintf( str, fmt, va );
|
||||||
|
va_end( va );
|
||||||
|
return ret;
|
||||||
|
}
|
632
src/config.c
632
src/config.c
|
@ -1,8 +1,7 @@
|
||||||
/* $Id$
|
/*
|
||||||
*
|
* mbsync - mailbox synchronizer
|
||||||
* isync - IMAP4 to maildir mailbox synchronizer
|
|
||||||
* Copyright (C) 2000-2002 Michael R. Elkins <me@mutt.org>
|
* Copyright (C) 2000-2002 Michael R. Elkins <me@mutt.org>
|
||||||
* Copyright (C) 2002-2003 Oswald Buddenhagen <ossi@users.sf.net>
|
* Copyright (C) 2002-2004 Oswald Buddenhagen <ossi@users.sf.net>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -18,7 +17,7 @@
|
||||||
* along with this program; if not, write to the Free Software
|
* along with this program; if not, write to the Free Software
|
||||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*
|
*
|
||||||
* As a special exception, isync may be linked with the OpenSSL library,
|
* As a special exception, mbsync may be linked with the OpenSSL library,
|
||||||
* despite that library's more restrictive license.
|
* despite that library's more restrictive license.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -33,254 +32,411 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
config_t *boxes = 0;
|
store_conf_t *stores;
|
||||||
|
channel_conf_t *channels;
|
||||||
|
group_conf_t *groups;
|
||||||
|
int global_mops, global_sops;
|
||||||
|
char *global_sync_state;
|
||||||
|
|
||||||
/* set defaults from the global configuration section */
|
int
|
||||||
static void
|
parse_bool( conffile_t *cfile )
|
||||||
config_defaults (config_t * conf)
|
|
||||||
{
|
{
|
||||||
memcpy (conf, &global, sizeof (config_t));
|
if (!strcasecmp( cfile->val, "yes" ) ||
|
||||||
}
|
!strcasecmp( cfile->val, "true" ) ||
|
||||||
|
!strcasecmp( cfile->val, "on" ) ||
|
||||||
static char *
|
!strcmp( cfile->val, "1" ))
|
||||||
my_strndup (const char *s, size_t nchars)
|
return 1;
|
||||||
{
|
if (strcasecmp( cfile->val, "no" ) &&
|
||||||
char *r = malloc (sizeof (char) * (nchars + 1));
|
strcasecmp( cfile->val, "false" ) &&
|
||||||
if (r)
|
strcasecmp( cfile->val, "off" ) &&
|
||||||
{
|
strcmp( cfile->val, "0" ))
|
||||||
memcpy (r, s, nchars);
|
fprintf( stderr, "%s:%d: invalid boolean value '%s'\n",
|
||||||
r[nchars] = 0;
|
cfile->file, cfile->line, cfile->val );
|
||||||
}
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *
|
|
||||||
expand_strdup (const char *s)
|
|
||||||
{
|
|
||||||
char path[_POSIX_PATH_MAX];
|
|
||||||
struct passwd *pw;
|
|
||||||
const char *p;
|
|
||||||
|
|
||||||
if (*s == '~')
|
|
||||||
{
|
|
||||||
s++;
|
|
||||||
if (*s == '/')
|
|
||||||
{
|
|
||||||
/* current user */
|
|
||||||
pw = getpwuid (getuid ());
|
|
||||||
p = s + 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
char *user;
|
|
||||||
|
|
||||||
p = strchr (s, '/');
|
|
||||||
if (p)
|
|
||||||
{
|
|
||||||
user = my_strndup (s, (int)(p - s));
|
|
||||||
p++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
user = strdup (s);
|
|
||||||
pw = getpwnam (user);
|
|
||||||
free (user);
|
|
||||||
}
|
|
||||||
if (!pw)
|
|
||||||
return 0;
|
return 0;
|
||||||
snprintf (path, sizeof (path), "%s/%s", pw->pw_dir, p ? p : "");
|
|
||||||
s = path;
|
|
||||||
}
|
}
|
||||||
else if (*s != '/')
|
|
||||||
|
int
|
||||||
|
parse_int( conffile_t *cfile )
|
||||||
{
|
{
|
||||||
snprintf (path, sizeof (path), "%s/%s",
|
char *p;
|
||||||
global.maildir ? global.maildir : "", s);
|
int ret;
|
||||||
s = path;
|
|
||||||
|
ret = strtol( cfile->val, &p, 10 );
|
||||||
|
if (*p) {
|
||||||
|
fprintf( stderr, "%s:%d: invalid integer value '%s'\n",
|
||||||
|
cfile->file, cfile->line, cfile->val );
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
return strdup (s);
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
parse_size( conffile_t *cfile )
|
||||||
|
{
|
||||||
|
char *p;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = strtol (cfile->val, &p, 10);
|
||||||
|
if (*p == 'k' || *p == 'K')
|
||||||
|
ret *= 1024, p++;
|
||||||
|
else if (*p == 'm' || *p == 'M')
|
||||||
|
ret *= 1024 * 1024, p++;
|
||||||
|
if (*p == 'b' || *p == 'B')
|
||||||
|
p++;
|
||||||
|
if (*p) {
|
||||||
|
fprintf (stderr, "%s:%d: invalid size '%s'\n",
|
||||||
|
cfile->file, cfile->line, cfile->val);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
is_true (const char *val)
|
getopt_helper( conffile_t *cfile, int *cops, int *mops, int *sops, char **sync_state )
|
||||||
{
|
{
|
||||||
return
|
char *arg;
|
||||||
!strcasecmp (val, "yes") ||
|
|
||||||
!strcasecmp (val, "true") ||
|
|
||||||
!strcasecmp (val, "on") ||
|
|
||||||
!strcmp (val, "1");
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
if (!strcasecmp( "Sync", cfile->cmd )) {
|
||||||
load_config (const char *where, int *o2o)
|
arg = cfile->val;
|
||||||
{
|
do
|
||||||
char path[_POSIX_PATH_MAX];
|
if (!strcasecmp( "Push", arg ))
|
||||||
char buf[1024];
|
*cops |= XOP_PUSH;
|
||||||
struct passwd *pw;
|
else if (!strcasecmp( "Pull", arg ))
|
||||||
config_t **stor = &boxes, *cfg;
|
*cops |= XOP_PULL;
|
||||||
int line = 0;
|
else if (!strcasecmp( "ReNew", arg ))
|
||||||
FILE *fp;
|
*cops |= OP_RENEW;
|
||||||
char *p, *cmd, *val;
|
else if (!strcasecmp( "New", arg ))
|
||||||
|
*cops |= OP_NEW;
|
||||||
if (!where)
|
else if (!strcasecmp( "Delete", arg ))
|
||||||
{
|
*cops |= OP_DELETE;
|
||||||
pw = getpwuid (getuid ());
|
else if (!strcasecmp( "Flags", arg ))
|
||||||
snprintf (path, sizeof (path), "%s/.isyncrc", pw->pw_dir);
|
*cops |= OP_FLAGS;
|
||||||
where = path;
|
else if (!strcasecmp( "PullReNew", arg ))
|
||||||
}
|
*sops |= OP_RENEW;
|
||||||
|
else if (!strcasecmp( "PullNew", arg ))
|
||||||
info ("Reading configuration file %s\n", where);
|
*sops |= OP_NEW;
|
||||||
|
else if (!strcasecmp( "PullDelete", arg ))
|
||||||
fp = fopen (where, "r");
|
*sops |= OP_DELETE;
|
||||||
if (!fp)
|
else if (!strcasecmp( "PullFlags", arg ))
|
||||||
{
|
*sops |= OP_FLAGS;
|
||||||
if (errno != ENOENT)
|
else if (!strcasecmp( "PushReNew", arg ))
|
||||||
perror ("fopen");
|
*mops |= OP_RENEW;
|
||||||
return;
|
else if (!strcasecmp( "PushNew", arg ))
|
||||||
}
|
*mops |= OP_NEW;
|
||||||
buf[sizeof buf - 1] = 0;
|
else if (!strcasecmp( "PushDelete", arg ))
|
||||||
cfg = &global;
|
*mops |= OP_DELETE;
|
||||||
while ((fgets (buf, sizeof (buf) - 1, fp)))
|
else if (!strcasecmp( "PushFlags", arg ))
|
||||||
{
|
*mops |= OP_FLAGS;
|
||||||
p = buf;
|
else if (!strcasecmp( "All", arg ) || !strcasecmp( "Full", arg ))
|
||||||
cmd = next_arg (&p);
|
*cops |= XOP_PULL|XOP_PUSH;
|
||||||
val = next_arg (&p);
|
else if (strcasecmp( "None", arg ) && strcasecmp( "Noop", arg ))
|
||||||
line++;
|
fprintf( stderr, "%s:%d: invalid Sync arg '%s'\n",
|
||||||
if (!cmd || *cmd == '#')
|
cfile->file, cfile->line, arg );
|
||||||
continue;
|
while ((arg = next_arg( &cfile->rest )));
|
||||||
if (!val) {
|
*mops |= XOP_HAVE_TYPE;
|
||||||
fprintf (stderr, "%s:%d: parameter missing\n", path, line);
|
} else if (!strcasecmp( "Expunge", cfile->cmd )) {
|
||||||
continue;
|
arg = cfile->val;
|
||||||
}
|
do
|
||||||
if (!strcasecmp ("mailbox", cmd))
|
if (!strcasecmp( "Both", arg ))
|
||||||
{
|
*cops |= OP_EXPUNGE;
|
||||||
if (*o2o)
|
else if (!strcasecmp( "Master", arg ))
|
||||||
break;
|
*mops |= OP_EXPUNGE;
|
||||||
cfg = *stor = malloc (sizeof (config_t));
|
else if (!strcasecmp( "Slave", arg ))
|
||||||
stor = &cfg->next;
|
*sops |= OP_EXPUNGE;
|
||||||
config_defaults (cfg);
|
else if (strcasecmp( "None", arg ))
|
||||||
/* not expanded at this point */
|
fprintf( stderr, "%s:%d: invalid Expunge arg '%s'\n",
|
||||||
cfg->path = strdup (val);
|
cfile->file, cfile->line, arg );
|
||||||
}
|
while ((arg = next_arg( &cfile->rest )));
|
||||||
else if (!strcasecmp ("OneToOne", cmd))
|
*mops |= XOP_HAVE_EXPUNGE;
|
||||||
{
|
} else if (!strcasecmp( "Create", cfile->cmd )) {
|
||||||
if (boxes) {
|
arg = cfile->val;
|
||||||
forbid:
|
do
|
||||||
fprintf (stderr,
|
if (!strcasecmp( "Both", arg ))
|
||||||
"%s:%d: keyword '%s' allowed only in global section\n",
|
*cops |= OP_CREATE;
|
||||||
path, line, cmd);
|
else if (!strcasecmp( "Master", arg ))
|
||||||
continue;
|
*mops |= OP_CREATE;
|
||||||
}
|
else if (!strcasecmp( "Slave", arg ))
|
||||||
*o2o = is_true (val);
|
*sops |= OP_CREATE;
|
||||||
}
|
else if (strcasecmp( "None", arg ))
|
||||||
else if (!strcasecmp ("maildir", cmd))
|
fprintf( stderr, "%s:%d: invalid Create arg '%s'\n",
|
||||||
{
|
cfile->file, cfile->line, arg );
|
||||||
if (boxes)
|
while ((arg = next_arg( &cfile->rest )));
|
||||||
goto forbid;
|
*mops |= XOP_HAVE_CREATE;
|
||||||
/* this only affects the global setting */
|
} else if (!strcasecmp( "SyncState", cfile->cmd ))
|
||||||
global.maildir = expand_strdup (val);
|
*sync_state = expand_strdup( cfile->val );
|
||||||
}
|
|
||||||
else if (!strcasecmp ("folder", cmd))
|
|
||||||
{
|
|
||||||
if (boxes)
|
|
||||||
goto forbid;
|
|
||||||
/* this only affects the global setting */
|
|
||||||
global.folder = strdup (val);
|
|
||||||
}
|
|
||||||
else if (!strcasecmp ("inbox", cmd))
|
|
||||||
{
|
|
||||||
if (boxes)
|
|
||||||
goto forbid;
|
|
||||||
/* this only affects the global setting */
|
|
||||||
global.inbox = strdup (val);
|
|
||||||
}
|
|
||||||
else if (!strcasecmp ("host", cmd))
|
|
||||||
{
|
|
||||||
#if HAVE_LIBSSL
|
|
||||||
if (!strncasecmp ("imaps:", val, 6))
|
|
||||||
{
|
|
||||||
val += 6;
|
|
||||||
cfg->use_imaps = 1;
|
|
||||||
cfg->port = 993;
|
|
||||||
cfg->use_sslv2 = 1;
|
|
||||||
cfg->use_sslv3 = 1;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
cfg->host = strdup (val);
|
|
||||||
}
|
|
||||||
else if (!strcasecmp ("user", cmd))
|
|
||||||
cfg->user = strdup (val);
|
|
||||||
else if (!strcasecmp ("pass", cmd))
|
|
||||||
cfg->pass = strdup (val);
|
|
||||||
else if (!strcasecmp ("port", cmd))
|
|
||||||
cfg->port = atoi (val);
|
|
||||||
else if (!strcasecmp ("box", cmd))
|
|
||||||
cfg->box = strdup (val);
|
|
||||||
else if (!strcasecmp ("alias", cmd))
|
|
||||||
{
|
|
||||||
if (!boxes) {
|
|
||||||
fprintf (stderr,
|
|
||||||
"%s:%d: keyword 'alias' allowed only in mailbox specification\n",
|
|
||||||
path, line);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
cfg->alias = strdup (val);
|
|
||||||
}
|
|
||||||
else if (!strcasecmp ("maxsize", cmd))
|
|
||||||
cfg->max_size = atol (val);
|
|
||||||
else if (!strcasecmp ("MaxMessages", cmd))
|
|
||||||
cfg->max_messages = atol (val);
|
|
||||||
else if (!strcasecmp ("UseNamespace", cmd))
|
|
||||||
cfg->use_namespace = is_true (val);
|
|
||||||
else if (!strcasecmp ("CopyDeletedTo", cmd))
|
|
||||||
cfg->copy_deleted_to = strdup (val);
|
|
||||||
else if (!strcasecmp ("Tunnel", cmd))
|
|
||||||
cfg->tunnel = strdup (val);
|
|
||||||
else if (!strcasecmp ("Expunge", cmd))
|
|
||||||
cfg->expunge = is_true (val);
|
|
||||||
else if (!strcasecmp ("Delete", cmd))
|
|
||||||
cfg->delete = is_true (val);
|
|
||||||
#if HAVE_LIBSSL
|
|
||||||
else if (!strcasecmp ("CertificateFile", cmd))
|
|
||||||
cfg->cert_file = expand_strdup (val);
|
|
||||||
else if (!strcasecmp ("RequireSSL", cmd))
|
|
||||||
cfg->require_ssl = is_true (val);
|
|
||||||
else if (!strcasecmp ("UseSSLv2", cmd))
|
|
||||||
cfg->use_sslv2 = is_true (val);
|
|
||||||
else if (!strcasecmp ("UseSSLv3", cmd))
|
|
||||||
cfg->use_sslv3 = is_true (val);
|
|
||||||
else if (!strcasecmp ("UseTLSv1", cmd))
|
|
||||||
cfg->use_tlsv1 = is_true (val);
|
|
||||||
else if (!strcasecmp ("RequireCRAM", cmd))
|
|
||||||
cfg->require_cram = is_true (val);
|
|
||||||
#endif
|
|
||||||
else if (buf[0])
|
|
||||||
fprintf (stderr, "%s:%d: unknown keyword '%s'\n", path, line, cmd);
|
|
||||||
}
|
|
||||||
fclose (fp);
|
|
||||||
}
|
|
||||||
|
|
||||||
config_t *
|
|
||||||
find_box (const char *s)
|
|
||||||
{
|
|
||||||
config_t *p = boxes;
|
|
||||||
|
|
||||||
for (; p; p = p->next)
|
|
||||||
{
|
|
||||||
if (!strcmp (s, p->path) || (p->alias && !strcmp (s, p->alias)))
|
|
||||||
return p;
|
|
||||||
else
|
else
|
||||||
{
|
return 0;
|
||||||
/* check to see if the full pathname was specified on the
|
return 1;
|
||||||
* command line.
|
}
|
||||||
*/
|
|
||||||
char *t = expand_strdup (p->path);
|
|
||||||
|
|
||||||
if (!strcmp (s, t))
|
int
|
||||||
|
getcline( conffile_t *cfile )
|
||||||
{
|
{
|
||||||
free (t);
|
char *p;
|
||||||
return p;
|
|
||||||
}
|
while (fgets( cfile->buf, cfile->bufl, cfile->fp )) {
|
||||||
free (t);
|
cfile->line++;
|
||||||
|
p = cfile->buf;
|
||||||
|
if (!(cfile->cmd = next_arg( &p )))
|
||||||
|
return 1;
|
||||||
|
if (*cfile->cmd == '#')
|
||||||
|
continue;
|
||||||
|
if (!(cfile->val = next_arg( &p ))) {
|
||||||
|
fprintf( stderr, "%s:%d: parameter missing\n",
|
||||||
|
cfile->file, cfile->line );
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
cfile->rest = p;
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* XXX - this does not detect None conflicts ... */
|
||||||
|
int
|
||||||
|
merge_ops( int cops, int *mops, int *sops )
|
||||||
|
{
|
||||||
|
int aops;
|
||||||
|
|
||||||
|
aops = *mops | *sops;
|
||||||
|
if (*mops & XOP_HAVE_TYPE) {
|
||||||
|
if (aops & OP_MASK_TYPE) {
|
||||||
|
if (aops & cops & OP_MASK_TYPE) {
|
||||||
|
cfl:
|
||||||
|
fprintf( stderr, "Conflicting Sync args specified.\n" );
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
*mops |= cops & OP_MASK_TYPE;
|
||||||
|
*sops |= cops & OP_MASK_TYPE;
|
||||||
|
if (cops & XOP_PULL) {
|
||||||
|
if (*sops & OP_MASK_TYPE)
|
||||||
|
goto cfl;
|
||||||
|
*sops |= OP_MASK_TYPE;
|
||||||
|
}
|
||||||
|
if (cops & XOP_PUSH) {
|
||||||
|
if (*mops & OP_MASK_TYPE)
|
||||||
|
goto cfl;
|
||||||
|
*mops |= OP_MASK_TYPE;
|
||||||
|
}
|
||||||
|
} else if (cops & (OP_MASK_TYPE|XOP_MASK_DIR)) {
|
||||||
|
if (!(cops & OP_MASK_TYPE))
|
||||||
|
cops |= OP_MASK_TYPE;
|
||||||
|
else if (!(cops & XOP_MASK_DIR))
|
||||||
|
cops |= XOP_PULL|XOP_PUSH;
|
||||||
|
if (cops & XOP_PULL)
|
||||||
|
*sops |= cops & OP_MASK_TYPE;
|
||||||
|
if (cops & XOP_PUSH)
|
||||||
|
*mops |= cops & OP_MASK_TYPE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (*mops & XOP_HAVE_EXPUNGE) {
|
||||||
|
if (aops & cops & OP_EXPUNGE) {
|
||||||
|
fprintf( stderr, "Conflicting Expunge args specified.\n" );
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
*mops |= cops & OP_EXPUNGE;
|
||||||
|
*sops |= cops & OP_EXPUNGE;
|
||||||
|
}
|
||||||
|
if (*mops & XOP_HAVE_CREATE) {
|
||||||
|
if (aops & cops & OP_CREATE) {
|
||||||
|
fprintf( stderr, "Conflicting Create args specified.\n" );
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
*mops |= cops & OP_CREATE;
|
||||||
|
*sops |= cops & OP_CREATE;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
load_config( const char *where, int pseudo )
|
||||||
|
{
|
||||||
|
conffile_t cfile;
|
||||||
|
store_conf_t *store, **storeapp = &stores, **sptarg;
|
||||||
|
channel_conf_t *channel, **channelapp = &channels;
|
||||||
|
group_conf_t *group, **groupapp = &groups;
|
||||||
|
string_list_t *chanlist, **chanlistapp;
|
||||||
|
char *arg, *p, **ntarg;
|
||||||
|
int err, len, cops, gcops, max_size;
|
||||||
|
char path[_POSIX_PATH_MAX];
|
||||||
|
char buf[1024];
|
||||||
|
|
||||||
|
if (!where) {
|
||||||
|
nfsnprintf( path, sizeof(path), "%s/." EXE "rc", Home );
|
||||||
|
cfile.file = path;
|
||||||
|
} else
|
||||||
|
cfile.file = where;
|
||||||
|
|
||||||
|
if (!pseudo)
|
||||||
|
info( "Reading configuration file %s\n", cfile.file );
|
||||||
|
|
||||||
|
if (!(cfile.fp = fopen( cfile.file, "r" ))) {
|
||||||
|
perror( "Cannot open config file" );
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
buf[sizeof(buf) - 1] = 0;
|
||||||
|
cfile.buf = buf;
|
||||||
|
cfile.bufl = sizeof(buf) - 1;
|
||||||
|
cfile.line = 0;
|
||||||
|
|
||||||
|
gcops = err = 0;
|
||||||
|
reloop:
|
||||||
|
while (getcline( &cfile )) {
|
||||||
|
if (!cfile.cmd)
|
||||||
|
continue;
|
||||||
|
if (imap_driver.parse_store( &cfile, &store, &err ) ||
|
||||||
|
maildir_driver.parse_store( &cfile, &store, &err ))
|
||||||
|
{
|
||||||
|
if (store) {
|
||||||
|
if (!store->path)
|
||||||
|
store->path = "";
|
||||||
|
*storeapp = store;
|
||||||
|
storeapp = &store->next;
|
||||||
|
*storeapp = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!strcasecmp( "Channel", cfile.cmd ))
|
||||||
|
{
|
||||||
|
channel = nfcalloc( sizeof(*channel) );
|
||||||
|
channel->name = nfstrdup( cfile.val );
|
||||||
|
cops = 0;
|
||||||
|
max_size = -1;
|
||||||
|
while (getcline( &cfile ) && cfile.cmd) {
|
||||||
|
if (!strcasecmp( "MaxSize", cfile.cmd ))
|
||||||
|
max_size = parse_size( &cfile );
|
||||||
|
else if (!strcasecmp( "MaxMessages", cfile.cmd ))
|
||||||
|
channel->max_messages = parse_int( &cfile );
|
||||||
|
else if (!strcasecmp( "Pattern", cfile.cmd ) ||
|
||||||
|
!strcasecmp( "Patterns", cfile.cmd ))
|
||||||
|
{
|
||||||
|
arg = cfile.val;
|
||||||
|
do
|
||||||
|
add_string_list( &channel->patterns, arg );
|
||||||
|
while ((arg = next_arg( &cfile.rest )));
|
||||||
|
}
|
||||||
|
else if (!strcasecmp( "Master", cfile.cmd )) {
|
||||||
|
sptarg = &channel->master;
|
||||||
|
ntarg = &channel->master_name;
|
||||||
|
goto linkst;
|
||||||
|
} else if (!strcasecmp( "Slave", cfile.cmd )) {
|
||||||
|
sptarg = &channel->slave;
|
||||||
|
ntarg = &channel->slave_name;
|
||||||
|
linkst:
|
||||||
|
if (*cfile.val != ':' || !(p = strchr( cfile.val + 1, ':' ))) {
|
||||||
|
fprintf( stderr, "%s:%d: malformed mailbox spec\n",
|
||||||
|
cfile.file, cfile.line );
|
||||||
|
err = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
*p = 0;
|
||||||
|
for (store = stores; store; store = store->next)
|
||||||
|
if (!strcmp( store->name, cfile.val + 1 )) {
|
||||||
|
memset( sptarg, 0, sizeof(*sptarg) );
|
||||||
|
*sptarg = store;
|
||||||
|
goto stpcom;
|
||||||
|
}
|
||||||
|
fprintf( stderr, "%s:%d: unknown store '%s'\n",
|
||||||
|
cfile.file, cfile.line, cfile.val + 1 );
|
||||||
|
err = 1;
|
||||||
|
continue;
|
||||||
|
stpcom:
|
||||||
|
if (*++p)
|
||||||
|
*ntarg = nfstrdup( p );
|
||||||
|
} else if (!getopt_helper( &cfile, &cops, &channel->mops, &channel->sops, &channel->sync_state )) {
|
||||||
|
fprintf( stderr, "%s:%d: unknown keyword '%s'\n",
|
||||||
|
cfile.file, cfile.line, cfile.cmd );
|
||||||
|
err = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!channel->master) {
|
||||||
|
fprintf( stderr, "channel '%s' refers to no master store\n", channel->name );
|
||||||
|
err = 1;
|
||||||
|
} else if (!channel->slave) {
|
||||||
|
fprintf( stderr, "channel '%s' refers to no slave store\n", channel->name );
|
||||||
|
err = 1;
|
||||||
|
} else if (merge_ops( cops, &channel->mops, &channel->sops ))
|
||||||
|
err = 1;
|
||||||
|
else {
|
||||||
|
if (max_size >= 0)
|
||||||
|
channel->master->max_size = channel->slave->max_size = max_size;
|
||||||
|
*channelapp = channel;
|
||||||
|
channelapp = &channel->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!strcasecmp( "Group", cfile.cmd ))
|
||||||
|
{
|
||||||
|
group = nfmalloc( sizeof(*group) );
|
||||||
|
group->name = nfstrdup( cfile.val );
|
||||||
|
*groupapp = group;
|
||||||
|
groupapp = &group->next;
|
||||||
|
*groupapp = 0;
|
||||||
|
chanlistapp = &group->channels;
|
||||||
|
*chanlistapp = 0;
|
||||||
|
p = cfile.rest;
|
||||||
|
while ((arg = next_arg( &p ))) {
|
||||||
|
addone:
|
||||||
|
len = strlen( arg );
|
||||||
|
chanlist = nfmalloc( sizeof(*chanlist) + len );
|
||||||
|
memcpy( chanlist->string, arg, len + 1 );
|
||||||
|
*chanlistapp = chanlist;
|
||||||
|
chanlistapp = &chanlist->next;
|
||||||
|
*chanlistapp = 0;
|
||||||
|
}
|
||||||
|
while (getcline( &cfile )) {
|
||||||
|
if (!cfile.cmd)
|
||||||
|
goto reloop;
|
||||||
|
if (!strcasecmp( "Channel", cfile.cmd ) ||
|
||||||
|
!strcasecmp( "Channels", cfile.cmd ))
|
||||||
|
{
|
||||||
|
p = cfile.rest;
|
||||||
|
arg = cfile.val;
|
||||||
|
goto addone;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fprintf( stderr, "%s:%d: unknown keyword '%s'\n",
|
||||||
|
cfile.file, cfile.line, cfile.cmd );
|
||||||
|
err = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (!getopt_helper( &cfile, &gcops, &global_mops, &global_sops, &global_sync_state ))
|
||||||
|
{
|
||||||
|
fprintf( stderr, "%s:%d: unknown section keyword '%s'\n",
|
||||||
|
cfile.file, cfile.line, cfile.cmd );
|
||||||
|
err = 1;
|
||||||
|
while (getcline( &cfile ))
|
||||||
|
if (!cfile.cmd)
|
||||||
|
goto reloop;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fclose (cfile.fp);
|
||||||
|
err |= merge_ops( gcops, &global_mops, &global_sops );
|
||||||
|
if (!global_sync_state)
|
||||||
|
global_sync_state = expand_strdup( "~/." EXE "/" );
|
||||||
|
if (!err && pseudo)
|
||||||
|
unlink( where );
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
parse_generic_store( store_conf_t *store, conffile_t *cfg, int *err )
|
||||||
|
{
|
||||||
|
if (!strcasecmp( "Trash", cfg->cmd ))
|
||||||
|
store->trash = nfstrdup( cfg->val );
|
||||||
|
else if (!strcasecmp( "TrashRemoteNew", cfg->cmd ))
|
||||||
|
store->trash_remote_new = parse_bool( cfg );
|
||||||
|
else if (!strcasecmp( "TrashNewOnly", cfg->cmd ))
|
||||||
|
store->trash_only_new = parse_bool( cfg );
|
||||||
|
else if (!strcasecmp( "MaxSize", cfg->cmd ))
|
||||||
|
store->max_size = parse_size( cfg );
|
||||||
|
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 );
|
||||||
|
*err = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
89
src/cram.c
89
src/cram.c
|
@ -1,89 +0,0 @@
|
||||||
/* $Id$
|
|
||||||
*
|
|
||||||
* isync - IMAP4 to maildir mailbox synchronizer
|
|
||||||
* Copyright (C) 2000-2002 Michael R. Elkins <me@mutt.org>
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
*
|
|
||||||
* As a special exception, isync may be linked with the OpenSSL library,
|
|
||||||
* despite that library's more restrictive license.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <config.h>
|
|
||||||
|
|
||||||
#if HAVE_LIBSSL
|
|
||||||
|
|
||||||
#include "isync.h"
|
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <openssl/hmac.h>
|
|
||||||
|
|
||||||
#define ENCODED_SIZE(n) (4*((n+2)/3))
|
|
||||||
|
|
||||||
static char
|
|
||||||
hexchar (unsigned int b)
|
|
||||||
{
|
|
||||||
if (b < 10)
|
|
||||||
return '0' + b;
|
|
||||||
return 'a' + (b - 10);
|
|
||||||
}
|
|
||||||
|
|
||||||
char *
|
|
||||||
cram (const char *challenge, const char *user, const char *pass)
|
|
||||||
{
|
|
||||||
HMAC_CTX hmac;
|
|
||||||
char hash[16];
|
|
||||||
char hex[33];
|
|
||||||
int i;
|
|
||||||
unsigned int hashlen = sizeof (hash);
|
|
||||||
char buf[256];
|
|
||||||
int len = strlen (challenge);
|
|
||||||
char *response = calloc (1, 1 + len);
|
|
||||||
char *final;
|
|
||||||
|
|
||||||
/* response will always be smaller than challenge because we are
|
|
||||||
* decoding.
|
|
||||||
*/
|
|
||||||
len = EVP_DecodeBlock ((unsigned char *) response, (unsigned char *) challenge, strlen (challenge));
|
|
||||||
|
|
||||||
HMAC_Init (&hmac, (unsigned char *) pass, strlen (pass), EVP_md5 ());
|
|
||||||
HMAC_Update (&hmac, (unsigned char *) response, strlen(response));
|
|
||||||
HMAC_Final (&hmac, (unsigned char *) hash, &hashlen);
|
|
||||||
|
|
||||||
assert (hashlen == sizeof (hash));
|
|
||||||
|
|
||||||
free (response);
|
|
||||||
|
|
||||||
hex[32] = 0;
|
|
||||||
for (i = 0; i < 16; i++)
|
|
||||||
{
|
|
||||||
hex[2 * i] = hexchar ((hash[i] >> 4) & 0xf);
|
|
||||||
hex[2 * i + 1] = hexchar (hash[i] & 0xf);
|
|
||||||
}
|
|
||||||
|
|
||||||
snprintf (buf, sizeof (buf), "%s %s", user, hex);
|
|
||||||
|
|
||||||
len = strlen (buf);
|
|
||||||
len = ENCODED_SIZE (len) + 1;
|
|
||||||
final = malloc (len);
|
|
||||||
final[len - 1] = 0;
|
|
||||||
|
|
||||||
assert (EVP_EncodeBlock ((unsigned char *) final, (unsigned char *) buf, strlen (buf)) == len - 1);
|
|
||||||
|
|
||||||
return final;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
102
src/dotlock.c
102
src/dotlock.c
|
@ -1,102 +0,0 @@
|
||||||
/* $Id$
|
|
||||||
*
|
|
||||||
* isync - IMAP4 to maildir mailbox synchronizer
|
|
||||||
* Copyright (C) 2002 Michael R. Elkins <me@mutt.org>
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
*
|
|
||||||
* As a special exception, isync may be linked with the OpenSSL library,
|
|
||||||
* despite that library's more restrictive license.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* this file contains routines to establish a mutex using a `dotlock' file
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "dotlock.h"
|
|
||||||
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#if TESTING
|
|
||||||
#include <stdio.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int dotlock_lock (const char *path, int *fd)
|
|
||||||
{
|
|
||||||
struct flock lck;
|
|
||||||
|
|
||||||
*fd = open (path, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
|
|
||||||
if (*fd == -1)
|
|
||||||
return -1;
|
|
||||||
memset (&lck, 0, sizeof(lck));
|
|
||||||
#if SEEK_SET != 0
|
|
||||||
lck.l_whence = SEEK_SET;
|
|
||||||
#endif
|
|
||||||
#if F_WRLCK != 0
|
|
||||||
lck.l_type = F_WRLCK;
|
|
||||||
#endif
|
|
||||||
if (fcntl (*fd, F_SETLK, &lck))
|
|
||||||
{
|
|
||||||
close (*fd);
|
|
||||||
*fd = -1;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int dotlock_unlock (int *fd)
|
|
||||||
{
|
|
||||||
int r = 0;
|
|
||||||
struct flock lck;
|
|
||||||
|
|
||||||
if (*fd != -1)
|
|
||||||
{
|
|
||||||
memset (&lck, 0, sizeof(lck));
|
|
||||||
#if SEEK_SET != 0
|
|
||||||
lck.l_whence = SEEK_SET;
|
|
||||||
#endif
|
|
||||||
#if F_UNLCK != 0
|
|
||||||
lck.l_type = F_UNLCK;
|
|
||||||
#endif
|
|
||||||
if (fcntl (*fd, F_SETLK, &lck))
|
|
||||||
r = -1;
|
|
||||||
close (*fd);
|
|
||||||
*fd = -1;
|
|
||||||
}
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if TESTING
|
|
||||||
int main (void)
|
|
||||||
{
|
|
||||||
int fd;
|
|
||||||
|
|
||||||
if (dotlock_lock ("./lock", &fd))
|
|
||||||
{
|
|
||||||
perror ("dotlock_lock");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
puts ("sleeping for 5 seconds");
|
|
||||||
sleep(5);
|
|
||||||
if (dotlock_unlock (&fd))
|
|
||||||
{
|
|
||||||
perror ("dotlock_unlock");
|
|
||||||
}
|
|
||||||
done:
|
|
||||||
exit (0);
|
|
||||||
}
|
|
||||||
#endif
|
|
|
@ -1,25 +0,0 @@
|
||||||
/* $Id$
|
|
||||||
*
|
|
||||||
* isync - IMAP4 to maildir mailbox synchronizer
|
|
||||||
* Copyright (C) 2002 Michael R. Elkins <me@mutt.org>
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
*
|
|
||||||
* As a special exception, isync may be linked with the OpenSSL library,
|
|
||||||
* despite that library's more restrictive license.
|
|
||||||
*/
|
|
||||||
|
|
||||||
int dotlock_lock (const char *, int *);
|
|
||||||
int dotlock_unlock (int *);
|
|
1817
src/drv_imap.c
Normal file
1817
src/drv_imap.c
Normal file
File diff suppressed because it is too large
Load Diff
1153
src/drv_maildir.c
Normal file
1153
src/drv_maildir.c
Normal file
File diff suppressed because it is too large
Load Diff
1413
src/imap.c
1413
src/imap.c
File diff suppressed because it is too large
Load Diff
389
src/isync.h
389
src/isync.h
|
@ -1,6 +1,5 @@
|
||||||
/* $Id$
|
/*
|
||||||
*
|
* mbsync - mailbox synchronizer
|
||||||
* isync - IMAP4 to maildir mailbox synchronizer
|
|
||||||
* Copyright (C) 2000-2002 Michael R. Elkins <me@mutt.org>
|
* Copyright (C) 2000-2002 Michael R. Elkins <me@mutt.org>
|
||||||
* Copyright (C) 2002-2004 Oswald Buddenhagen <ossi@users.sf.net>
|
* Copyright (C) 2002-2004 Oswald Buddenhagen <ossi@users.sf.net>
|
||||||
*
|
*
|
||||||
|
@ -18,219 +17,233 @@
|
||||||
* along with this program; if not, write to the Free Software
|
* along with this program; if not, write to the Free Software
|
||||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*
|
*
|
||||||
* As a special exception, isync may be linked with the OpenSSL library,
|
* As a special exception, mbsync may be linked with the OpenSSL library,
|
||||||
* despite that library's more restrictive license.
|
* despite that library's more restrictive license.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
#include <db.h>
|
#define as(ar) (sizeof(ar)/sizeof(ar[0]))
|
||||||
|
|
||||||
#if HAVE_LIBSSL
|
#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4)
|
||||||
# include <openssl/ssl.h>
|
# define ATTR_UNUSED __attribute__((unused))
|
||||||
|
# define ATTR_NORETURN __attribute__((noreturn))
|
||||||
|
# define ATTR_PRINTFLIKE(fmt,var) __attribute__((format(printf,fmt,var)))
|
||||||
|
#else
|
||||||
|
# define ATTR_UNUSED
|
||||||
|
# define ATTR_NORETURN
|
||||||
|
# define ATTR_PRINTFLIKE(fmt,var)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef struct
|
#define EXE "mbsync"
|
||||||
{
|
|
||||||
int fd;
|
|
||||||
#if HAVE_LIBSSL
|
|
||||||
SSL *ssl;
|
|
||||||
unsigned int use_ssl:1;
|
|
||||||
#endif
|
|
||||||
} Socket_t;
|
|
||||||
|
|
||||||
typedef struct
|
typedef struct {
|
||||||
{
|
const char *file;
|
||||||
Socket_t *sock;
|
FILE *fp;
|
||||||
int bytes;
|
char *buf;
|
||||||
int offset;
|
int bufl;
|
||||||
char buf[1024];
|
int line;
|
||||||
}
|
char *cmd, *val, *rest;
|
||||||
buffer_t;
|
} conffile_t;
|
||||||
|
|
||||||
typedef struct config config_t;
|
#define OP_NEW (1<<0)
|
||||||
typedef struct mailbox mailbox_t;
|
#define OP_RENEW (1<<1)
|
||||||
typedef struct message message_t;
|
#define OP_DELETE (1<<2)
|
||||||
|
#define OP_FLAGS (1<<3)
|
||||||
|
#define OP_MASK_TYPE (OP_NEW|OP_RENEW|OP_DELETE|OP_FLAGS) /* asserted in the target ops */
|
||||||
|
#define OP_EXPUNGE (1<<4)
|
||||||
|
#define OP_CREATE (1<<5)
|
||||||
|
#define XOP_PUSH (1<<6)
|
||||||
|
#define XOP_PULL (1<<7)
|
||||||
|
#define XOP_MASK_DIR (XOP_PUSH|XOP_PULL)
|
||||||
|
#define XOP_HAVE_TYPE (1<<8)
|
||||||
|
#define XOP_HAVE_EXPUNGE (1<<9)
|
||||||
|
#define XOP_HAVE_CREATE (1<<10)
|
||||||
|
|
||||||
struct config
|
typedef struct driver driver_t;
|
||||||
{
|
|
||||||
char *maildir;
|
typedef struct store_conf {
|
||||||
char *path; /* path relative to .maildir, or absolute path */
|
struct store_conf *next;
|
||||||
char *host;
|
char *name;
|
||||||
int port;
|
driver_t *driver;
|
||||||
char *user;
|
const char *path; /* should this be here? its interpretation is driver-specific */
|
||||||
char *pass;
|
char *map_inbox;
|
||||||
char *folder;
|
char *trash;
|
||||||
char *box;
|
unsigned max_size; /* off_t is overkill */
|
||||||
char *inbox;
|
unsigned trash_remote_new:1, trash_only_new:1;
|
||||||
char *alias;
|
} store_conf_t;
|
||||||
char *copy_deleted_to;
|
|
||||||
char *tunnel;
|
typedef struct string_list {
|
||||||
unsigned int max_messages;
|
struct string_list *next;
|
||||||
off_t max_size;
|
char string[1];
|
||||||
config_t *next;
|
} string_list_t;
|
||||||
#if HAVE_LIBSSL
|
|
||||||
char *cert_file;
|
typedef struct channel_conf {
|
||||||
unsigned int use_imaps:1;
|
struct channel_conf *next;
|
||||||
unsigned int require_ssl:1;
|
char *name;
|
||||||
unsigned int use_sslv2:1;
|
store_conf_t *master, *slave;
|
||||||
unsigned int use_sslv3:1;
|
char *master_name, *slave_name;
|
||||||
unsigned int use_tlsv1:1;
|
char *sync_state;
|
||||||
unsigned int require_cram:1;
|
string_list_t *patterns;
|
||||||
#endif
|
int mops, sops;
|
||||||
unsigned int use_namespace:1;
|
unsigned max_messages; /* for slave only */
|
||||||
unsigned int expunge:1;
|
} channel_conf_t;
|
||||||
unsigned int delete:1;
|
|
||||||
unsigned int wanted:1;
|
typedef struct group_conf {
|
||||||
|
struct group_conf *next;
|
||||||
|
char *name;
|
||||||
|
string_list_t *channels;
|
||||||
|
} group_conf_t;
|
||||||
|
|
||||||
|
/* For message->flags */
|
||||||
|
/* Keep the mailbox driver flag definitions in sync! */
|
||||||
|
/* The order is according to alphabetical maildir flag sort */
|
||||||
|
#define F_DRAFT (1<<0) /* Draft */
|
||||||
|
#define F_FLAGGED (1<<1) /* Flagged */
|
||||||
|
#define F_ANSWERED (1<<2) /* Replied */
|
||||||
|
#define F_SEEN (1<<3) /* Seen */
|
||||||
|
#define F_DELETED (1<<4) /* Trashed */
|
||||||
|
#define NUM_FLAGS 5
|
||||||
|
|
||||||
|
/* For message->status */
|
||||||
|
#define M_RECENT (1<<0) /* unsyncable flag; maildir_* depend on this being 1<<0 */
|
||||||
|
#define M_DEAD (1<<1) /* expunged */
|
||||||
|
#define M_FLAGS (1<<2) /* flags fetched */
|
||||||
|
#define M_PROCESSED (1<<3) /* registered in pair */
|
||||||
|
#define M_NOT_SYNCED (1<<4) /* not in remote mailbox, yet */
|
||||||
|
#define M_EXPIRED (1<<5) /* kicked out by MaxMessages */
|
||||||
|
|
||||||
|
typedef struct message {
|
||||||
|
struct message *next;
|
||||||
|
/* string_list_t *keywords; */
|
||||||
|
size_t size; /* zero implies "not fetched" */
|
||||||
|
int uid;
|
||||||
|
unsigned char flags, status;
|
||||||
|
} message_t;
|
||||||
|
|
||||||
|
/* For opts, both in store and driver_t->select() */
|
||||||
|
#define OPEN_OLD (1<<0)
|
||||||
|
#define OPEN_NEW (1<<1)
|
||||||
|
#define OPEN_FLAGS (1<<2)
|
||||||
|
#define OPEN_SIZE (1<<3)
|
||||||
|
#define OPEN_CREATE (1<<4)
|
||||||
|
#define OPEN_EXPUNGE (1<<5)
|
||||||
|
#define OPEN_SETFLAGS (1<<6)
|
||||||
|
#define OPEN_APPEND (1<<7)
|
||||||
|
|
||||||
|
typedef struct store {
|
||||||
|
store_conf_t *conf; /* foreign */
|
||||||
|
|
||||||
|
/* currently open mailbox */
|
||||||
|
const char *name; /* foreign! maybe preset? */
|
||||||
|
char *path; /* own */
|
||||||
|
message_t *msgs; /* own */
|
||||||
|
int uidvalidity;
|
||||||
|
unsigned char opts; /* maybe preset? */
|
||||||
|
/* note that the following do _not_ reflect stats from msgs, but mailbox totals */
|
||||||
|
int count; /* # of messages */
|
||||||
|
int recent; /* # of recent messages - don't trust this beyond the initial read */
|
||||||
|
} store_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char *data;
|
||||||
|
int len;
|
||||||
|
unsigned char flags;
|
||||||
|
unsigned char crlf:1;
|
||||||
|
} msg_data_t;
|
||||||
|
|
||||||
|
#define DRV_OK 0
|
||||||
|
#define DRV_MSG_BAD -1
|
||||||
|
#define DRV_BOX_BAD -2
|
||||||
|
#define DRV_STORE_BAD -3
|
||||||
|
|
||||||
|
struct driver {
|
||||||
|
int (*parse_store)( conffile_t *cfg, store_conf_t **storep, int *err );
|
||||||
|
store_t *(*open_store)( store_conf_t *conf, store_t *oldctx );
|
||||||
|
void (*close_store)( store_t *ctx );
|
||||||
|
int (*list)( store_t *ctx, string_list_t **boxes );
|
||||||
|
void (*prepare)( store_t *ctx, int opts );
|
||||||
|
int (*select)( store_t *ctx, int minuid, int maxuid, int *excs, int nexcs );
|
||||||
|
int (*fetch_msg)( store_t *ctx, message_t *msg, msg_data_t *data );
|
||||||
|
int (*store_msg)( store_t *ctx, msg_data_t *data, int *uid ); /* if uid is null, store to trash */
|
||||||
|
int (*set_flags)( store_t *ctx, message_t *msg, int uid, int add, int del ); /* msg can be null, therefore uid as a fallback */
|
||||||
|
int (*trash_msg)( store_t *ctx, message_t *msg ); /* This may expunge the original message immediately, but it needn't to */
|
||||||
|
int (*check)( store_t *ctx ); /* IMAP-style: flush */
|
||||||
|
int (*close)( store_t *ctx ); /* IMAP-style: expunge inclusive */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* struct representing local mailbox file */
|
|
||||||
struct mailbox
|
|
||||||
{
|
|
||||||
DB *db;
|
|
||||||
char *path;
|
|
||||||
message_t *msgs;
|
|
||||||
int lockfd;
|
|
||||||
unsigned int deleted; /* # of deleted messages */
|
|
||||||
unsigned int uidvalidity;
|
|
||||||
unsigned int maxuid; /* largest uid we know about */
|
|
||||||
unsigned int uidseen : 1; /* flag indicating whether or not we saw a
|
|
||||||
valid value for UIDVALIDITY */
|
|
||||||
};
|
|
||||||
|
|
||||||
/* message dispositions */
|
/* main.c */
|
||||||
#define D_SEEN (1<<0)
|
|
||||||
#define D_ANSWERED (1<<1)
|
|
||||||
#define D_DELETED (1<<2)
|
|
||||||
#define D_FLAGGED (1<<3)
|
|
||||||
#define D_RECENT (1<<4)
|
|
||||||
#define D_DRAFT (1<<5)
|
|
||||||
#define D_MAX 6
|
|
||||||
|
|
||||||
struct message
|
extern int Pid;
|
||||||
{
|
|
||||||
char *file;
|
|
||||||
unsigned int uid;
|
|
||||||
unsigned int flags;
|
|
||||||
size_t size;
|
|
||||||
message_t *next;
|
|
||||||
unsigned int processed:1; /* message has already been evaluated */
|
|
||||||
unsigned int new:1; /* message is in the new/ subdir */
|
|
||||||
unsigned int dead:1; /* message doesn't exist on the server */
|
|
||||||
unsigned int wanted:1; /* when using MaxMessages, keep this message */
|
|
||||||
};
|
|
||||||
|
|
||||||
/* struct used for parsing IMAP lists */
|
|
||||||
typedef struct _list list_t;
|
|
||||||
|
|
||||||
#define NIL (void*)0x1
|
|
||||||
#define LIST (void*)0x2
|
|
||||||
|
|
||||||
struct _list
|
|
||||||
{
|
|
||||||
char *val;
|
|
||||||
list_t *next;
|
|
||||||
list_t *child;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* imap connection info */
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
Socket_t *sock;
|
|
||||||
unsigned int count; /* # of msgs */
|
|
||||||
unsigned int recent; /* # of recent messages */
|
|
||||||
buffer_t *buf; /* input buffer for reading server output */
|
|
||||||
message_t *msgs; /* list of messages on the server */
|
|
||||||
config_t *box; /* mailbox to open */
|
|
||||||
char *prefix; /* namespace prefix */
|
|
||||||
unsigned int deleted; /* # of deleted messages */
|
|
||||||
unsigned int uidvalidity;
|
|
||||||
unsigned int maxuid;
|
|
||||||
unsigned int minuid;
|
|
||||||
/* NAMESPACE info */
|
|
||||||
list_t *ns_personal;
|
|
||||||
list_t *ns_other;
|
|
||||||
list_t *ns_shared;
|
|
||||||
unsigned int caps;
|
|
||||||
#if HAVE_LIBSSL
|
|
||||||
unsigned int cram:1;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
imap_t;
|
|
||||||
|
|
||||||
/* Keep in sync with cap_list */
|
|
||||||
enum CAPABILITY {
|
|
||||||
NOLOGIN,
|
|
||||||
UIDPLUS,
|
|
||||||
NAMESPACE,
|
|
||||||
#if HAVE_LIBSSL
|
|
||||||
CRAM,
|
|
||||||
STARTTLS,
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
/* flags for sync_mailbox */
|
|
||||||
#define SYNC_DELETE (1<<0) /* delete local that don't exist on server */
|
|
||||||
#define SYNC_EXPUNGE (1<<1) /* don't fetch deleted messages */
|
|
||||||
|
|
||||||
/* flags for maildir_open */
|
|
||||||
#define OPEN_FAST (1<<0) /* fast open - don't parse */
|
|
||||||
#define OPEN_CREATE (1<<1) /* create mailbox if nonexistent */
|
|
||||||
|
|
||||||
/* flags for imap_open */
|
|
||||||
#define IMAP_CREATE (1<<0) /* Create remote mailboxes if necessary */
|
|
||||||
#define IMAP_GET_SIZE (1<<1) /* Request the RFC 822 SIZE */
|
|
||||||
|
|
||||||
|
|
||||||
extern config_t global;
|
|
||||||
extern config_t *boxes;
|
|
||||||
extern char Hostname[256];
|
extern char Hostname[256];
|
||||||
extern int Verbose, Quiet;
|
extern const char *Home;
|
||||||
|
|
||||||
extern void info (const char *, ...);
|
|
||||||
extern void infoc (char);
|
|
||||||
extern void warn (const char *, ...);
|
|
||||||
|
|
||||||
#if HAVE_LIBSSL
|
/* util.c */
|
||||||
extern SSL_CTX *SSLContext;
|
|
||||||
|
|
||||||
char *cram (const char *, const char *, const char *);
|
extern int Verbose, Quiet, Debug;
|
||||||
#endif
|
|
||||||
|
void debug( const char *, ... );
|
||||||
|
void info( const char *, ... );
|
||||||
|
void infoc( char );
|
||||||
|
void warn( const char *, ... );
|
||||||
|
|
||||||
char *next_arg( char ** );
|
char *next_arg( char ** );
|
||||||
|
|
||||||
int sync_mailbox (mailbox_t *, imap_t *, int, unsigned int, unsigned int);
|
void add_string_list( string_list_t **list, const char *str );
|
||||||
|
void free_string_list( string_list_t *list );
|
||||||
|
|
||||||
|
void free_generic_messages( message_t * );
|
||||||
|
|
||||||
|
void strip_cr( msg_data_t *msgdata );
|
||||||
|
|
||||||
|
void *nfmalloc( size_t sz );
|
||||||
|
void *nfcalloc( size_t sz );
|
||||||
|
void *nfrealloc( void *mem, size_t sz );
|
||||||
|
char *nfstrdup( const char *str );
|
||||||
|
int nfvasprintf( char **str, const char *fmt, va_list va );
|
||||||
|
int nfasprintf( char **str, const char *fmt, ... );
|
||||||
|
int nfsnprintf( char *buf, int blen, const char *fmt, ... );
|
||||||
|
void ATTR_NORETURN oob( void );
|
||||||
|
|
||||||
void load_config (const char *, int *);
|
|
||||||
char *expand_strdup( const char *s );
|
char *expand_strdup( const char *s );
|
||||||
config_t *find_box (const char *);
|
|
||||||
|
|
||||||
void imap_close (imap_t *);
|
void sort_ints( int *arr, int len );
|
||||||
int imap_copy_message (imap_t * imap, unsigned int uid, const char *mailbox);
|
|
||||||
int imap_fetch_message (imap_t *, unsigned int, int);
|
|
||||||
int imap_set_flags (imap_t *, unsigned int, unsigned int);
|
|
||||||
int imap_expunge (imap_t *);
|
|
||||||
imap_t *imap_connect (config_t *);
|
|
||||||
imap_t *imap_open (config_t *, unsigned int, imap_t *, int);
|
|
||||||
int imap_append_message (imap_t *, int, message_t *);
|
|
||||||
int imap_list (imap_t *);
|
|
||||||
|
|
||||||
mailbox_t *maildir_open (const char *, int flags);
|
void arc4_init( void );
|
||||||
int maildir_expunge (mailbox_t *, int);
|
unsigned char arc4_getbyte( void );
|
||||||
int maildir_set_uidvalidity (mailbox_t *, unsigned int uidvalidity);
|
|
||||||
void maildir_close (mailbox_t *);
|
|
||||||
int maildir_update_maxuid (mailbox_t * mbox);
|
|
||||||
|
|
||||||
message_t * find_msg (message_t * list, unsigned int uid);
|
/* sync.c */
|
||||||
void free_message (message_t *);
|
|
||||||
|
|
||||||
/* parse an IMAP list construct */
|
#define SYNC_OK 0
|
||||||
list_t * parse_list (char *s, char **end);
|
#define SYNC_FAIL 1
|
||||||
int is_atom (list_t *list);
|
#define SYNC_MASTER_BAD 2
|
||||||
int is_list (list_t *list);
|
#define SYNC_SLAVE_BAD 3
|
||||||
int is_nil (list_t *list);
|
|
||||||
void free_list (list_t *list);
|
|
||||||
|
|
||||||
#define strfcpy(a,b,c) {strncpy(a,b,c);(a)[c-1]=0;}
|
int sync_boxes( store_t *, const char *,
|
||||||
|
store_t *, const char *,
|
||||||
|
channel_conf_t * );
|
||||||
|
|
||||||
|
/* config.c */
|
||||||
|
|
||||||
|
extern channel_conf_t *channels;
|
||||||
|
extern group_conf_t *groups;
|
||||||
|
extern int global_mops, global_sops;
|
||||||
|
extern char *global_sync_state;
|
||||||
|
|
||||||
|
int parse_bool( conffile_t *cfile );
|
||||||
|
int parse_int( conffile_t *cfile );
|
||||||
|
int parse_size( conffile_t *cfile );
|
||||||
|
int getcline( conffile_t *cfile );
|
||||||
|
int merge_ops( int cops, int *mops, int *sops );
|
||||||
|
int load_config( const char *filename, int pseudo );
|
||||||
|
void parse_generic_store( store_conf_t *store, conffile_t *cfg, int *err );
|
||||||
|
|
||||||
|
/* drv_*.c */
|
||||||
|
extern driver_t maildir_driver, imap_driver;
|
||||||
|
|
179
src/list.c
179
src/list.c
|
@ -1,179 +0,0 @@
|
||||||
/* $Id$
|
|
||||||
*
|
|
||||||
* isync - IMAP4 to maildir mailbox synchronizer
|
|
||||||
* Copyright (C) 2000-2002 Michael R. Elkins <me@mutt.org>
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
*
|
|
||||||
* As a special exception, isync may be linked with the OpenSSL library,
|
|
||||||
* despite that library's more restrictive license.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "isync.h"
|
|
||||||
|
|
||||||
#include <ctype.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
static char *
|
|
||||||
skip_string (char *s)
|
|
||||||
{
|
|
||||||
while (*s && *s != '"')
|
|
||||||
s++;
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
list_t *
|
|
||||||
parse_list (char *s, char **end)
|
|
||||||
{
|
|
||||||
int level = 1;
|
|
||||||
list_t *cur;
|
|
||||||
list_t **list;
|
|
||||||
char *b;
|
|
||||||
|
|
||||||
cur = calloc (1, sizeof (list_t));
|
|
||||||
while (isspace ((unsigned char) *s))
|
|
||||||
s++;
|
|
||||||
if (*s == '(')
|
|
||||||
{
|
|
||||||
/* start of list. find the end of the list */
|
|
||||||
s++;
|
|
||||||
b = s; /* save beginning */
|
|
||||||
cur->val = LIST;
|
|
||||||
while (*s)
|
|
||||||
{
|
|
||||||
if (*s == '(')
|
|
||||||
{
|
|
||||||
level++;
|
|
||||||
}
|
|
||||||
else if (*s == ')')
|
|
||||||
{
|
|
||||||
level--;
|
|
||||||
if (level == 0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else if (*s == '"')
|
|
||||||
{
|
|
||||||
s = skip_string (s + 1);
|
|
||||||
if (!*s)
|
|
||||||
{
|
|
||||||
/* parse error */
|
|
||||||
free (cur);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
s++;
|
|
||||||
}
|
|
||||||
if (level != 0)
|
|
||||||
{
|
|
||||||
free (cur); /* parse error */
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
*s++ = 0;
|
|
||||||
|
|
||||||
list = &cur->child;
|
|
||||||
while (*b)
|
|
||||||
{
|
|
||||||
*list = parse_list (b, &b);
|
|
||||||
if (*list == NULL)
|
|
||||||
{
|
|
||||||
/* parse error */
|
|
||||||
free (cur);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
while (*list)
|
|
||||||
list = &(*list)->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (*s == '"')
|
|
||||||
{
|
|
||||||
/* quoted string */
|
|
||||||
s++;
|
|
||||||
cur->val = s;
|
|
||||||
s = skip_string (s);
|
|
||||||
if (!*s)
|
|
||||||
{
|
|
||||||
/* parse error */
|
|
||||||
free (cur);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
*s++ = 0;
|
|
||||||
cur->val = strdup (cur->val);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* atom */
|
|
||||||
cur->val = s;
|
|
||||||
while (*s && !isspace ((unsigned char) *s))
|
|
||||||
s++;
|
|
||||||
if (*s)
|
|
||||||
*s++ = 0;
|
|
||||||
if (strcmp ("NIL", cur->val))
|
|
||||||
cur->val = strdup (cur->val);
|
|
||||||
else
|
|
||||||
cur->val = NIL;
|
|
||||||
}
|
|
||||||
if (end)
|
|
||||||
*end = s;
|
|
||||||
return cur;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
is_atom (list_t * list)
|
|
||||||
{
|
|
||||||
return (list && list->val && list->val != NIL && list->val != LIST);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
is_list (list_t * list)
|
|
||||||
{
|
|
||||||
return (list && list->val == LIST);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
is_nil (list_t * list)
|
|
||||||
{
|
|
||||||
return (list && list->val == NIL);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
free_list (list_t * list)
|
|
||||||
{
|
|
||||||
list_t *tmp;
|
|
||||||
|
|
||||||
while (list)
|
|
||||||
{
|
|
||||||
tmp = list;
|
|
||||||
list = list->next;
|
|
||||||
if (is_list (tmp))
|
|
||||||
free_list (tmp->child);
|
|
||||||
else if (is_atom (tmp))
|
|
||||||
free (tmp->val);
|
|
||||||
free (tmp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if TEST
|
|
||||||
int
|
|
||||||
main (int argc, char **argv)
|
|
||||||
{
|
|
||||||
char buf[256];
|
|
||||||
list_t *list;
|
|
||||||
|
|
||||||
strcpy (buf,
|
|
||||||
"((compound list) atom NIL \"string with a (\" (another list))");
|
|
||||||
list = parse_list (buf, 0);
|
|
||||||
}
|
|
||||||
#endif
|
|
459
src/maildir.c
459
src/maildir.c
|
@ -1,459 +0,0 @@
|
||||||
/* $Id$
|
|
||||||
*
|
|
||||||
* isync - IMAP4 to maildir mailbox synchronizer
|
|
||||||
* Copyright (C) 2000-2002 Michael R. Elkins <me@mutt.org>
|
|
||||||
* Copyright (C) 2002-2003 Oswald Buddenhagen <ossi@users.sf.net>
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
*
|
|
||||||
* As a special exception, isync may be linked with the OpenSSL library,
|
|
||||||
* despite that library's more restrictive license.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "isync.h"
|
|
||||||
#include "dotlock.h"
|
|
||||||
|
|
||||||
#include <limits.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <dirent.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <time.h>
|
|
||||||
|
|
||||||
/* 2,<flags> */
|
|
||||||
static void
|
|
||||||
parse_info (message_t * m, char *s)
|
|
||||||
{
|
|
||||||
if (*s == '2' && *(s + 1) == ',')
|
|
||||||
{
|
|
||||||
s += 2;
|
|
||||||
while (*s)
|
|
||||||
{
|
|
||||||
if (*s == 'F')
|
|
||||||
m->flags |= D_FLAGGED;
|
|
||||||
else if (*s == 'R')
|
|
||||||
m->flags |= D_ANSWERED;
|
|
||||||
else if (*s == 'T')
|
|
||||||
m->flags |= D_DELETED;
|
|
||||||
else if (*s == 'S')
|
|
||||||
m->flags |= D_SEEN;
|
|
||||||
s++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* There are three possible results of this function:
|
|
||||||
* >1 uid was already seen
|
|
||||||
* 0 uid was not yet seen
|
|
||||||
* -1 unable to read uid because of some other error
|
|
||||||
*/
|
|
||||||
|
|
||||||
static int
|
|
||||||
read_uid (const char *path, const char *file, unsigned int *uid /* out */)
|
|
||||||
{
|
|
||||||
char full[_POSIX_PATH_MAX];
|
|
||||||
int fd;
|
|
||||||
int ret = -1;
|
|
||||||
int len;
|
|
||||||
char buf[64], *ptr;
|
|
||||||
|
|
||||||
snprintf (full, sizeof (full), "%s/%s", path, file);
|
|
||||||
fd = open (full, O_RDONLY);
|
|
||||||
if (fd == -1)
|
|
||||||
{
|
|
||||||
if (errno != ENOENT)
|
|
||||||
{
|
|
||||||
perror (full);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 0; /* doesn't exist */
|
|
||||||
}
|
|
||||||
len = read (fd, buf, sizeof (buf) - 1);
|
|
||||||
if (len == -1)
|
|
||||||
perror ("read");
|
|
||||||
else
|
|
||||||
{
|
|
||||||
buf[len] = 0;
|
|
||||||
errno = 0;
|
|
||||||
*uid = strtoul (buf, &ptr, 10);
|
|
||||||
if (errno)
|
|
||||||
perror ("strtoul");
|
|
||||||
else if (ptr && *ptr == '\n')
|
|
||||||
ret = 1;
|
|
||||||
/* else invalid value */
|
|
||||||
}
|
|
||||||
close (fd);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* open a maildir mailbox.
|
|
||||||
* if OPEN_FAST is set, we just check to make
|
|
||||||
* sure its a valid mailbox and don't actually parse it. any IMAP messages
|
|
||||||
* with the \Recent flag set are guaranteed not to be in the mailbox yet,
|
|
||||||
* so we can save a lot of time when the user just wants to fetch new messages
|
|
||||||
* without syncing the flags.
|
|
||||||
* if OPEN_CREATE is set, we create the mailbox if it doesn't already exist.
|
|
||||||
*/
|
|
||||||
mailbox_t *
|
|
||||||
maildir_open (const char *path, int flags)
|
|
||||||
{
|
|
||||||
char buf[_POSIX_PATH_MAX];
|
|
||||||
DIR *d;
|
|
||||||
struct dirent *e;
|
|
||||||
message_t **cur;
|
|
||||||
message_t *p;
|
|
||||||
mailbox_t *m;
|
|
||||||
char *s;
|
|
||||||
int count = 0;
|
|
||||||
struct stat sb;
|
|
||||||
const char *subdirs[] = { "cur", "new", "tmp" };
|
|
||||||
int i, ret;
|
|
||||||
DBT key, value;
|
|
||||||
|
|
||||||
m = calloc (1, sizeof (mailbox_t));
|
|
||||||
m->lockfd = -1;
|
|
||||||
/* filename expansion happens here, not in the config parser */
|
|
||||||
m->path = expand_strdup (path);
|
|
||||||
|
|
||||||
if (stat (m->path, &sb))
|
|
||||||
{
|
|
||||||
if (errno == ENOENT && (flags & OPEN_CREATE))
|
|
||||||
{
|
|
||||||
if (mkdir (m->path, S_IRUSR | S_IWUSR | S_IXUSR))
|
|
||||||
{
|
|
||||||
fprintf (stderr, "ERROR: mkdir %s: %s (errno %d)\n",
|
|
||||||
m->path, strerror (errno), errno);
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < 3; i++)
|
|
||||||
{
|
|
||||||
snprintf (buf, sizeof (buf), "%s/%s", m->path, subdirs[i]);
|
|
||||||
if (mkdir (buf, S_IRUSR | S_IWUSR | S_IXUSR))
|
|
||||||
{
|
|
||||||
fprintf (stderr, "ERROR: mkdir %s: %s (errno %d)\n",
|
|
||||||
buf, strerror (errno), errno);
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
fprintf (stderr, "ERROR: stat %s: %s (errno %d)\n", m->path,
|
|
||||||
strerror (errno), errno);
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* check to make sure this looks like a valid maildir box */
|
|
||||||
for (i = 0; i < 3; i++)
|
|
||||||
{
|
|
||||||
snprintf (buf, sizeof (buf), "%s/%s", m->path, subdirs[i]);
|
|
||||||
if (stat (buf, &sb))
|
|
||||||
{
|
|
||||||
fprintf (stderr, "ERROR: stat %s: %s (errno %d)\n", buf,
|
|
||||||
strerror (errno), errno);
|
|
||||||
fprintf (stderr,
|
|
||||||
"ERROR: %s does not appear to be a valid maildir style mailbox\n",
|
|
||||||
m->path);
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* we need a mutex on the maildir because of the state files that isync
|
|
||||||
* uses.
|
|
||||||
*/
|
|
||||||
snprintf (buf, sizeof (buf), "%s/isynclock", m->path);
|
|
||||||
if (dotlock_lock (buf, &m->lockfd))
|
|
||||||
goto err;
|
|
||||||
|
|
||||||
/* check for the uidvalidity value */
|
|
||||||
i = read_uid (m->path, "isyncuidvalidity", &m->uidvalidity);
|
|
||||||
if (i == -1)
|
|
||||||
goto err;
|
|
||||||
else if (i > 0)
|
|
||||||
m->uidseen = 1;
|
|
||||||
|
|
||||||
/* load the current maxuid */
|
|
||||||
if (read_uid (m->path, "isyncmaxuid", &m->maxuid) == -1)
|
|
||||||
goto err;
|
|
||||||
|
|
||||||
snprintf (buf, sizeof (buf), "%s/isyncuidmap.db", m->path);
|
|
||||||
if (db_create (&m->db, 0, 0)) {
|
|
||||||
fputs ("dbcreate failed\n", stderr);
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
if ((ret = m->db->set_pagesize (m->db, 4096)) != 0 ||
|
|
||||||
(ret = m->db->set_h_ffactor (m->db, 40)) != 0 ||
|
|
||||||
(ret = m->db->set_h_nelem (m->db, 1)) != 0) {
|
|
||||||
fputs ("Error configuring database\n", stderr);
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
m->db->open (m->db, buf, 0, DB_HASH, DB_CREATE, S_IRUSR | S_IWUSR);
|
|
||||||
if (m->db == NULL)
|
|
||||||
{
|
|
||||||
fputs ("ERROR: unable to open UID db\n", stderr);
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (flags & OPEN_FAST)
|
|
||||||
return m;
|
|
||||||
|
|
||||||
cur = &m->msgs;
|
|
||||||
for (; count < 2; count++)
|
|
||||||
{
|
|
||||||
/* read the msgs from the new subdir */
|
|
||||||
snprintf (buf, sizeof (buf), "%s/%s", m->path,
|
|
||||||
(count == 0) ? "new" : "cur");
|
|
||||||
d = opendir (buf);
|
|
||||||
if (!d)
|
|
||||||
{
|
|
||||||
perror ("opendir");
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
while ((e = readdir (d)))
|
|
||||||
{
|
|
||||||
if (*e->d_name == '.')
|
|
||||||
continue; /* skip dot-files */
|
|
||||||
*cur = calloc (1, sizeof (message_t));
|
|
||||||
p = *cur;
|
|
||||||
p->file = strdup (e->d_name);
|
|
||||||
p->uid = -1;
|
|
||||||
p->flags = 0;
|
|
||||||
p->new = (count == 0);
|
|
||||||
|
|
||||||
/* determine the UID for this message. The basename (sans
|
|
||||||
* flags) is used as the key in the db
|
|
||||||
*/
|
|
||||||
memset (&key, 0, sizeof(key));
|
|
||||||
memset (&value, 0, sizeof(value));
|
|
||||||
key.data = p->file;
|
|
||||||
s = strchr (p->file, ':');
|
|
||||||
key.size = s ? (size_t) (s - p->file) : strlen (p->file);
|
|
||||||
ret = m->db->get (m->db, 0, &key, &value, 0);
|
|
||||||
if (ret == DB_NOTFOUND) {
|
|
||||||
/* Every locally generated message triggers this ... */
|
|
||||||
/*warn ("Warning: no UID for message %.*s\n",
|
|
||||||
key.size, p->file);*/
|
|
||||||
} else if (ret) {
|
|
||||||
fprintf (stderr, "Unexpected error (%d) from db_get(%.*s)\n",
|
|
||||||
ret, key.size, p->file);
|
|
||||||
} else if (ret == 0) {
|
|
||||||
p->uid = *((int *) value.data);
|
|
||||||
if (p->uid > m->maxuid)
|
|
||||||
m->maxuid = p->uid;
|
|
||||||
}
|
|
||||||
if (s)
|
|
||||||
parse_info (p, s + 1);
|
|
||||||
if (p->flags & D_DELETED)
|
|
||||||
m->deleted++;
|
|
||||||
cur = &p->next;
|
|
||||||
}
|
|
||||||
closedir (d);
|
|
||||||
}
|
|
||||||
return m;
|
|
||||||
|
|
||||||
err:
|
|
||||||
if (m->db)
|
|
||||||
m->db->close (m->db, 0);
|
|
||||||
dotlock_unlock (&m->lockfd);
|
|
||||||
free (m->path);
|
|
||||||
free (m);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* permanently remove messages from a maildir mailbox. if `dead' is nonzero,
|
|
||||||
* we only remove the messags marked dead.
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
maildir_expunge (mailbox_t * mbox, int dead)
|
|
||||||
{
|
|
||||||
message_t **cur = &mbox->msgs;
|
|
||||||
message_t *tmp;
|
|
||||||
char *s;
|
|
||||||
DBT key;
|
|
||||||
char path[_POSIX_PATH_MAX];
|
|
||||||
|
|
||||||
while (*cur)
|
|
||||||
{
|
|
||||||
if ((dead == 0 && (*cur)->flags & D_DELETED) ||
|
|
||||||
(dead && (*cur)->dead))
|
|
||||||
{
|
|
||||||
tmp = *cur;
|
|
||||||
snprintf (path, sizeof (path), "%s/%s/%s",
|
|
||||||
mbox->path, tmp->new ? "new" : "cur", tmp->file);
|
|
||||||
if (unlink (path))
|
|
||||||
perror (path);
|
|
||||||
/* remove the message from the UID map */
|
|
||||||
memset (&key, 0, sizeof(key));
|
|
||||||
key.data = tmp->file;
|
|
||||||
s = strchr (tmp->file, ':');
|
|
||||||
key.size = s ? (size_t) (s - tmp->file) : strlen (key.data);
|
|
||||||
mbox->db->del (mbox->db, 0, &key, 0);
|
|
||||||
mbox->db->sync (mbox->db, 0);
|
|
||||||
*cur = (*cur)->next;
|
|
||||||
free (tmp->file);
|
|
||||||
free (tmp);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
cur = &(*cur)->next;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
maildir_update_maxuid (mailbox_t * mbox)
|
|
||||||
{
|
|
||||||
int fd;
|
|
||||||
char buf[64];
|
|
||||||
size_t len;
|
|
||||||
char path[_POSIX_PATH_MAX];
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
snprintf (path, sizeof (path), "%s/isyncmaxuid", mbox->path);
|
|
||||||
fd = open (path, O_WRONLY | O_CREAT, 0600);
|
|
||||||
if (fd == -1)
|
|
||||||
{
|
|
||||||
perror ("open");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* write out the file */
|
|
||||||
snprintf (buf, sizeof (buf), "%u\n", mbox->maxuid);
|
|
||||||
len = write (fd, buf, strlen (buf));
|
|
||||||
if (len == (size_t) - 1)
|
|
||||||
{
|
|
||||||
perror ("write");
|
|
||||||
ret = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (close (fd))
|
|
||||||
ret = -1;
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define _24_HOURS (3600 * 24)
|
|
||||||
|
|
||||||
static void
|
|
||||||
maildir_clean_tmp (const char *mbox)
|
|
||||||
{
|
|
||||||
char path[_POSIX_PATH_MAX];
|
|
||||||
DIR *dirp;
|
|
||||||
struct dirent *entry;
|
|
||||||
struct stat st;
|
|
||||||
time_t now;
|
|
||||||
|
|
||||||
snprintf (path, sizeof (path), "%s/tmp", mbox);
|
|
||||||
dirp = opendir (path);
|
|
||||||
if (dirp == NULL)
|
|
||||||
{
|
|
||||||
fprintf (stderr, "maildir_clean_tmp: opendir: %s: %s (errno %d)\n",
|
|
||||||
path, strerror (errno), errno);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
/* assuming this scan will take less than a second, we only need to
|
|
||||||
* check the time once before the following loop.
|
|
||||||
*/
|
|
||||||
time (&now);
|
|
||||||
while ((entry = readdir (dirp)))
|
|
||||||
{
|
|
||||||
snprintf (path, sizeof (path), "%s/tmp/%s", mbox, entry->d_name);
|
|
||||||
if (stat (path, &st))
|
|
||||||
fprintf (stderr, "maildir_clean_tmp: stat: %s: %s (errno %d)\n",
|
|
||||||
path, 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 ("Notice: removing stale file %s\n", path);
|
|
||||||
if (unlink (path))
|
|
||||||
fprintf (stderr,
|
|
||||||
"maildir_clean_tmp: unlink: %s: %s (errno %d)\n",
|
|
||||||
path, strerror (errno), errno);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
closedir(dirp);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
maildir_close (mailbox_t * mbox)
|
|
||||||
{
|
|
||||||
if (mbox->db)
|
|
||||||
mbox->db->close (mbox->db, 0);
|
|
||||||
|
|
||||||
/* release the mutex on the mailbox */
|
|
||||||
dotlock_unlock (&mbox->lockfd);
|
|
||||||
|
|
||||||
/* per the maildir(5) specification, delivery agents are supposed to
|
|
||||||
* set a 24-hour timer on items placed in the `tmp' directory.
|
|
||||||
*/
|
|
||||||
maildir_clean_tmp (mbox->path);
|
|
||||||
|
|
||||||
free (mbox->path);
|
|
||||||
free_message (mbox->msgs);
|
|
||||||
memset (mbox, 0xff, sizeof (mailbox_t));
|
|
||||||
free (mbox);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
maildir_set_uidvalidity (mailbox_t * mbox, unsigned int uidvalidity)
|
|
||||||
{
|
|
||||||
char path[_POSIX_PATH_MAX];
|
|
||||||
char buf[16];
|
|
||||||
int fd;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
snprintf (path, sizeof (path), "%s/isyncuidvalidity", mbox->path);
|
|
||||||
fd = open (path, O_WRONLY | O_CREAT | O_EXCL, 0600);
|
|
||||||
if (fd == -1)
|
|
||||||
{
|
|
||||||
perror ("open");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
snprintf (buf, sizeof (buf), "%u\n", uidvalidity);
|
|
||||||
|
|
||||||
ret = write (fd, buf, strlen (buf));
|
|
||||||
|
|
||||||
if (ret == -1)
|
|
||||||
perror ("write");
|
|
||||||
else if ((size_t) ret != strlen (buf))
|
|
||||||
ret = -1;
|
|
||||||
else
|
|
||||||
ret = 0;
|
|
||||||
|
|
||||||
if (close (fd))
|
|
||||||
{
|
|
||||||
perror ("close");
|
|
||||||
ret = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ret)
|
|
||||||
if (unlink (path))
|
|
||||||
perror ("unlink");
|
|
||||||
|
|
||||||
return (ret);
|
|
||||||
}
|
|
901
src/main.c
901
src/main.c
|
@ -1,6 +1,5 @@
|
||||||
/* $Id$
|
/*
|
||||||
*
|
* mbsync - mailbox synchronizer
|
||||||
* isync - IMAP4 to maildir mailbox synchronizer
|
|
||||||
* Copyright (C) 2000-2002 Michael R. Elkins <me@mutt.org>
|
* Copyright (C) 2000-2002 Michael R. Elkins <me@mutt.org>
|
||||||
* Copyright (C) 2002-2004 Oswald Buddenhagen <ossi@users.sf.net>
|
* Copyright (C) 2002-2004 Oswald Buddenhagen <ossi@users.sf.net>
|
||||||
*
|
*
|
||||||
|
@ -18,92 +17,19 @@
|
||||||
* along with this program; if not, write to the Free Software
|
* along with this program; if not, write to the Free Software
|
||||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*
|
*
|
||||||
* As a special exception, isync may be linked with the OpenSSL library,
|
* As a special exception, mbsync may be linked with the OpenSSL library,
|
||||||
* despite that library's more restrictive license.
|
* despite that library's more restrictive license.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "isync.h"
|
#include "isync.h"
|
||||||
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <stdarg.h>
|
|
||||||
#include <limits.h>
|
|
||||||
#include <pwd.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <ctype.h>
|
|
||||||
#include <dirent.h>
|
|
||||||
|
|
||||||
int Quiet;
|
int Pid; /* for maildir and imap */
|
||||||
|
char Hostname[256]; /* for maildir */
|
||||||
void
|
const char *Home; /* for config */
|
||||||
info (const char *msg, ...)
|
|
||||||
{
|
|
||||||
va_list va;
|
|
||||||
|
|
||||||
if (!Quiet)
|
|
||||||
{
|
|
||||||
va_start (va, msg);
|
|
||||||
vprintf (msg, va);
|
|
||||||
va_end (va);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
infoc (char c)
|
|
||||||
{
|
|
||||||
if (!Quiet)
|
|
||||||
putchar (c);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
warn (const char *msg, ...)
|
|
||||||
{
|
|
||||||
va_list va;
|
|
||||||
|
|
||||||
if (Quiet < 2)
|
|
||||||
{
|
|
||||||
va_start (va, msg);
|
|
||||||
vfprintf (stderr, msg, va);
|
|
||||||
va_end (va);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if HAVE_GETOPT_LONG
|
|
||||||
# define _GNU_SOURCE
|
|
||||||
# include <getopt.h>
|
|
||||||
struct option Opts[] = {
|
|
||||||
{"all", 0, NULL, 'a'},
|
|
||||||
{"list", 0, NULL, 'l'},
|
|
||||||
{"config", 1, NULL, 'c'},
|
|
||||||
{"create", 0, NULL, 'C'},
|
|
||||||
{"create-local", 0, NULL, 'L'},
|
|
||||||
{"create-remote", 0, NULL, 'R'},
|
|
||||||
{"delete", 0, NULL, 'd'},
|
|
||||||
{"expunge", 0, NULL, 'e'},
|
|
||||||
{"fast", 0, NULL, 'f'},
|
|
||||||
{"help", 0, NULL, 'h'},
|
|
||||||
{"remote", 1, NULL, 'r'},
|
|
||||||
{"folder", 1, NULL, 'F'},
|
|
||||||
{"maildir", 1, NULL, 'M'},
|
|
||||||
{"one-to-one", 0, NULL, '1'},
|
|
||||||
{"inbox", 1, NULL, 'I'},
|
|
||||||
{"host", 1, NULL, 's'},
|
|
||||||
{"port", 1, NULL, 'p'},
|
|
||||||
{"quiet", 0, NULL, 'q'},
|
|
||||||
{"user", 1, NULL, 'u'},
|
|
||||||
{"version", 0, NULL, 'v'},
|
|
||||||
{"verbose", 0, NULL, 'V'},
|
|
||||||
{0, 0, 0, 0}
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
config_t global;
|
|
||||||
char Hostname[256];
|
|
||||||
int Verbose = 0;
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
version( void )
|
version( void )
|
||||||
|
@ -116,35 +42,34 @@ static void
|
||||||
usage( int code )
|
usage( int code )
|
||||||
{
|
{
|
||||||
fputs(
|
fputs(
|
||||||
PACKAGE " " VERSION " IMAP4 to maildir synchronizer\n"
|
PACKAGE " " VERSION " - mailbox synchronizer\n"
|
||||||
"Copyright (C) 2000-2002 Michael R. Elkins <me@mutt.org>\n"
|
"Copyright (C) 2000-2002 Michael R. Elkins <me@mutt.org>\n"
|
||||||
"Copyright (C) 2002-2004 Oswald Buddenhagen <ossi@users.sf.net>\n"
|
"Copyright (C) 2002-2004 Oswald Buddenhagen <ossi@users.sf.net>\n"
|
||||||
|
"Copyright (C) 2004 Theodore Ts'o <tytso@mit.edu>\n"
|
||||||
"usage:\n"
|
"usage:\n"
|
||||||
" " PACKAGE " [ flags ] mailbox [mailbox ...]\n"
|
" " EXE " [flags] {{channel[:box,...]|group} ...|-a}\n"
|
||||||
" " PACKAGE " [ flags ] -a\n"
|
" -a, --all operate on all defined channels\n"
|
||||||
" " PACKAGE " [ flags ] -l\n"
|
" -l, --list list mailboxes instead of syncing them\n"
|
||||||
" -a, --all synchronize all defined mailboxes\n"
|
" -n, --new propagate new messages\n"
|
||||||
" -l, --list list all defined mailboxes and exit\n"
|
" -d, --delete propagate message deletions\n"
|
||||||
" -L, --create-local create local maildir mailbox if nonexistent\n"
|
" -f, --flags propagate message flag changes\n"
|
||||||
" -R, --create-remote create remote imap mailbox if nonexistent\n"
|
" -N, --renew propagate previously not propagated new messages\n"
|
||||||
" -C, --create create both local and remote mailboxes if nonexistent\n"
|
" -L, --pull propagate from master to slave\n"
|
||||||
" -d, --delete delete local msgs that don't exist on the server\n"
|
" -H, --push propagate from slave to master\n"
|
||||||
" -e, --expunge expunge deleted messages\n"
|
" -C, --create create mailboxes if nonexistent\n"
|
||||||
" -f, --fast only fetch new messages\n"
|
" -X, --expunge expunge deleted messages\n"
|
||||||
" -r, --remote BOX remote mailbox\n"
|
" -c, --config CONFIG read an alternate config file (default: ~/." EXE "rc)\n"
|
||||||
" -F, --folder DIR remote IMAP folder containing mailboxes\n"
|
" -D, --debug print debugging messages\n"
|
||||||
" -M, --maildir DIR local directory containing mailboxes\n"
|
|
||||||
" -1, --one-to-one map every IMAP <folder>/box to <maildir>/box\n"
|
|
||||||
" -I, --inbox BOX map IMAP INBOX to <maildir>/BOX (exception to -1)\n"
|
|
||||||
" -s, --host HOST IMAP server address\n"
|
|
||||||
" -p, --port PORT server IMAP port\n"
|
|
||||||
" -u, --user USER IMAP user name\n"
|
|
||||||
" -c, --config CONFIG read an alternate config file (default: ~/.isyncrc)\n"
|
|
||||||
" -V, --verbose verbose mode (display network traffic)\n"
|
" -V, --verbose verbose mode (display network traffic)\n"
|
||||||
" -q, --quiet don't display progress info\n"
|
" -q, --quiet don't display progress info\n"
|
||||||
" -v, --version display version\n"
|
" -v, --version display version\n"
|
||||||
" -h, --help display this help message\n"
|
" -h, --help display this help message\n"
|
||||||
"Compile time options:\n"
|
"\nIf neither --pull nor --push are specified, both are active.\n"
|
||||||
|
"If neither --new, --delete, --flags nor --renew are specified, all are active.\n"
|
||||||
|
"Direction and operation can be concatenated like --pull-new, etc.\n"
|
||||||
|
"--create and --expunge can be suffixed with -master/-slave. Read the man page.\n"
|
||||||
|
"\nSupported mailbox formats are: IMAP4rev1, Maildir\n"
|
||||||
|
"\nCompile time options:\n"
|
||||||
#if HAVE_LIBSSL
|
#if HAVE_LIBSSL
|
||||||
" +HAVE_LIBSSL\n"
|
" +HAVE_LIBSSL\n"
|
||||||
#else
|
#else
|
||||||
|
@ -154,337 +79,535 @@ PACKAGE " " VERSION " IMAP4 to maildir synchronizer\n"
|
||||||
exit( code );
|
exit( code );
|
||||||
}
|
}
|
||||||
|
|
||||||
char *
|
static int
|
||||||
next_arg (char **s)
|
matches( const char *t, const char *p )
|
||||||
{
|
{
|
||||||
char *ret;
|
for (;;) {
|
||||||
|
if (!*p)
|
||||||
|
return !*t;
|
||||||
|
if (*p == '*') {
|
||||||
|
p++;
|
||||||
|
do {
|
||||||
|
if (matches( t, p ))
|
||||||
|
return 1;
|
||||||
|
} while (*t++);
|
||||||
|
return 0;
|
||||||
|
} else if (*p == '%') {
|
||||||
|
p++;
|
||||||
|
do {
|
||||||
|
if (*t == '.' || *t == '/') /* this is "somewhat" hacky ... */
|
||||||
|
return 0;
|
||||||
|
if (matches( t, p ))
|
||||||
|
return 1;
|
||||||
|
} while (*t++);
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
if (*p != *t)
|
||||||
|
return 0;
|
||||||
|
p++, t++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!s)
|
static string_list_t *
|
||||||
return 0;
|
filter_boxes( string_list_t *boxes, string_list_t *patterns )
|
||||||
if (!*s)
|
|
||||||
return 0;
|
|
||||||
while (isspace ((unsigned char) **s))
|
|
||||||
(*s)++;
|
|
||||||
if (!**s)
|
|
||||||
{
|
{
|
||||||
*s = 0;
|
string_list_t *nboxes = 0, *cpat;
|
||||||
return 0;
|
const char *ps;
|
||||||
|
int not, fnot;
|
||||||
|
|
||||||
|
for (; boxes; boxes = boxes->next) {
|
||||||
|
fnot = 1;
|
||||||
|
for (cpat = patterns; cpat; cpat = cpat->next) {
|
||||||
|
ps = cpat->string;
|
||||||
|
if (*ps == '!') {
|
||||||
|
ps++;
|
||||||
|
not = 1;
|
||||||
|
} else
|
||||||
|
not = 0;
|
||||||
|
if (matches( boxes->string, ps )) {
|
||||||
|
fnot = not;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (**s == '"')
|
}
|
||||||
|
if (!fnot)
|
||||||
|
add_string_list( &nboxes, boxes->string );
|
||||||
|
}
|
||||||
|
return nboxes;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
merge_actions( channel_conf_t *chan, int mops, int sops, int have, int mask, int def )
|
||||||
{
|
{
|
||||||
++*s;
|
if (mops & have) {
|
||||||
ret = *s;
|
chan->mops &= ~mask;
|
||||||
*s = strchr (*s, '"');
|
chan->mops |= mops & mask;
|
||||||
|
chan->sops &= ~mask;
|
||||||
|
chan->sops |= sops & mask;
|
||||||
|
} else if (!(chan->mops & have)) {
|
||||||
|
if (global_mops & have) {
|
||||||
|
chan->mops |= global_mops & mask;
|
||||||
|
chan->sops |= global_sops & mask;
|
||||||
|
} else {
|
||||||
|
chan->mops |= def;
|
||||||
|
chan->sops |= def;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
ret = *s;
|
|
||||||
while (**s && !isspace ((unsigned char) **s))
|
|
||||||
(*s)++;
|
|
||||||
}
|
}
|
||||||
if (*s)
|
|
||||||
{
|
|
||||||
if (**s)
|
|
||||||
*(*s)++ = 0;
|
|
||||||
if (!**s)
|
|
||||||
*s = 0;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
main( int argc, char **argv )
|
main( int argc, char **argv )
|
||||||
{
|
{
|
||||||
int i;
|
channel_conf_t *chan;
|
||||||
int ret;
|
store_conf_t *mconf, *sconf;
|
||||||
config_t *box = 0;
|
group_conf_t *group;
|
||||||
mailbox_t *mail = 0;
|
driver_t *mdriver, *sdriver;
|
||||||
imap_t *imap = 0;
|
store_t *mctx, *sctx;
|
||||||
int expunge = 0; /* by default, don't delete anything */
|
string_list_t *umboxes, *usboxes, *mboxes, *sboxes, *mbox, *sbox, **mboxp, **sboxp, *cboxes, *chanptr;
|
||||||
int fast = 0;
|
char *config = 0, *channame, *boxlist, *opt, *ochar;
|
||||||
int delete = 0;
|
int all = 0, list = 0, cops = 0, mops = 0, sops = 0, gumboxes, gusboxes;
|
||||||
char *config = 0;
|
int oind, ret, op, multiple, pseudo = 0;
|
||||||
struct passwd *pw;
|
|
||||||
int all = 0;
|
|
||||||
int list = 0;
|
|
||||||
int o2o = 0;
|
|
||||||
int mbox_open_mode = 0;
|
|
||||||
int imap_flags = 0;
|
|
||||||
|
|
||||||
pw = getpwuid (getuid ());
|
gethostname( Hostname, sizeof(Hostname) );
|
||||||
|
if ((ochar = strchr( Hostname, '.' )))
|
||||||
|
*ochar = 0;
|
||||||
|
Pid = getpid();
|
||||||
|
if (!(Home = getenv("HOME"))) {
|
||||||
|
fputs( "Fatal: $HOME not set\n", stderr );
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
arc4_init();
|
||||||
|
|
||||||
/* defaults */
|
for (oind = 1, ochar = 0; oind < argc; ) {
|
||||||
memset (&global, 0, sizeof (global));
|
if (!ochar || !*ochar) {
|
||||||
/* XXX the precedence is borked:
|
if (argv[oind][0] != '-')
|
||||||
it's defaults < cmdline < file instead of defaults < file < cmdline */
|
break;
|
||||||
global.port = 143;
|
if (argv[oind][1] == '-') {
|
||||||
global.box = "INBOX";
|
opt = argv[oind++] + 2;
|
||||||
global.folder = "";
|
if (!*opt)
|
||||||
global.user = strdup (pw->pw_name);
|
break;
|
||||||
global.maildir = strdup (pw->pw_dir);
|
if (!strcmp( opt, "config" )) {
|
||||||
global.use_namespace = 1;
|
if (oind >= argc) {
|
||||||
#if HAVE_LIBSSL
|
fprintf( stderr, "--config requires an argument.\n" );
|
||||||
/* this will probably annoy people, but its the best default just in
|
return 1;
|
||||||
* case people forget to turn it on
|
}
|
||||||
*/
|
config = argv[oind++];
|
||||||
global.require_ssl = 1;
|
} else if (!memcmp( opt, "config=", 7 ))
|
||||||
global.use_tlsv1 = 1;
|
config = opt + 7;
|
||||||
#endif
|
else if (!strcmp( opt, "all" ))
|
||||||
|
all = 1;
|
||||||
#define FLAGS "alCLRc:defhp:qu:r:F:M:1I:s:vV"
|
else if (!strcmp( opt, "list" ))
|
||||||
|
|
||||||
#if HAVE_GETOPT_LONG
|
|
||||||
while ((i = getopt_long (argc, argv, FLAGS, Opts, NULL)) != -1)
|
|
||||||
#else
|
|
||||||
while ((i = getopt (argc, argv, FLAGS)) != -1)
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
switch (i)
|
|
||||||
{
|
|
||||||
case 'l':
|
|
||||||
list = 1;
|
list = 1;
|
||||||
/* plopp */
|
else if (!strcmp( opt, "help" ))
|
||||||
|
usage( 0 );
|
||||||
|
else if (!strcmp( opt, "version" ))
|
||||||
|
version();
|
||||||
|
else if (!strcmp( opt, "quiet" ))
|
||||||
|
Quiet++;
|
||||||
|
else if (!strcmp( opt, "verbose" )) {
|
||||||
|
Verbose = 1;
|
||||||
|
if (!Quiet)
|
||||||
|
Quiet = 1;
|
||||||
|
} else if (!strcmp( opt, "debug" )) {
|
||||||
|
Debug = 1;
|
||||||
|
if (!Quiet)
|
||||||
|
Quiet = 1;
|
||||||
|
} else if (!strcmp( opt, "pull" ))
|
||||||
|
cops |= XOP_PULL, mops |= XOP_HAVE_TYPE;
|
||||||
|
else if (!strcmp( opt, "push" ))
|
||||||
|
cops |= XOP_PUSH, mops |= XOP_HAVE_TYPE;
|
||||||
|
else if (!memcmp( opt, "create", 6 )) {
|
||||||
|
opt += 6;
|
||||||
|
op = OP_CREATE|XOP_HAVE_CREATE;
|
||||||
|
lcop:
|
||||||
|
if (!*opt)
|
||||||
|
cops |= op;
|
||||||
|
else if (!strcmp( opt, "-master" ))
|
||||||
|
mops |= op, ochar++;
|
||||||
|
else if (!strcmp( opt, "-slave" ))
|
||||||
|
sops |= op, ochar++;
|
||||||
|
else
|
||||||
|
goto badopt;
|
||||||
|
mops |= op & (XOP_HAVE_CREATE|XOP_HAVE_EXPUNGE);
|
||||||
|
} else if (!memcmp( opt, "expunge", 7 )) {
|
||||||
|
opt += 7;
|
||||||
|
op = OP_EXPUNGE|XOP_HAVE_EXPUNGE;
|
||||||
|
goto lcop;
|
||||||
|
} else if (!strcmp( opt, "no-expunge" ))
|
||||||
|
mops |= XOP_HAVE_EXPUNGE;
|
||||||
|
else if (!strcmp( opt, "no-create" ))
|
||||||
|
mops |= XOP_HAVE_CREATE;
|
||||||
|
else if (!strcmp( opt, "full" ))
|
||||||
|
mops |= XOP_HAVE_TYPE|XOP_PULL|XOP_PUSH;
|
||||||
|
else if (!strcmp( opt, "noop" ))
|
||||||
|
mops |= XOP_HAVE_TYPE;
|
||||||
|
else if (!memcmp( opt, "pull", 4 )) {
|
||||||
|
op = XOP_PULL;
|
||||||
|
lcac:
|
||||||
|
opt += 4;
|
||||||
|
if (!*opt)
|
||||||
|
cops |= op;
|
||||||
|
else if (*opt == '-') {
|
||||||
|
opt++;
|
||||||
|
goto rlcac;
|
||||||
|
} else
|
||||||
|
goto badopt;
|
||||||
|
} else if (!memcmp( opt, "push", 4 )) {
|
||||||
|
op = XOP_PUSH;
|
||||||
|
goto lcac;
|
||||||
|
} else {
|
||||||
|
op = 0;
|
||||||
|
rlcac:
|
||||||
|
if (!strcmp( opt, "new" ))
|
||||||
|
op |= OP_NEW;
|
||||||
|
else if (!strcmp( opt, "renew" ))
|
||||||
|
op |= OP_RENEW;
|
||||||
|
else if (!strcmp( opt, "delete" ))
|
||||||
|
op |= OP_DELETE;
|
||||||
|
else if (!strcmp( opt, "flags" ))
|
||||||
|
op |= OP_FLAGS;
|
||||||
|
else {
|
||||||
|
badopt:
|
||||||
|
fprintf( stderr, "Unknown option '%s'\n", argv[oind - 1] );
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
switch (op & XOP_MASK_DIR) {
|
||||||
|
case XOP_PULL: sops |= op & OP_MASK_TYPE; break;
|
||||||
|
case XOP_PUSH: mops |= op & OP_MASK_TYPE; break;
|
||||||
|
default: cops |= op; break;
|
||||||
|
}
|
||||||
|
mops |= XOP_HAVE_TYPE;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ochar = argv[oind++] + 1;
|
||||||
|
if (!*ochar) {
|
||||||
|
fprintf( stderr, "Invalid option '-'\n" );
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch (*ochar++) {
|
||||||
case 'a':
|
case 'a':
|
||||||
all = 1;
|
all = 1;
|
||||||
break;
|
break;
|
||||||
case '1':
|
case 'l':
|
||||||
o2o = 1;
|
list = 1;
|
||||||
break;
|
|
||||||
case 'C':
|
|
||||||
mbox_open_mode |= OPEN_CREATE;
|
|
||||||
imap_flags |= IMAP_CREATE;
|
|
||||||
break;
|
|
||||||
case 'L':
|
|
||||||
mbox_open_mode |= OPEN_CREATE;
|
|
||||||
break;
|
|
||||||
case 'R':
|
|
||||||
imap_flags |= IMAP_CREATE;
|
|
||||||
break;
|
break;
|
||||||
case 'c':
|
case 'c':
|
||||||
config = optarg;
|
if (*ochar == 'T') {
|
||||||
|
ochar++;
|
||||||
|
pseudo = 1;
|
||||||
|
}
|
||||||
|
if (oind >= argc) {
|
||||||
|
fprintf( stderr, "-c requires an argument.\n" );
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
config = argv[oind++];
|
||||||
break;
|
break;
|
||||||
|
case 'C':
|
||||||
|
op = OP_CREATE|XOP_HAVE_CREATE;
|
||||||
|
cop:
|
||||||
|
if (*ochar == 'm')
|
||||||
|
mops |= op, ochar++;
|
||||||
|
else if (*ochar == 's')
|
||||||
|
sops |= op, ochar++;
|
||||||
|
else if (*ochar == '-')
|
||||||
|
ochar++;
|
||||||
|
else
|
||||||
|
cops |= op;
|
||||||
|
mops |= op & (XOP_HAVE_CREATE|XOP_HAVE_EXPUNGE);
|
||||||
|
break;
|
||||||
|
case 'X':
|
||||||
|
op = OP_EXPUNGE|XOP_HAVE_EXPUNGE;
|
||||||
|
goto cop;
|
||||||
|
case 'F':
|
||||||
|
cops |= XOP_PULL|XOP_PUSH;
|
||||||
|
case '0':
|
||||||
|
mops |= XOP_HAVE_TYPE;
|
||||||
|
break;
|
||||||
|
case 'n':
|
||||||
case 'd':
|
case 'd':
|
||||||
delete = 1;
|
|
||||||
break;
|
|
||||||
case 'e':
|
|
||||||
expunge = 1;
|
|
||||||
break;
|
|
||||||
case 'f':
|
case 'f':
|
||||||
mbox_open_mode |= OPEN_FAST;
|
case 'N':
|
||||||
fast = 1;
|
--ochar;
|
||||||
|
op = 0;
|
||||||
|
cac:
|
||||||
|
for (;; ochar++) {
|
||||||
|
if (*ochar == 'n')
|
||||||
|
op |= OP_NEW;
|
||||||
|
else if (*ochar == 'd')
|
||||||
|
op |= OP_DELETE;
|
||||||
|
else if (*ochar == 'f')
|
||||||
|
op |= OP_FLAGS;
|
||||||
|
else if (*ochar == 'N')
|
||||||
|
op |= OP_RENEW;
|
||||||
|
else
|
||||||
break;
|
break;
|
||||||
case 'p':
|
}
|
||||||
global.port = atoi (optarg);
|
if (op & OP_MASK_TYPE)
|
||||||
|
switch (op & XOP_MASK_DIR) {
|
||||||
|
case XOP_PULL: sops |= op & OP_MASK_TYPE; break;
|
||||||
|
case XOP_PUSH: mops |= op & OP_MASK_TYPE; break;
|
||||||
|
default: cops |= op; break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
cops |= op;
|
||||||
|
mops |= XOP_HAVE_TYPE;
|
||||||
break;
|
break;
|
||||||
|
case 'L':
|
||||||
|
op = XOP_PULL;
|
||||||
|
goto cac;
|
||||||
|
case 'H':
|
||||||
|
op = XOP_PUSH;
|
||||||
|
goto cac;
|
||||||
case 'q':
|
case 'q':
|
||||||
Quiet++;
|
Quiet++;
|
||||||
Verbose = 0;
|
|
||||||
break;
|
|
||||||
case 'r':
|
|
||||||
global.box = optarg;
|
|
||||||
break;
|
|
||||||
case 'F':
|
|
||||||
global.folder = optarg;
|
|
||||||
break;
|
|
||||||
case 'M':
|
|
||||||
global.maildir = optarg;
|
|
||||||
break;
|
|
||||||
case 'I':
|
|
||||||
global.inbox = optarg;
|
|
||||||
break;
|
|
||||||
case 's':
|
|
||||||
#if HAVE_LIBSSL
|
|
||||||
if (!strncasecmp ("imaps:", optarg, 6))
|
|
||||||
{
|
|
||||||
global.use_imaps = 1;
|
|
||||||
global.port = 993;
|
|
||||||
global.use_sslv2 = 1;
|
|
||||||
global.use_sslv3 = 1;
|
|
||||||
optarg += 6;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
global.host = optarg;
|
|
||||||
break;
|
|
||||||
case 'u':
|
|
||||||
global.user = optarg;
|
|
||||||
break;
|
break;
|
||||||
case 'V':
|
case 'V':
|
||||||
Verbose = 1;
|
Verbose = 1;
|
||||||
|
if (!Quiet)
|
||||||
|
Quiet = 1;
|
||||||
|
break;
|
||||||
|
case 'D':
|
||||||
|
Debug = 1;
|
||||||
|
if (!Quiet)
|
||||||
|
Quiet = 1;
|
||||||
break;
|
break;
|
||||||
case 'v':
|
case 'v':
|
||||||
version();
|
version();
|
||||||
case 'h':
|
case 'h':
|
||||||
usage( 0 );
|
usage( 0 );
|
||||||
default:
|
default:
|
||||||
usage (1);
|
fprintf( stderr, "Unknown option '-%c'\n", *(ochar - 1) );
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!argv[optind] && !all)
|
if (merge_ops( cops, &mops, &sops ))
|
||||||
{
|
return 1;
|
||||||
fprintf (stderr, "No mailbox specified. Try isync -h\n");
|
|
||||||
|
if (load_config( config, pseudo ))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (!all && !argv[oind]) {
|
||||||
|
fputs( "No channel specified. Try '" EXE " -h'\n", stderr );
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (!channels) {
|
||||||
|
fputs( "No channels defined. Try 'man " EXE "'\n", stderr );
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
gethostname (Hostname, sizeof (Hostname));
|
|
||||||
|
|
||||||
load_config (config, &o2o);
|
|
||||||
|
|
||||||
if (all && o2o)
|
|
||||||
{
|
|
||||||
DIR *dir;
|
|
||||||
struct dirent *de;
|
|
||||||
|
|
||||||
if (global.inbox) {
|
|
||||||
boxes = malloc (sizeof (config_t));
|
|
||||||
memcpy (boxes, &global, sizeof (config_t));
|
|
||||||
boxes->box = "INBOX";
|
|
||||||
boxes->path = global.inbox;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(dir = opendir (global.maildir))) {
|
|
||||||
fprintf (stderr, "%s: %s\n", global.maildir, strerror(errno));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
while ((de = readdir (dir))) {
|
|
||||||
struct stat st;
|
|
||||||
char buf[PATH_MAX];
|
|
||||||
|
|
||||||
if (*de->d_name == '.')
|
|
||||||
continue;
|
|
||||||
if (global.inbox && !strcmp (global.inbox, de->d_name))
|
|
||||||
continue;
|
|
||||||
snprintf (buf, sizeof(buf), "%s/%s/cur", global.maildir, de->d_name);
|
|
||||||
if (stat (buf, &st) || !S_ISDIR (st.st_mode))
|
|
||||||
continue;
|
|
||||||
box = malloc (sizeof (config_t));
|
|
||||||
memcpy (box, &global, sizeof (config_t));
|
|
||||||
box->path = strdup (de->d_name);
|
|
||||||
box->box = box->path;
|
|
||||||
box->next = boxes;
|
|
||||||
boxes = box;
|
|
||||||
}
|
|
||||||
closedir (dir);
|
|
||||||
|
|
||||||
imap = imap_connect (&global);
|
|
||||||
if (!imap)
|
|
||||||
return 1;
|
|
||||||
if (imap_list (imap))
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if (list)
|
|
||||||
{
|
|
||||||
for (box = boxes; box; box = box->next)
|
|
||||||
puts (box->path);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
for (box = boxes; (all && box) || (!all && argv[optind]); optind++)
|
chan = channels;
|
||||||
{
|
chanptr = 0;
|
||||||
if (!all)
|
mctx = sctx = 0;
|
||||||
{
|
mconf = sconf = 0; /* make-gcc-happy */
|
||||||
if (o2o || NULL == (box = find_box (argv[optind])))
|
mdriver = sdriver = 0; /* make-gcc-happy */
|
||||||
{
|
gumboxes = gusboxes = 0;
|
||||||
/* if enough info is given on the command line, don't worry if
|
umboxes = usboxes = 0;
|
||||||
* the mailbox isn't defined.
|
|
||||||
*/
|
|
||||||
if (!global.host)
|
|
||||||
{
|
|
||||||
fprintf (stderr, "%s: no such mailbox\n", argv[optind]);
|
|
||||||
/* continue is ok here because we are not handling the
|
|
||||||
* `all' case.
|
|
||||||
*/
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
global.path = argv[optind];
|
|
||||||
box = &global;
|
|
||||||
if (o2o)
|
|
||||||
global.box =
|
|
||||||
(global.inbox && !strcmp (global.path, global.inbox)) ?
|
|
||||||
"INBOX" : global.path;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
do {
|
|
||||||
info ("Mailbox %s\n", box->path);
|
|
||||||
mail = maildir_open (box->path, mbox_open_mode);
|
|
||||||
if (!mail)
|
|
||||||
{
|
|
||||||
fprintf (stderr, "%s: unable to open mailbox\n", box->path);
|
|
||||||
ret = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (box->max_size)
|
|
||||||
imap_flags |= IMAP_GET_SIZE;
|
|
||||||
imap = imap_open (box, fast ? mail->maxuid + 1 : 1, imap, imap_flags);
|
|
||||||
if (!imap)
|
|
||||||
{
|
|
||||||
fprintf (stderr, "%s: skipping mailbox due to IMAP error\n",
|
|
||||||
box->path);
|
|
||||||
ret = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
info ("Synchronizing\n");
|
|
||||||
i = (delete || box->delete) ? SYNC_DELETE : 0;
|
|
||||||
i |= (expunge || box->expunge) ? SYNC_EXPUNGE : 0;
|
|
||||||
if (sync_mailbox (mail, imap, i, box->max_size, box->max_messages))
|
|
||||||
{
|
|
||||||
imap_close (imap); /* Just to be safe. Don't really know
|
|
||||||
* what the problem was.
|
|
||||||
*/
|
|
||||||
imap = NULL; /* context no longer valid */
|
|
||||||
ret = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!fast)
|
|
||||||
{
|
|
||||||
if ((expunge || box->expunge) &&
|
|
||||||
(imap->deleted || mail->deleted))
|
|
||||||
{
|
|
||||||
/* remove messages marked for deletion */
|
|
||||||
info ("Expunging %d messages from server\n", imap->deleted);
|
|
||||||
if (imap_expunge (imap))
|
|
||||||
{
|
|
||||||
imap_close (imap);
|
|
||||||
imap = NULL;
|
|
||||||
ret = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
info ("Expunging %d messages from local mailbox\n",
|
|
||||||
mail->deleted);
|
|
||||||
if (maildir_expunge (mail, 0)) {
|
|
||||||
ret = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* remove messages deleted from server. this can safely be an
|
|
||||||
* `else' clause since dead messages are marked as deleted by
|
|
||||||
* sync_mailbox.
|
|
||||||
*/
|
|
||||||
else if (delete) {
|
|
||||||
if (maildir_expunge (mail, 1)) {
|
|
||||||
ret = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} while (0);
|
|
||||||
|
|
||||||
/* we never sync the same mailbox twice, so close it now */
|
|
||||||
if (mail)
|
|
||||||
maildir_close (mail);
|
|
||||||
|
|
||||||
/* the imap connection is not closed so we can keep the connection
|
|
||||||
* open, and there is no IMAP command for un-SELECT-ing a mailbox.
|
|
||||||
*/
|
|
||||||
if (all)
|
if (all)
|
||||||
box = box->next;
|
multiple = channels->next != 0;
|
||||||
|
else if (argv[oind + 1])
|
||||||
|
multiple = 1;
|
||||||
|
else {
|
||||||
|
multiple = 0;
|
||||||
|
for (group = groups; group; group = group->next)
|
||||||
|
if (!strcmp( group->name, argv[oind] )) {
|
||||||
|
multiple = 1;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
/* gracefully close connection to the IMAP server */
|
}
|
||||||
imap_close (imap);
|
for (;;) {
|
||||||
|
boxlist = 0;
|
||||||
|
if (!all) {
|
||||||
|
if (chanptr)
|
||||||
|
channame = chanptr->string;
|
||||||
|
else {
|
||||||
|
for (group = groups; group; group = group->next)
|
||||||
|
if (!strcmp( group->name, argv[oind] )) {
|
||||||
|
chanptr = group->channels;
|
||||||
|
channame = chanptr->string;
|
||||||
|
goto gotgrp;
|
||||||
|
}
|
||||||
|
channame = argv[oind];
|
||||||
|
gotgrp: ;
|
||||||
|
}
|
||||||
|
if ((boxlist = strchr( channame, ':' )))
|
||||||
|
*boxlist++ = 0;
|
||||||
|
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 );
|
||||||
|
ret = 1;
|
||||||
|
goto gotnone;
|
||||||
|
gotchan: ;
|
||||||
|
}
|
||||||
|
merge_actions( chan, mops, sops, XOP_HAVE_TYPE, OP_MASK_TYPE, OP_MASK_TYPE );
|
||||||
|
merge_actions( chan, mops, sops, XOP_HAVE_CREATE, OP_CREATE, 0 );
|
||||||
|
merge_actions( chan, mops, sops, XOP_HAVE_EXPUNGE, OP_EXPUNGE, 0 );
|
||||||
|
|
||||||
|
mboxes = sboxes = cboxes = 0;
|
||||||
|
/* possible todo: handle master <-> slave swaps */
|
||||||
|
if (mctx) {
|
||||||
|
if (mconf == chan->master)
|
||||||
|
goto gotmctx;
|
||||||
|
free_string_list( umboxes );
|
||||||
|
umboxes = 0;
|
||||||
|
gumboxes = 0;
|
||||||
|
if (mconf->driver != chan->master->driver) {
|
||||||
|
mdriver->close_store( mctx );
|
||||||
|
mctx = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mconf = chan->master;
|
||||||
|
mdriver = mconf->driver;
|
||||||
|
if (!(mctx = mdriver->open_store( chan->master, mctx ))) {
|
||||||
|
ret = 1;
|
||||||
|
goto next;
|
||||||
|
}
|
||||||
|
gotmctx:
|
||||||
|
if (sctx) {
|
||||||
|
if (sconf == chan->slave)
|
||||||
|
goto gotsctx;
|
||||||
|
free_string_list( usboxes );
|
||||||
|
usboxes = 0;
|
||||||
|
gusboxes = 0;
|
||||||
|
if (sconf->driver != chan->slave->driver) {
|
||||||
|
sdriver->close_store( sctx );
|
||||||
|
sctx = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sconf = chan->slave;
|
||||||
|
sdriver = sconf->driver;
|
||||||
|
if (!(sctx = sdriver->open_store( chan->slave, sctx ))) {
|
||||||
|
ret = 1;
|
||||||
|
goto next;
|
||||||
|
}
|
||||||
|
gotsctx:
|
||||||
|
info( "Channel %s\n", chan->name );
|
||||||
|
if (list && multiple)
|
||||||
|
printf( "%s:\n", chan->name );
|
||||||
|
if (boxlist) {
|
||||||
|
for (boxlist = strtok( boxlist, ",\n" ); boxlist; boxlist = strtok( 0, ",\n" ))
|
||||||
|
if (list)
|
||||||
|
puts( boxlist );
|
||||||
|
else
|
||||||
|
switch (sync_boxes( mctx, boxlist, sctx, boxlist, chan )) {
|
||||||
|
case SYNC_MASTER_BAD: goto screwm;
|
||||||
|
case SYNC_SLAVE_BAD: goto screws;
|
||||||
|
case SYNC_FAIL: ret = 1;
|
||||||
|
}
|
||||||
|
} else if (chan->patterns) {
|
||||||
|
if (!gumboxes) {
|
||||||
|
if (mdriver->list( mctx, &umboxes ) != DRV_OK) {
|
||||||
|
screwm:
|
||||||
|
mdriver->close_store( mctx );
|
||||||
|
free_string_list( umboxes );
|
||||||
|
umboxes = 0;
|
||||||
|
gumboxes = 0;
|
||||||
|
mctx = 0;
|
||||||
|
ret = 1;
|
||||||
|
goto next;
|
||||||
|
} else {
|
||||||
|
gumboxes = 1;
|
||||||
|
if (mctx->conf->map_inbox)
|
||||||
|
add_string_list( &umboxes, mctx->conf->map_inbox );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!gusboxes) {
|
||||||
|
if (sdriver->list( sctx, &usboxes ) != DRV_OK) {
|
||||||
|
screws:
|
||||||
|
sdriver->close_store( sctx );
|
||||||
|
free_string_list( usboxes );
|
||||||
|
usboxes = 0;
|
||||||
|
gusboxes = 0;
|
||||||
|
sctx = 0;
|
||||||
|
ret = 1;
|
||||||
|
goto next;
|
||||||
|
} else {
|
||||||
|
gusboxes = 1;
|
||||||
|
if (sctx->conf->map_inbox)
|
||||||
|
add_string_list( &usboxes, sctx->conf->map_inbox );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mboxes = filter_boxes( umboxes, chan->patterns );
|
||||||
|
sboxes = filter_boxes( usboxes, chan->patterns );
|
||||||
|
for (mboxp = &mboxes; (mbox = *mboxp); ) {
|
||||||
|
for (sboxp = &sboxes; (sbox = *sboxp); sboxp = &sbox->next)
|
||||||
|
if (!strcmp( sbox->string, mbox->string )) {
|
||||||
|
*sboxp = sbox->next;
|
||||||
|
free( sbox );
|
||||||
|
*mboxp = mbox->next;
|
||||||
|
mbox->next = cboxes;
|
||||||
|
cboxes = mbox;
|
||||||
|
goto gotdupe;
|
||||||
|
}
|
||||||
|
mboxp = &mbox->next;
|
||||||
|
gotdupe: ;
|
||||||
|
}
|
||||||
|
for (mbox = cboxes; mbox; mbox = mbox->next)
|
||||||
|
if (list)
|
||||||
|
puts( mbox->string );
|
||||||
|
else
|
||||||
|
switch (sync_boxes( mctx, mbox->string, sctx, mbox->string, chan )) {
|
||||||
|
case SYNC_MASTER_BAD: goto screwm;
|
||||||
|
case SYNC_SLAVE_BAD: goto screws;
|
||||||
|
case SYNC_FAIL: ret = 1;
|
||||||
|
}
|
||||||
|
if ((chan->sops & OP_MASK_TYPE) && (chan->sops & OP_CREATE)) {
|
||||||
|
for (mbox = mboxes; mbox; mbox = mbox->next)
|
||||||
|
if (list)
|
||||||
|
puts( mbox->string );
|
||||||
|
else
|
||||||
|
switch (sync_boxes( mctx, mbox->string, sctx, mbox->string, chan )) {
|
||||||
|
case SYNC_MASTER_BAD: goto screwm;
|
||||||
|
case SYNC_SLAVE_BAD: goto screws;
|
||||||
|
case SYNC_FAIL: ret = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((chan->mops & OP_MASK_TYPE) && (chan->mops & OP_CREATE)) {
|
||||||
|
for (mbox = sboxes; mbox; mbox = mbox->next)
|
||||||
|
if (list)
|
||||||
|
puts( mbox->string );
|
||||||
|
else
|
||||||
|
switch (sync_boxes( mctx, mbox->string, sctx, mbox->string, chan )) {
|
||||||
|
case SYNC_MASTER_BAD: goto screwm;
|
||||||
|
case SYNC_SLAVE_BAD: goto screws;
|
||||||
|
case SYNC_FAIL: ret = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
if (list)
|
||||||
|
printf( "%s <=> %s\n", chan->master_name, chan->slave_name );
|
||||||
|
else
|
||||||
|
switch (sync_boxes( mctx, chan->master_name, sctx, chan->slave_name, chan )) {
|
||||||
|
case SYNC_MASTER_BAD: goto screwm;
|
||||||
|
case SYNC_SLAVE_BAD: goto screws;
|
||||||
|
case SYNC_FAIL: ret = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
next:
|
||||||
|
free_string_list( cboxes );
|
||||||
|
free_string_list( mboxes );
|
||||||
|
free_string_list( sboxes );
|
||||||
|
if (all) {
|
||||||
|
if (!(chan = chan->next))
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
if (chanptr && (chanptr = chanptr->next))
|
||||||
|
continue;
|
||||||
|
gotnone:
|
||||||
|
if (!argv[++oind])
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free_string_list( usboxes );
|
||||||
|
if (sctx)
|
||||||
|
sdriver->close_store( sctx );
|
||||||
|
free_string_list( umboxes );
|
||||||
|
if (mctx)
|
||||||
|
mdriver->close_store( mctx );
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
471
src/mbsync.1
Normal file
471
src/mbsync.1
Normal file
|
@ -0,0 +1,471 @@
|
||||||
|
.ig
|
||||||
|
\" mbsync - mailbox synchronizer
|
||||||
|
\" Copyright (C) 2000-2002 Michael R. Elkins <me@mutt.org>
|
||||||
|
\" Copyright (C) 2002-2004 Oswald Buddenhagen <ossi@users.sf.net>
|
||||||
|
\" Copyright (C) 2004 Theodore Y. Ts'o <tytso@mit.edu>
|
||||||
|
\"
|
||||||
|
\" This program is free software; you can redistribute it and/or modify
|
||||||
|
\" it under the terms of the GNU General Public License as published by
|
||||||
|
\" the Free Software Foundation; either version 2 of the License, or
|
||||||
|
\" (at your option) any later version.
|
||||||
|
\"
|
||||||
|
\" This program is distributed in the hope that it will be useful,
|
||||||
|
\" but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
\" GNU General Public License for more details.
|
||||||
|
\"
|
||||||
|
\" You should have received a copy of the GNU General Public License
|
||||||
|
\" along with this program; if not, write to the Free Software
|
||||||
|
\" Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
\"
|
||||||
|
\" As a special exception, mbsync may be linked with the OpenSSL library,
|
||||||
|
\" despite that library's more restrictive license.
|
||||||
|
..
|
||||||
|
.TH mbsync 1 "2004 Mar 27"
|
||||||
|
..
|
||||||
|
.SH NAME
|
||||||
|
mbsync - synchronize IMAP4 and Maildir mailboxes
|
||||||
|
..
|
||||||
|
.SH SYNOPSIS
|
||||||
|
\fBmbsync\fR [\fIoptions\fR ...] {{\fIchannel\fR[\fB:\fIbox\fR[{\fB,\fR|\fB\\n\fR}...]]|\fIgroup\fR} ...|\fB-a\fR}
|
||||||
|
..
|
||||||
|
.SH DESCRIPTION
|
||||||
|
\fBmbsync\fR is a command line application which synchronizes mailboxes;
|
||||||
|
currently Maildir and IMAP4 mailboxes are supported.
|
||||||
|
New messages, message deletions and flag changes can be propagated both ways;
|
||||||
|
the operation set can be selected in a fine-grained manner.
|
||||||
|
.br
|
||||||
|
Synchronization is based on unique message identifiers (UIDs), so no
|
||||||
|
identification conflicts can occur (as opposed to some other mail synchronizers).
|
||||||
|
OTOH, \fBmbsync\fR is susceptible to UID validity changes (that \fIshould\fR
|
||||||
|
never happen, but see "Compatibility" in the README).
|
||||||
|
Synchronization state is kept in one local text file per mailbox pair;
|
||||||
|
multiple replicas of a mailbox can be maintained.
|
||||||
|
..
|
||||||
|
.SH OPTIONS
|
||||||
|
.TP
|
||||||
|
\fB-c\fR, \fB--config\fR \fIfile\fR
|
||||||
|
Read configuration from \fIfile\fR.
|
||||||
|
By default, the configuration is read from ~/.mbsyncrc.
|
||||||
|
.TP
|
||||||
|
\fB-a\fR, \fB--all\fR
|
||||||
|
Select all configured channels. Any channel/group specifications on the command
|
||||||
|
line are ignored.
|
||||||
|
.TP
|
||||||
|
\fB-l\fR, \fB--list\fR
|
||||||
|
Don't synchronize anything, but list all mailboxes in the selected channels
|
||||||
|
and exit.
|
||||||
|
.TP
|
||||||
|
\fB-C\fR[\fBm\fR][\fBs\fR], \fB--create\fR[\fB-master\fR|\fB-slave\fR]
|
||||||
|
Override any \fBCreate\fR options from the config file. See below.
|
||||||
|
.TP
|
||||||
|
\fB-X\fR[\fBm\fR][\fBs\fR], \fB--expunge\fR[\fB-master\fR|\fB-slave\fR]
|
||||||
|
Override any \fBExpunge\fR options from the config file. See below.
|
||||||
|
.TP
|
||||||
|
{\fB-n\fR|\fB-N\fR|\fB-d\fR|\fB-f\fR|\fB-0\fR|\fB-F\fR},\
|
||||||
|
{\fB--new\fR|\fB--renew\fR|\fB--delete\fR|\fB--flags\fR|\fB--noop\fR|\fB--full\fR}
|
||||||
|
.TP
|
||||||
|
\r{\fB-L\fR|\fB-H\fR}[\fBn\fR][\fBN\fR][\fBd\fR][\fBf\fR],\
|
||||||
|
{\fB--pull\fR|\fB--push\fR}[\fB-new\fR|\fB-renew\fR|\fB-delete\fR|\fB-flags\fR]
|
||||||
|
Override any \fBSync\fR options from the config file. See below.
|
||||||
|
.TP
|
||||||
|
\fB-h\fR, \fB--help\fR
|
||||||
|
Display a summary of command line options.
|
||||||
|
.TP
|
||||||
|
\fB-v\fR, \fB--version\fR
|
||||||
|
Display version information.
|
||||||
|
.TP
|
||||||
|
\fB-V\fR, \fB--verbose\fR
|
||||||
|
Enable \fIverbose\fR mode, which displays the IMAP4 network traffic.
|
||||||
|
.TP
|
||||||
|
\fB-D\fR, \fB--debug\fR
|
||||||
|
Enable printing \fIdebug\fR information.
|
||||||
|
.TP
|
||||||
|
\fB-q\fR, \fB--quiet\fR
|
||||||
|
Suppress informational messages.
|
||||||
|
If specified twice, suppress warning messages as well.
|
||||||
|
..
|
||||||
|
.SH CONFIGURATION
|
||||||
|
The configuration file is mandatory; \fBmbsync\fR will not run without it.
|
||||||
|
Lines starting with a hash mark (\fB#\fR) are comments and are ignored entirely.
|
||||||
|
Configuration items are keywords followed by one or more arguments;
|
||||||
|
arguments containing spaces must be enclosed in double quotes (\fB"\fR).
|
||||||
|
All keywords (including those used as arguments) are case-insensitive.
|
||||||
|
There are a few global options, the rest applies to particular sections.
|
||||||
|
Sections are started by a section keyword and are terminated by an empty line
|
||||||
|
or end of file.
|
||||||
|
Every section defines an object with a an identifier unique within that
|
||||||
|
object class.
|
||||||
|
.P
|
||||||
|
There are two basic object classes: Stores and Channels. A Store defines
|
||||||
|
a collection of mailboxes; basically a folder, either local or remote.
|
||||||
|
A Channel connects two Stores, describing the way the two are synchronized.
|
||||||
|
.br
|
||||||
|
There are two auxiliary object classes: Accounts and Groups. An Account
|
||||||
|
describes the connection part of remote Stores, so a server connection can be
|
||||||
|
shared between multiple Stores. A Group aggregates multiple Channels to
|
||||||
|
save typing on the command line.
|
||||||
|
..
|
||||||
|
.SS All Stores
|
||||||
|
These options can be used in all supported Store types.
|
||||||
|
.br
|
||||||
|
In this context, the term "remote" describes the second Store within a Channel,
|
||||||
|
and not necessarily a remote server.
|
||||||
|
.br
|
||||||
|
The special mailbox \fBINBOX\fR exists in every Store; its physical location
|
||||||
|
in the file system is Store type specific.
|
||||||
|
..
|
||||||
|
.TP
|
||||||
|
\fBPath\fR \fIpath\fR
|
||||||
|
The location of the Store in the (server's) file system.
|
||||||
|
If this is no absolute path, the reference point is Store type specific.
|
||||||
|
This string is prepended to the mailbox names addressed in this Store,
|
||||||
|
but is not considered part of them; this is important for \fBPatterns\fR
|
||||||
|
in the Channels section.
|
||||||
|
Note that you \fBmust\fR append a slash if you want to specify an entire
|
||||||
|
directory.
|
||||||
|
(Default: \fI""\fR)
|
||||||
|
..
|
||||||
|
.TP
|
||||||
|
\fBMaxSize\fR \fIsize\fR[\fBk\fR|\fBm\fR][\fBb\fR]
|
||||||
|
Messages larger than that will not be propagated into this Store.
|
||||||
|
This is useful for weeding out messages with large attachments.
|
||||||
|
\fBK\fR and \fBM\fR can be appended to the size to specify KiBytes resp.
|
||||||
|
MeBytes instead of bytes. \fBB\fR is accepted but superflous.
|
||||||
|
If \fIsize\fR is 0, the maximum message size is \fBunlimited\fR.
|
||||||
|
(Default: \fI0\fR)
|
||||||
|
..
|
||||||
|
.TP
|
||||||
|
\fBMapInbox\fR \fImailbox\fR
|
||||||
|
Create a virtual mailbox (relative to \fBPath\fR), which is backed by
|
||||||
|
the \fBINBOX\fR. Makes sense in conjunction with \fBPatterns\fR in the
|
||||||
|
Channels section.
|
||||||
|
..
|
||||||
|
.TP
|
||||||
|
\fBTrash\fR \fImailbox\fR
|
||||||
|
Specifies a mailbox (relative to \fBPath\fR) to copy deleted messages to
|
||||||
|
prior to expunging. See \fBINHERENT PROBLEMS\fR below.
|
||||||
|
(Default: none)
|
||||||
|
..
|
||||||
|
.TP
|
||||||
|
\fBTrashNewOnly\fR \fIyes\fR|\fIno\fR
|
||||||
|
When trashing, copy only not yet propagated messages. This makes sense if the
|
||||||
|
remote Store has a \fBTrash\fR as well (with \fBTrashNewOnly\fR \fIno\fR).
|
||||||
|
(Default: \fIno\fR)
|
||||||
|
..
|
||||||
|
.TP
|
||||||
|
\fBTrashRemoteNew\fR \fIyes\fR|\fIno\fR
|
||||||
|
When expunging the remote Store, copy not yet propagated messages to this
|
||||||
|
Store's \fBTrash\fR. When using this, the remote Store does not need an own
|
||||||
|
\fBTrash\fR at all, yet all messages are archived.
|
||||||
|
(Default: \fIno\fR)
|
||||||
|
..
|
||||||
|
.SS Maildir Stores
|
||||||
|
The reference point for relative \fBPath\fRs is $HOME.
|
||||||
|
.P
|
||||||
|
As \fBmbsync\fR needs UIDs, but no standardized UID storage scheme exists for
|
||||||
|
Maildir, \fBmbsync\fR supports two schemes, each with its pros and cons.
|
||||||
|
.br
|
||||||
|
The \fBnative\fR scheme is stolen from the latest Maildir patches to \fBc-client\fR
|
||||||
|
and is therefore compatible with \fBpine\fR. The UID validity is stored in a
|
||||||
|
file named .uidvalidity; the UIDs are encoded in the file names of the messages.
|
||||||
|
.br
|
||||||
|
The \fBalternative\fR scheme is based on the UID mapping used by \fBisync\fR
|
||||||
|
versions 0.8 and 0.9.x. The invariant parts of the file names of the messages
|
||||||
|
are used as keys into a Berkeley database named .isyncuidmap.db, which holds
|
||||||
|
the UID validity as well.
|
||||||
|
.br
|
||||||
|
The \fBnative\fR scheme is faster, more space efficient, endianess independent
|
||||||
|
and "human readable", but will be disrupted if a message is copied from another
|
||||||
|
mailbox without getting a new file name; this would result in duplicated UIDs
|
||||||
|
sooner or later, which in turn results in a UID validity change, making
|
||||||
|
synchronization fail.
|
||||||
|
The \fBalternative\fR scheme would fail if a MUA changed a message's file name
|
||||||
|
in a part \fBmbsync\fR considers invariant; this would be interpreted as a
|
||||||
|
message deletion and a new message, resulting in unnecessary traffic.
|
||||||
|
.br
|
||||||
|
\fBMutt\fR is known to work fine with both schemes.
|
||||||
|
.br
|
||||||
|
Use \fBmdconvert\fR to convert mailboxes from one scheme to the other.
|
||||||
|
..
|
||||||
|
.TP
|
||||||
|
\fBMaildirStore\fR \fIname\fR
|
||||||
|
Define the Maildir Store \fIname\fR, opening a section for its parameters.
|
||||||
|
..
|
||||||
|
.TP
|
||||||
|
\fBAltMap\fR \fIyes\fR|\fIno\fR
|
||||||
|
Use the \fBalternative\fR UID storage scheme for mailboxes in this Store.
|
||||||
|
This does not affect mailboxes that do already have a UID storage scheme;
|
||||||
|
use \fBmdconvert\fR to change it.
|
||||||
|
(Default: \fIno\fR)
|
||||||
|
..
|
||||||
|
.TP
|
||||||
|
\fBInbox\fR \fIpath\fR
|
||||||
|
The location of the \fBINBOX\fR. This is \fInot\fR relative to \fBPath\fR.
|
||||||
|
(Default: \fI~/Maildir\fR)
|
||||||
|
..
|
||||||
|
.SS IMAP4 Accounts
|
||||||
|
.TP
|
||||||
|
\fBIMAPAccount\fR \fIname\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.
|
||||||
|
..
|
||||||
|
.TP
|
||||||
|
\fBPort\fR \fIport\fR
|
||||||
|
Specify the TCP port number of the IMAP server. (Default: 143 for imap,
|
||||||
|
993 for imaps)
|
||||||
|
..
|
||||||
|
.TP
|
||||||
|
\fBUser\fR \fIusername\fR
|
||||||
|
Specify the login name on the IMAP server. (Default: current local user)
|
||||||
|
..
|
||||||
|
.TP
|
||||||
|
\fBPass\fR \fIpassword\fR
|
||||||
|
Specify the password for \fIusername\fR on the IMAP server.
|
||||||
|
Note that this option is \fBNOT\fR required.
|
||||||
|
If no password is specified in the configuration file, \fBmbsync\fR
|
||||||
|
will prompt you for it.
|
||||||
|
..
|
||||||
|
.TP
|
||||||
|
\fBTunnel\fR \fIcommand\fR
|
||||||
|
Specify a command to run to establish a connection rather than opening a TCP
|
||||||
|
socket. This allows you to run an IMAP session over an SSH tunnel, for
|
||||||
|
example. This makes most other IMAPAccount options superflous.
|
||||||
|
..
|
||||||
|
.TP
|
||||||
|
\fBRequireCRAM\fR \fIyes\fR|\fIno\fR
|
||||||
|
If set to \fIyes\fR, \fBmbsync\fR will abort the connection if no CRAM-MD5
|
||||||
|
authentication is possible. (Default: \fIno\fR)
|
||||||
|
..
|
||||||
|
.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)
|
||||||
|
..
|
||||||
|
.TP
|
||||||
|
\fBCertificateFile\fR \fIpath\fR
|
||||||
|
File containing X.509 CA certificates used to verify server identities.
|
||||||
|
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)
|
||||||
|
..
|
||||||
|
.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)
|
||||||
|
..
|
||||||
|
.TP
|
||||||
|
\fBUseTLSv1\fR \fIyes\fR|\fIno\fR
|
||||||
|
Use TLSv1 for communication with the IMAP server over SSL?
|
||||||
|
(Default: \fIyes\fR)
|
||||||
|
..
|
||||||
|
.SS IMAP Stores
|
||||||
|
The reference point for relative \fBPath\fRs is whatever the server likes it
|
||||||
|
to be; probably the user's $HOME or $HOME/Mail on that server. The location
|
||||||
|
of \fBINBOX\fR is up to the server as well and is usually irrelevant.
|
||||||
|
.TP
|
||||||
|
\fBIMAPStore\fR \fIname\fR
|
||||||
|
Define the IMAP4 Store \fIname\fR, opening a section for its parameters.
|
||||||
|
..
|
||||||
|
.TP
|
||||||
|
\fBAccount\fR \fIaccount\fR
|
||||||
|
Specify which IMAP4 Account to use. Instead of defining an Account and
|
||||||
|
referencing it here, it is also possible to specify all the Account options
|
||||||
|
directly in the Store's section - this makes sense if an Account is used for
|
||||||
|
one Store only anyway.
|
||||||
|
..
|
||||||
|
.TP
|
||||||
|
\fBUseNamespace\fR \fIyes\fR|\fIno\fR
|
||||||
|
Selects whether the server's first "personal" NAMESPACE should be prefixed to
|
||||||
|
mailbox names. Disabling this makes sense for some broken IMAP servers.
|
||||||
|
This option is meaningless if a \fBPath\fR was specified.
|
||||||
|
(Default: \fIyes\fR)
|
||||||
|
..
|
||||||
|
.SS Channels
|
||||||
|
.TP
|
||||||
|
\fBChannel\fR \fIname\fR
|
||||||
|
Define the Channel \fIname\fR, opening a section for its parameters.
|
||||||
|
..
|
||||||
|
.TP
|
||||||
|
{\fBMaster\fR|\fBSlave\fR} \fB:\fIstore\fB:\fR[\fImailbox\fR]
|
||||||
|
Specify the Master resp. Slave Store to be connected by this Channel.
|
||||||
|
If \fImailbox\fR is omitted, \fBINBOX\fR is assumed.
|
||||||
|
The \fImailbox\fR specification can be overridden by \fBPatterns\fR, which
|
||||||
|
in turn can be overridden by a mailbox list in a Channel reference (a Group
|
||||||
|
specification or the command line).
|
||||||
|
..
|
||||||
|
.TP
|
||||||
|
\fBPattern\fR[\fBs\fR] [\fB!\fR]\fIpattern\fR ...
|
||||||
|
Instead of synchronizing only one mailbox pair, synchronize all mailboxes
|
||||||
|
that match the \fIpattern\fR(s). The mailbox names are the same on both
|
||||||
|
Master and Slave. Patterns are IMAP4 patterns, i.e., \fB*\fR matches anything
|
||||||
|
and \fB%\fR matches anything up to the next hierarchy delimiter. Prepending
|
||||||
|
\fB!\fR to a pattern makes it an exclusion. Multiple patterns can be specified
|
||||||
|
(either by supplying multiple arguments or by using \fBPattern\fR multiple
|
||||||
|
times); later matches take precedence.
|
||||||
|
Example: "\fBPatterns\fR\ \fI%\ !Trash\fR"
|
||||||
|
..
|
||||||
|
.TP
|
||||||
|
\fBMaxSize\fR \fIsize\fR[\fBk\fR|\fBm\fR][\fBb\fR]
|
||||||
|
Analogous to the homonymous option in the Stores section, but applies equally
|
||||||
|
to Master and Slave. Note that this actually modifies the Stores, so take care
|
||||||
|
not to provide conflicting settings if you use the Stores in multiple Channels.
|
||||||
|
..
|
||||||
|
.TP
|
||||||
|
\fBMaxMessages\fR \fIcount\fR
|
||||||
|
Sets the maximum number of messages to keep in each Slave mailbox.
|
||||||
|
This is useful for mailboxes where you keep a complete archive on the server,
|
||||||
|
but want to mirror only the last messages (for instance, for mailing lists).
|
||||||
|
The messages that were the first to arrive in the mailbox (independently of
|
||||||
|
the actual date of the message) will be deleted first.
|
||||||
|
Messages that are flagged (marked as important) and recent messages will not
|
||||||
|
be automatically deleted.
|
||||||
|
If \fIcount\fR is 0, the maximum number of messages is \fBunlimited\fR
|
||||||
|
(Default: \fI0\fR).
|
||||||
|
..
|
||||||
|
.TP
|
||||||
|
\fBSync\fR {\fINone\fR|[\fIPull\fR] [\fIPush\fR] [\fINew\fR] [\fIReNew\fR] [\fIDelete\fR] [\fIFlags\fR]|\fIFull\fR}
|
||||||
|
Select the synchronization operation(s) to perform:
|
||||||
|
.br
|
||||||
|
\fBPull\fR - propagate changes from Master to Slave.
|
||||||
|
.br
|
||||||
|
\fBPush\fR - propagate changes from Slave to Master.
|
||||||
|
.br
|
||||||
|
\fBNew\fR - propagate newly appeared messages.
|
||||||
|
.br
|
||||||
|
\fBReNew\fR - previously refused messages are re-evaluated for propagation.
|
||||||
|
Useful after flagging affected messages in the source Store or enlarging
|
||||||
|
MaxSize in the destination Store.
|
||||||
|
.br
|
||||||
|
\fBDelete\fR - propagate message deletions. This applies only to messages that
|
||||||
|
are actually gone, i.e., were expunged. The affected messages in the remote
|
||||||
|
Store are marked as deleted only, i.e., they won't be really deleted until
|
||||||
|
that Store is expunged.
|
||||||
|
.br
|
||||||
|
\fBFlags\fR - propagate flag changes. Note that Deleted/Trashed is a flag as
|
||||||
|
well; this is particularily interesting if you use \fBmutt\fR with the
|
||||||
|
maildir_trash option.
|
||||||
|
.br
|
||||||
|
\fBAll\fR (\fB--full\fR on the command line) - all of the above.
|
||||||
|
This is the global default.
|
||||||
|
.br
|
||||||
|
\fBNone\fR (\fB--noop\fR on the command line) - don't propagate anything.
|
||||||
|
Useful if you want to expunge only.
|
||||||
|
.IP
|
||||||
|
\fBPull\fR and \fBPush\fR are direction flags, while \fBNew\fR, \fBReNew\fR,
|
||||||
|
\fBDelete\fR and \fBFlags\fR are type flags. The two flag classes make up a
|
||||||
|
two-dimensional matrix (a table). Its cells are the individual actions to
|
||||||
|
perform. There are two styles of asserting the cells:
|
||||||
|
.br
|
||||||
|
In the first style, the flags select entire rows/colums in the matrix. Only
|
||||||
|
the cells which are selected both horizontally and vertically are asserted.
|
||||||
|
Specifying no flags from a class is like specifying all flags from this class.
|
||||||
|
For example, "\fBSync\fR\ \fBPull\fR\ \fBNew\fR\ \fBFlags\fR" will propagate
|
||||||
|
new messages and flag changes from the Master to the Slave,
|
||||||
|
"\fBSync\fR\ \fBNew\fR\ \fBDelete\fR" will propagate message arrivals and
|
||||||
|
deletions both ways, and "\fBSync\fR\ \fBPush\fR" will propagate all changes
|
||||||
|
from the Slave to the Master.
|
||||||
|
.br
|
||||||
|
In the second style, direction flags are concatenated with type flags; every
|
||||||
|
compound flag immediately asserts a cell in the matrix. In addition to at least
|
||||||
|
one compound flag, the individual flags can be used as well, but as opposed to
|
||||||
|
the first style, they immediately assert all cells in their respective
|
||||||
|
row/column. For example,
|
||||||
|
"\fBSync\fR\ \fBPullNew\fR\ \fBPullDelete\fR\ \fBPush\fR" will propagate
|
||||||
|
message arrivals and deletions from the Master to the Slave and any changes
|
||||||
|
from the Slave to the Master.
|
||||||
|
Note that it is not allowed to assert a cell in two ways, e.g.
|
||||||
|
"\fBSync\fR\ \fBPullNew\fR\ \fBPull\fR" and
|
||||||
|
"\fBSync\fR\ \fBPullNew\fR\ \fBDelete\fR\ \fBPush\fR" induce error messages.
|
||||||
|
..
|
||||||
|
.TP
|
||||||
|
\fBCreate\fR {\fINone\fR|\fIMaster\fR|\fISlave\fR|\fIBoth\fR}
|
||||||
|
Automatically create missing mailboxes [on the Master/Slave].
|
||||||
|
Otherwise print an error message and skip that mailbox pair if a mailbox
|
||||||
|
does not exist.
|
||||||
|
(Global default: \fINone\fR)
|
||||||
|
..
|
||||||
|
.TP
|
||||||
|
\fBExpunge\fR {\fINone\fR|\fIMaster\fR|\fISlave\fR|\fIBoth\fR}
|
||||||
|
Permanently remove all messages [on the Master/Slave] marked for deletion.
|
||||||
|
(Global default: \fINone\fR)
|
||||||
|
..
|
||||||
|
.P
|
||||||
|
\fBSync\fR, \fBCreate\fR and \fBExpunge\fR can be used outside any section for
|
||||||
|
a global effect. The global settings are overridden by Channel-specific options,
|
||||||
|
which in turn are overridden by command line switches.
|
||||||
|
..
|
||||||
|
.TP
|
||||||
|
\fBSyncState\fR {\fB*\fR|\fIpath\fR}
|
||||||
|
Set the location of this Channel's synchronization state files. \fB*\fR means
|
||||||
|
that the state should be saved in a file named .mbsyncstate in the
|
||||||
|
Slave mailbox itself; this has the advantage that you needn't to care for the
|
||||||
|
state file if you delete the mailbox, but it works only with Maildir mailboxes,
|
||||||
|
obviously. Otherwise this is interpreted as a string to prepend to the Slave
|
||||||
|
mailbox name to make up a complete path.
|
||||||
|
.br
|
||||||
|
This option can be used outside any section for a global effect. In this case
|
||||||
|
the appended string is made up according to the pattern
|
||||||
|
\fB:\fImaster\fB:\fImaster-box\fB_:\fIslave\fB:\fIslave-box\fR.
|
||||||
|
.br
|
||||||
|
(Global default: \fI~/.mbsync/\fR).
|
||||||
|
..
|
||||||
|
.SS Groups
|
||||||
|
.TP
|
||||||
|
\fBGroup\fR \fIname\fR [\fIchannel\fR[\fB:\fIbox\fR[\fB,\fR...]]] ...
|
||||||
|
Define the Group \fIname\fR, opening a section for its parameters.
|
||||||
|
Note that even though Groups have an own namespace, they will "hide" Channels
|
||||||
|
with the same name on the command line.
|
||||||
|
.br
|
||||||
|
One or more Channels can be specified on the same line.
|
||||||
|
.br
|
||||||
|
If you supply one or more \fIbox\fRes to a \fIchannel\fR, they will be used
|
||||||
|
instead of what is specified in the Channel. The same can be done on the command
|
||||||
|
line, except that there newlines can be used as mailbox name separators as well.
|
||||||
|
..
|
||||||
|
.TP
|
||||||
|
\fBChannel\fR[\fBs\fR] \fIchannel\fR[\fB:\fIbox\fR[\fB,\fR...]] ...
|
||||||
|
Add the specified channels to the group. This option can be specified multiple
|
||||||
|
times within a Group.
|
||||||
|
..
|
||||||
|
.SH SSL CERTIFICATES
|
||||||
|
[to be done]
|
||||||
|
..
|
||||||
|
.SH INHERENT PROBLEMS
|
||||||
|
Changes done after \fBmbsync\fR has retrieved the message list will not be
|
||||||
|
synchronised until the next time \fBmbsync\fR is invoked.
|
||||||
|
.P
|
||||||
|
Using \fBTrash\fR on IMAP Stores bears a race condition: messages will be
|
||||||
|
lost if they are marked as deleted after the message list was retrieved but
|
||||||
|
before the mailbox is expunged. There is no risk as long as the IMAP mailbox
|
||||||
|
is not simultaneously accessed by \fBmbsync\fR and another mail client.
|
||||||
|
..
|
||||||
|
.SH FILES
|
||||||
|
.TP
|
||||||
|
.B ~/.mbsyncrc
|
||||||
|
Default configuration file
|
||||||
|
.TP
|
||||||
|
.B ~/.mbsync/
|
||||||
|
Directory containing synchronization state files
|
||||||
|
..
|
||||||
|
.SH SEE ALSO
|
||||||
|
mdconvert(1), isync(1), mutt(1), maildir(5)
|
||||||
|
.P
|
||||||
|
Up to date information on \fBmbsync\fR can be found at http://isync.sf.net/
|
||||||
|
..
|
||||||
|
.SH AUTHOR
|
||||||
|
Written by Michael R. Elkins <me@mutt.org>,
|
||||||
|
.br
|
||||||
|
rewritten and maintained by Oswald Buddenhagen <ossi@users.sf.net>,
|
||||||
|
.br
|
||||||
|
contributions by Theodore Y. Ts'o <tytso@mit.edu>.
|
82
src/mbsyncrc.sample
Normal file
82
src/mbsyncrc.sample
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
# Global configuration section
|
||||||
|
# Values here are used as defaults for any following Channel section that
|
||||||
|
# doesn't specify them.
|
||||||
|
Expunge None
|
||||||
|
Create Both
|
||||||
|
|
||||||
|
MaildirStore local
|
||||||
|
Path ~/Mail/
|
||||||
|
Trash Trash
|
||||||
|
|
||||||
|
|
||||||
|
IMAPStore work
|
||||||
|
Host work.host.com
|
||||||
|
Pass xxxxxxxx
|
||||||
|
CertificateFile /etc/ssl/certs/ca-certificates.crt
|
||||||
|
|
||||||
|
Channel work
|
||||||
|
Master :work:
|
||||||
|
Slave :local:work
|
||||||
|
Expunge Slave
|
||||||
|
Sync PullNew Push
|
||||||
|
|
||||||
|
|
||||||
|
IMAPStore personal
|
||||||
|
Host host.play.com
|
||||||
|
Port 6789
|
||||||
|
RequireSSL no
|
||||||
|
|
||||||
|
Channel personal
|
||||||
|
Master :personal:
|
||||||
|
Slave :local:personal
|
||||||
|
Expunge Both
|
||||||
|
MaxMessages 150
|
||||||
|
MaxSize 200k
|
||||||
|
|
||||||
|
IMAPStore remote
|
||||||
|
Tunnel "ssh -q host.remote.com /usr/sbin/imapd"
|
||||||
|
|
||||||
|
Channel remote
|
||||||
|
Master :remote:
|
||||||
|
Slave :local:remote
|
||||||
|
|
||||||
|
|
||||||
|
Group boxes
|
||||||
|
Channels work personal remote
|
||||||
|
|
||||||
|
|
||||||
|
IMAPStore st1
|
||||||
|
Host st1.domain.com
|
||||||
|
RequireCRAM yes
|
||||||
|
CertificateFile ~/.st1-certificate.crt
|
||||||
|
|
||||||
|
IMAPStore st2
|
||||||
|
Host imap.another-domain.com
|
||||||
|
Path non-standard/
|
||||||
|
RequireSSL no
|
||||||
|
UseTLSv1 no
|
||||||
|
|
||||||
|
Channel rst
|
||||||
|
Master :st1:somebox
|
||||||
|
Slave :st2:
|
||||||
|
|
||||||
|
|
||||||
|
IMAPAccount server
|
||||||
|
Host imaps:foo.bar.com
|
||||||
|
CertificateFile ~/.server-certificate.crt
|
||||||
|
|
||||||
|
IMAPStore server
|
||||||
|
Account server
|
||||||
|
MapInbox inbox
|
||||||
|
Trash ~/trash
|
||||||
|
TrashRemoteNew yes
|
||||||
|
|
||||||
|
MaildirStore mirror
|
||||||
|
Path ~/Maildir/
|
||||||
|
|
||||||
|
Channel o2o
|
||||||
|
Master :server:
|
||||||
|
Slave :mirror:
|
||||||
|
Patterns %
|
||||||
|
|
||||||
|
Group partial o2o:inbox,sent-mail,foobar
|
51
src/mdconvert.1
Normal file
51
src/mdconvert.1
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
.ig
|
||||||
|
\" mdconvert - Maildir mailbox UID storage scheme converter
|
||||||
|
\" Copyright (C) 2004 Oswald Buddenhagen <ossi@users.sf.net>
|
||||||
|
\"
|
||||||
|
\" This program is free software; you can redistribute it and/or modify
|
||||||
|
\" it under the terms of the GNU General Public License as published by
|
||||||
|
\" the Free Software Foundation; either version 2 of the License, or
|
||||||
|
\" (at your option) any later version.
|
||||||
|
\"
|
||||||
|
\" This program is distributed in the hope that it will be useful,
|
||||||
|
\" but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
\" GNU General Public License for more details.
|
||||||
|
\"
|
||||||
|
\" You should have received a copy of the GNU General Public License
|
||||||
|
\" along with this program; if not, write to the Free Software
|
||||||
|
\" Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
..
|
||||||
|
.TH mdconvert 1 "2004 Mar 27"
|
||||||
|
..
|
||||||
|
.SH NAME
|
||||||
|
mdconvert - Maildir mailbox UID storage scheme converter
|
||||||
|
..
|
||||||
|
.SH SYNOPSIS
|
||||||
|
\fBmdconvert\fR [\fIoptions\fR ...] \fImailbox\fR ...
|
||||||
|
..
|
||||||
|
.SH DESCRIPTION
|
||||||
|
\fBmdconvert\fR converts Maildir mailboxes between the two UID storage schemes
|
||||||
|
supported by \fBmbsync\fR. See \fBmbsync\fR's manual page for details on these
|
||||||
|
schemes.
|
||||||
|
..
|
||||||
|
.SH OPTIONS
|
||||||
|
.TP
|
||||||
|
\fB-a\fR, \fB--alt\fR
|
||||||
|
Convert to the \fBalternative\fR (Berkeley DB based) UID storage scheme.
|
||||||
|
.TP
|
||||||
|
\fB-n\fR, \fB--native\fR
|
||||||
|
Convert to the \fBnative\fR (file name based) UID storage scheme.
|
||||||
|
This is the default.
|
||||||
|
.TP
|
||||||
|
\fB-h\fR, \fB--help\fR
|
||||||
|
Displays a summary of command line options.
|
||||||
|
.TP
|
||||||
|
\fB-v\fR, \fB--version\fR
|
||||||
|
Displays version information.
|
||||||
|
..
|
||||||
|
.SH SEE ALSO
|
||||||
|
mbsync(1)
|
||||||
|
..
|
||||||
|
.SH AUTHOR
|
||||||
|
Written and maintained by Oswald Buddenhagen <ossi@users.sf.net>.
|
256
src/mdconvert.c
Normal file
256
src/mdconvert.c
Normal file
|
@ -0,0 +1,256 @@
|
||||||
|
/*
|
||||||
|
* mdconvert - Maildir UID scheme converter
|
||||||
|
* Copyright (C) 2004 Oswald Buddenhagen <ossi@users.sf.net>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#include <db.h>
|
||||||
|
|
||||||
|
#define EXE "mdconvert"
|
||||||
|
|
||||||
|
static int
|
||||||
|
nfsnprintf( char *buf, int blen, const char *fmt, ... )
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
va_list va;
|
||||||
|
|
||||||
|
va_start( va, fmt );
|
||||||
|
if (blen <= 0 || (unsigned)(ret = vsnprintf( buf, blen, fmt, va )) >= (unsigned)blen) {
|
||||||
|
fputs( "Fatal: buffer too small. Please report a bug.\n", stderr );
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
va_end( va );
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *subdirs[] = { "cur", "new" };
|
||||||
|
static struct flock lck;
|
||||||
|
static DBT key, value;
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
convert( const char *box, int altmap )
|
||||||
|
{
|
||||||
|
DB *db;
|
||||||
|
DIR *d;
|
||||||
|
struct dirent *e;
|
||||||
|
const char *u, *ru;
|
||||||
|
char *p, *s, *dpath, *spath, *dbpath;
|
||||||
|
int i, n, ret, sfd, dfd, bl, ml, uv[2], uid;
|
||||||
|
struct stat st;
|
||||||
|
char buf[_POSIX_PATH_MAX], buf2[_POSIX_PATH_MAX];
|
||||||
|
char umpath[_POSIX_PATH_MAX], uvpath[_POSIX_PATH_MAX], tdpath[_POSIX_PATH_MAX];
|
||||||
|
|
||||||
|
if (stat( box, &st ) || !S_ISDIR(st.st_mode)) {
|
||||||
|
fprintf( stderr, "'%s' is no Maildir mailbox.\n", box );
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
nfsnprintf( umpath, sizeof(umpath), "%s/.isyncuidmap.db", box );
|
||||||
|
nfsnprintf( uvpath, sizeof(uvpath), "%s/.uidvalidity", box );
|
||||||
|
if (altmap)
|
||||||
|
dpath = umpath, spath = uvpath, dbpath = tdpath;
|
||||||
|
else
|
||||||
|
spath = umpath, dpath = uvpath, dbpath = umpath;
|
||||||
|
nfsnprintf( tdpath, sizeof(tdpath), "%s.tmp", dpath );
|
||||||
|
if ((sfd = open( spath, O_RDWR )) < 0) {
|
||||||
|
if (errno != ENOENT)
|
||||||
|
perror( spath );
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (fcntl( sfd, F_SETLKW, &lck )) {
|
||||||
|
perror( spath );
|
||||||
|
goto sbork;
|
||||||
|
}
|
||||||
|
if ((dfd = open( tdpath, O_RDWR|O_CREAT, 0600 )) < 0) {
|
||||||
|
perror( tdpath );
|
||||||
|
goto sbork;
|
||||||
|
}
|
||||||
|
if (db_create( &db, 0, 0 )) {
|
||||||
|
fputs( "Error: db_create() failed\n", stderr );
|
||||||
|
goto tbork;
|
||||||
|
}
|
||||||
|
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 );
|
||||||
|
tbork:
|
||||||
|
unlink( tdpath );
|
||||||
|
close( dfd );
|
||||||
|
sbork:
|
||||||
|
close( sfd );
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
key.data = (void *)"UIDVALIDITY";
|
||||||
|
key.size = 11;
|
||||||
|
if (altmap) {
|
||||||
|
if ((n = read( sfd, buf, sizeof(buf) )) <= 0 ||
|
||||||
|
(buf[n] = 0, sscanf( buf, "%d\n%d", &uv[0], &uv[1] ) != 2))
|
||||||
|
{
|
||||||
|
fprintf( stderr, "Error: cannot read UIDVALIDITY of '%s'.\n", box );
|
||||||
|
goto dbork;
|
||||||
|
}
|
||||||
|
value.data = uv;
|
||||||
|
value.size = sizeof(uv);
|
||||||
|
if ((ret = db->put( db, 0, &key, &value, 0 ))) {
|
||||||
|
db->err( db, ret, "Error: cannot write UIDVALIDITY for '%s'", box );
|
||||||
|
goto dbork;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ((ret = db->get( db, 0, &key, &value, 0 ))) {
|
||||||
|
db->err( db, ret, "Error: cannot read UIDVALIDITY of '%s'", box );
|
||||||
|
goto dbork;
|
||||||
|
}
|
||||||
|
n = sprintf( buf, "%d\n%d\n", ((int *)value.data)[0], ((int *)value.data)[1] );
|
||||||
|
if (write( dfd, buf, n ) != n) {
|
||||||
|
fprintf( stderr, "Error: cannot write UIDVALIDITY for '%s'.\n", box );
|
||||||
|
goto dbork;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
again:
|
||||||
|
for (i = 0; i < 2; i++) {
|
||||||
|
bl = nfsnprintf( buf, sizeof(buf), "%s/%s/", box, subdirs[i] );
|
||||||
|
if (!(d = opendir( buf ))) {
|
||||||
|
perror( "opendir" );
|
||||||
|
goto dbork;
|
||||||
|
}
|
||||||
|
while ((e = readdir( d ))) {
|
||||||
|
if (*e->d_name == '.')
|
||||||
|
continue;
|
||||||
|
nfsnprintf( buf + bl, sizeof(buf) - bl, "%s", e->d_name );
|
||||||
|
memcpy( buf2, buf, bl );
|
||||||
|
p = strstr( e->d_name, ",U=" );
|
||||||
|
if (p)
|
||||||
|
for (u = p, ru = p + 3; isdigit( (unsigned char)*ru ); ru++);
|
||||||
|
else
|
||||||
|
u = ru = strchr( e->d_name, ':' );
|
||||||
|
if (u)
|
||||||
|
ml = u - e->d_name;
|
||||||
|
else
|
||||||
|
ru = "", ml = INT_MAX;
|
||||||
|
if (altmap) {
|
||||||
|
if (!p)
|
||||||
|
continue;
|
||||||
|
key.data = e->d_name;
|
||||||
|
key.size = (size_t)(strchr( e->d_name, ',' ) - e->d_name);
|
||||||
|
uid = atoi( p + 3 );
|
||||||
|
value.data = &uid;
|
||||||
|
value.size = sizeof(uid);
|
||||||
|
if ((ret = db->put( db, 0, &key, &value, 0 ))) {
|
||||||
|
db->err( db, ret, "Error: cannot write UID for '%s'", box );
|
||||||
|
goto ebork;
|
||||||
|
}
|
||||||
|
nfsnprintf( buf2 + bl, sizeof(buf2) - bl, "%.*s%s", ml, e->d_name, ru );
|
||||||
|
} else {
|
||||||
|
s = strpbrk( e->d_name, ",:" );
|
||||||
|
key.data = e->d_name;
|
||||||
|
key.size = s ? (size_t)(s - e->d_name) : strlen( e->d_name );
|
||||||
|
if ((ret = db->get( db, 0, &key, &value, 0 ))) {
|
||||||
|
if (ret != DB_NOTFOUND) {
|
||||||
|
db->err( db, ret, "Error: cannot read UID for '%s'", box );
|
||||||
|
goto ebork;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
uid = *(int *)value.data;
|
||||||
|
nfsnprintf( buf2 + bl, sizeof(buf2) - bl, "%.*s,U=%d%s", ml, e->d_name, uid, ru );
|
||||||
|
}
|
||||||
|
if (rename( buf, buf2 )) {
|
||||||
|
if (errno == ENOENT)
|
||||||
|
goto again;
|
||||||
|
perror( buf );
|
||||||
|
ebork:
|
||||||
|
closedir( d );
|
||||||
|
goto dbork;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
closedir( d );
|
||||||
|
}
|
||||||
|
|
||||||
|
db->close( db, 0 );
|
||||||
|
close( dfd );
|
||||||
|
if (rename( tdpath, dpath )) {
|
||||||
|
perror( dpath );
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (unlink( spath ))
|
||||||
|
perror( spath );
|
||||||
|
close( sfd );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main( int argc, char **argv )
|
||||||
|
{
|
||||||
|
int oint, ret, altmap = 0;
|
||||||
|
|
||||||
|
for (oint = 1; oint < argc; oint++) {
|
||||||
|
if (!strcmp( argv[oint], "-h" ) || !strcmp( argv[oint], "--help" )) {
|
||||||
|
puts(
|
||||||
|
"Usage: " EXE " [-a] mailbox...\n"
|
||||||
|
" -a, --alt convert to alternative (DB based) UID scheme\n"
|
||||||
|
" -n, --native convert to native (file name based) UID scheme (default)\n"
|
||||||
|
" -h, --help show this help message\n"
|
||||||
|
" -v, --version display version"
|
||||||
|
);
|
||||||
|
return 0;
|
||||||
|
} else if (!strcmp( argv[oint], "-v" ) || !strcmp( argv[oint], "--version" )) {
|
||||||
|
puts( EXE " " VERSION " - Maildir UID scheme converter" );
|
||||||
|
return 0;
|
||||||
|
} else if (!strcmp( argv[oint], "-a" ) || !strcmp( argv[oint], "--alt" )) {
|
||||||
|
altmap = 1;
|
||||||
|
} else if (!strcmp( argv[oint], "-n" ) || !strcmp( argv[oint], "--native" )) {
|
||||||
|
altmap = 0;
|
||||||
|
} else if (!strcmp( argv[oint], "--" )) {
|
||||||
|
oint++;
|
||||||
|
break;
|
||||||
|
} else if (argv[oint][0] == '-') {
|
||||||
|
fprintf( stderr, "Unrecognized option '%s'. Try " EXE " -h\n", argv[oint] );
|
||||||
|
return 1;
|
||||||
|
} else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (oint == argc) {
|
||||||
|
fprintf( stderr, "Mailbox specification missing. Try " EXE " -h\n" );
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
#if SEEK_SET != 0
|
||||||
|
lck.l_whence = SEEK_SET;
|
||||||
|
#endif
|
||||||
|
#if F_WRLCK != 0
|
||||||
|
lck.l_type = F_WRLCK;
|
||||||
|
#endif
|
||||||
|
ret = 0;
|
||||||
|
for (; oint < argc; oint++)
|
||||||
|
ret |= convert( argv[oint], altmap );
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
1220
src/sync.c
1220
src/sync.c
File diff suppressed because it is too large
Load Diff
389
src/util.c
Normal file
389
src/util.c
Normal file
|
@ -0,0 +1,389 @@
|
||||||
|
/*
|
||||||
|
* mbsync - mailbox synchronizer
|
||||||
|
* Copyright (C) 2000-2002 Michael R. Elkins <me@mutt.org>
|
||||||
|
* Copyright (C) 2002-2004 Oswald Buddenhagen <ossi@users.sf.net>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
* As a special exception, mbsync may be linked with the OpenSSL library,
|
||||||
|
* despite that library's more restrictive license.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "isync.h"
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <pwd.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
int Verbose, Quiet, Debug;
|
||||||
|
|
||||||
|
void
|
||||||
|
debug( const char *msg, ... )
|
||||||
|
{
|
||||||
|
va_list va;
|
||||||
|
|
||||||
|
if (Debug) {
|
||||||
|
va_start( va, msg );
|
||||||
|
vprintf( msg, va );
|
||||||
|
va_end( va );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
info( const char *msg, ... )
|
||||||
|
{
|
||||||
|
va_list va;
|
||||||
|
|
||||||
|
if (!Quiet) {
|
||||||
|
va_start( va, msg );
|
||||||
|
vprintf( msg, va );
|
||||||
|
va_end( va );
|
||||||
|
fflush( stdout );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
infoc( char c )
|
||||||
|
{
|
||||||
|
if (!Quiet) {
|
||||||
|
putchar( c );
|
||||||
|
fflush( stdout );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
warn( const char *msg, ... )
|
||||||
|
{
|
||||||
|
va_list va;
|
||||||
|
|
||||||
|
if (Quiet < 2) {
|
||||||
|
va_start( va, msg );
|
||||||
|
vfprintf( stderr, msg, va );
|
||||||
|
va_end( va );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
next_arg( char **s )
|
||||||
|
{
|
||||||
|
char *ret;
|
||||||
|
|
||||||
|
if (!s || !*s)
|
||||||
|
return 0;
|
||||||
|
while (isspace( (unsigned char) **s ))
|
||||||
|
(*s)++;
|
||||||
|
if (!**s) {
|
||||||
|
*s = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (**s == '"') {
|
||||||
|
++*s;
|
||||||
|
ret = *s;
|
||||||
|
*s = strchr( *s, '"' );
|
||||||
|
} else {
|
||||||
|
ret = *s;
|
||||||
|
while (**s && !isspace( (unsigned char) **s ))
|
||||||
|
(*s)++;
|
||||||
|
}
|
||||||
|
if (*s) {
|
||||||
|
if (**s)
|
||||||
|
*(*s)++ = 0;
|
||||||
|
if (!**s)
|
||||||
|
*s = 0;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
add_string_list( string_list_t **list, const char *str )
|
||||||
|
{
|
||||||
|
string_list_t *elem;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
len = strlen( str );
|
||||||
|
elem = nfmalloc( sizeof(*elem) + len );
|
||||||
|
elem->next = *list;
|
||||||
|
*list = elem;
|
||||||
|
memcpy( elem->string, str, len + 1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
free_string_list( string_list_t *list )
|
||||||
|
{
|
||||||
|
string_list_t *tlist;
|
||||||
|
|
||||||
|
for (; list; list = tlist) {
|
||||||
|
tlist = list->next;
|
||||||
|
free( list );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
free_generic_messages( message_t *msgs )
|
||||||
|
{
|
||||||
|
message_t *tmsg;
|
||||||
|
|
||||||
|
for (; msgs; msgs = tmsg) {
|
||||||
|
tmsg = msgs->next;
|
||||||
|
free( msgs );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
strip_cr( msg_data_t *msgdata )
|
||||||
|
{
|
||||||
|
int i, o;
|
||||||
|
|
||||||
|
if (msgdata->crlf) {
|
||||||
|
for (i = o = 0; i < msgdata->len; i++)
|
||||||
|
if (msgdata->data[i] != '\r')
|
||||||
|
msgdata->data[o++] = msgdata->data[i];
|
||||||
|
msgdata->len = o;
|
||||||
|
msgdata->crlf = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef HAVE_VASPRINTF
|
||||||
|
static int
|
||||||
|
vasprintf( char **strp, const char *fmt, va_list ap )
|
||||||
|
{
|
||||||
|
int len;
|
||||||
|
char tmp[1024];
|
||||||
|
|
||||||
|
if ((len = vsnprintf( tmp, sizeof(tmp), fmt, ap) ) < 0)
|
||||||
|
*strp = 0;
|
||||||
|
else if ((*strp = malloc( len + 1 ))) {
|
||||||
|
if (len >= sizeof(tmp))
|
||||||
|
vsprintf( *strp, fmt, ap );
|
||||||
|
else
|
||||||
|
memcpy( *strp, tmp, len + 1 );
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void
|
||||||
|
oob( void )
|
||||||
|
{
|
||||||
|
fputs( "Fatal: buffer too small. Please report a bug.\n", stderr );
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
nfsnprintf( char *buf, int blen, const char *fmt, ... )
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
va_list va;
|
||||||
|
|
||||||
|
va_start( va, fmt );
|
||||||
|
if (blen <= 0 || (unsigned)(ret = vsnprintf( buf, blen, fmt, va )) >= (unsigned)blen)
|
||||||
|
oob();
|
||||||
|
va_end( va );
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ATTR_NORETURN
|
||||||
|
oom( void )
|
||||||
|
{
|
||||||
|
fputs( "Fatal: Out of memory\n", stderr );
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
nfmalloc( size_t sz )
|
||||||
|
{
|
||||||
|
void *ret;
|
||||||
|
|
||||||
|
if (!(ret = malloc( sz )))
|
||||||
|
oom();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
nfcalloc( size_t sz )
|
||||||
|
{
|
||||||
|
void *ret;
|
||||||
|
|
||||||
|
if (!(ret = calloc( sz, 1 )))
|
||||||
|
oom();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
nfrealloc( void *mem, size_t sz )
|
||||||
|
{
|
||||||
|
char *ret;
|
||||||
|
|
||||||
|
if (!(ret = realloc( mem, sz )) && sz)
|
||||||
|
oom();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
nfstrdup( const char *str )
|
||||||
|
{
|
||||||
|
char *ret;
|
||||||
|
|
||||||
|
if (!(ret = strdup( str )))
|
||||||
|
oom();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
nfvasprintf( char **str, const char *fmt, va_list va )
|
||||||
|
{
|
||||||
|
int ret = vasprintf( str, fmt, va );
|
||||||
|
if (!*str)
|
||||||
|
oom();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
nfasprintf( char **str, const char *fmt, ... )
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
va_list va;
|
||||||
|
|
||||||
|
va_start( va, fmt );
|
||||||
|
ret = nfvasprintf( str, fmt, va );
|
||||||
|
va_end( va );
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
static struct passwd *
|
||||||
|
cur_user( void )
|
||||||
|
{
|
||||||
|
char *p;
|
||||||
|
struct passwd *pw;
|
||||||
|
uid_t uid;
|
||||||
|
|
||||||
|
uid = getuid();
|
||||||
|
if ((!(p = getenv("LOGNAME")) || !(pw = getpwnam( p )) || pw->pw_uid != uid) &&
|
||||||
|
(!(p = getenv("USER")) || !(pw = getpwnam( p )) || pw->pw_uid != uid) &&
|
||||||
|
!(pw = getpwuid( uid )))
|
||||||
|
{
|
||||||
|
fputs ("Cannot determinate current user\n", stderr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return pw;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
static char *
|
||||||
|
my_strndup( const char *s, size_t nchars )
|
||||||
|
{
|
||||||
|
char *r = nfmalloc( nchars + 1 );
|
||||||
|
memcpy( r, s, nchars );
|
||||||
|
r[nchars] = 0;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
expand_strdup( const char *s )
|
||||||
|
{
|
||||||
|
struct passwd *pw;
|
||||||
|
const char *p, *q;
|
||||||
|
char *r;
|
||||||
|
|
||||||
|
if (*s == '~') {
|
||||||
|
s++;
|
||||||
|
if (!*s) {
|
||||||
|
p = 0;
|
||||||
|
q = Home;
|
||||||
|
} else if (*s == '/') {
|
||||||
|
p = s;
|
||||||
|
q = Home;
|
||||||
|
} else {
|
||||||
|
if ((p = strchr( s, '/' ))) {
|
||||||
|
r = my_strndup( s, (int)(p - s) );
|
||||||
|
pw = getpwnam( r );
|
||||||
|
free( r );
|
||||||
|
} else
|
||||||
|
pw = getpwnam( s );
|
||||||
|
if (!pw)
|
||||||
|
return 0;
|
||||||
|
q = pw->pw_dir;
|
||||||
|
}
|
||||||
|
nfasprintf( &r, "%s%s", q, p ? p : "" );
|
||||||
|
return r;
|
||||||
|
} else
|
||||||
|
return nfstrdup( s );
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
compare_ints( const void *l, const void *r )
|
||||||
|
{
|
||||||
|
return *(int *)l - *(int *)r;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
sort_ints( int *arr, int len )
|
||||||
|
{
|
||||||
|
qsort( arr, len, sizeof(int), compare_ints );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
unsigned char i, j, s[256];
|
||||||
|
} rs;
|
||||||
|
|
||||||
|
void
|
||||||
|
arc4_init( void )
|
||||||
|
{
|
||||||
|
int i, fd;
|
||||||
|
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" );
|
||||||
|
exit( 3 );
|
||||||
|
}
|
||||||
|
if (read( fd, dat, 128 ) != 128) {
|
||||||
|
fprintf( stderr, "Fatal: cannot read random number source.\n" );
|
||||||
|
exit( 3 );
|
||||||
|
}
|
||||||
|
close( fd );
|
||||||
|
|
||||||
|
for (i = 0; i < 256; i++)
|
||||||
|
rs.s[i] = i;
|
||||||
|
for (i = j = 0; i < 256; i++) {
|
||||||
|
si = rs.s[i];
|
||||||
|
j += si + dat[i & 127];
|
||||||
|
rs.s[i] = rs.s[j];
|
||||||
|
rs.s[j] = si;
|
||||||
|
}
|
||||||
|
rs.i = rs.j = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < 256; i++)
|
||||||
|
arc4_getbyte();
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char
|
||||||
|
arc4_getbyte( void )
|
||||||
|
{
|
||||||
|
unsigned char si, sj;
|
||||||
|
|
||||||
|
rs.i++;
|
||||||
|
si = rs.s[rs.i];
|
||||||
|
rs.j += si;
|
||||||
|
sj = rs.s[rs.j];
|
||||||
|
rs.s[rs.i] = sj;
|
||||||
|
rs.s[rs.j] = si;
|
||||||
|
return rs.s[(si + sj) & 0xff];
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user