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.in
|
||||
config.cache
|
||||
config.guess
|
||||
config.log
|
||||
config.status
|
||||
config.sub
|
||||
configure
|
||||
configure.lineno
|
||||
configure-stamp
|
||||
isync.spec
|
||||
isync-*.tar.gz
|
||||
patch-stamp
|
||||
stamp-h
|
||||
stamp-h.in
|
||||
stamp-h1
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
SUBDIRS = src
|
||||
man_MANS = isync.1
|
||||
EXTRA_DIST = debian isyncrc.sample isync.spec $(man_MANS)
|
||||
bin_SCRIPTS = get-cert
|
||||
EXTRA_DIST = debian isync.spec $(bin_SCRIPTS)
|
||||
|
||||
log:
|
||||
@perl -p -e "s/^(\\S+)\\s+(\\S.+\\S)\\s+(\\S+)\\s*\$$/\$$1:'\$$2 <\$$3>'\\n/" < ../CVSROOT/accounts > .usermap
|
||||
|
@ -16,6 +16,9 @@ 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:
|
||||
make dist
|
||||
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]
|
||||
|
||||
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/
|
||||
|
||||
Author: Michael Elkins <me@mutt.org>
|
||||
Current maintainer: Oswald Buddenhagen <ossi@users.sf.net>
|
||||
See AUTHORS for contact information.
|
||||
|
||||
``isync'' is a command line application which synchronizes a local
|
||||
maildir-style mailbox with a remote IMAP4 mailbox, suitable for use in
|
||||
IMAP-disconnected mode. Multiple copies of the remote IMAP4 mailbox can be
|
||||
maintained, and all flags are synchronized.
|
||||
``mbsync'' 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.
|
||||
``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
|
||||
* Supports imaps: (port 993) TLS/SSL connections
|
||||
* Supports STARTTLS (RFC2595) for confidentiality
|
||||
* Supports NAMESPACE (RFC2342)
|
||||
* Supports CRAM-MD5 (RFC2095) for authentication
|
||||
isync is the project name, while mbsync is the current executable name; this
|
||||
change was necessary because of massive changes in the user interface. An
|
||||
isync executable still exists; it is a compatibility wrapper around mbsync.
|
||||
|
||||
* 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
|
||||
|
||||
``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-IMAP 1.2.3
|
||||
* WU-IMAP 2000
|
||||
* Domino IMAP4 Server Release 5.0.8
|
||||
Courier 1.4.3 is known to be buggy, version 1.7.3 works fine.
|
||||
|
||||
c-client (UW-IMAP, Pine) is mostly fine, but tends to change UIDVALIDITY
|
||||
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
|
||||
|
||||
``isync'' has successfully been compiled on:
|
||||
|
||||
* Linux
|
||||
* Solaris 2.7
|
||||
* OpenBSD 2.8
|
||||
* FreeBSD 4.3
|
||||
At some point, ``isync'' has successfully run on:
|
||||
Linux, Solaris 2.7, OpenBSD 2.8, FreeBSD 4.3, Cygwin
|
||||
|
||||
* Requirements
|
||||
|
||||
OpenSSL for TLS/SSL support (optional)
|
||||
|
||||
* INSTALLING
|
||||
* Installation
|
||||
|
||||
./configure
|
||||
make install
|
||||
|
||||
* HELP
|
||||
* Help
|
||||
|
||||
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.
|
||||
maybe the error handling needs to be cleaned up in general.
|
||||
make SSL certificate validation more automatic.
|
||||
|
||||
don't require maildir_trash. currently MaxMessages gets into the way of
|
||||
simply removing it; that is fixable with some shuffling, though.
|
||||
add asynchronous operation to remote mailbox drivers. this is actually
|
||||
what prevents us from simply using c-client and thus becoming mailsync.
|
||||
|
||||
refactor mailbox support. create proper mailbox drivers; handle imap and
|
||||
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.
|
||||
handle custom flags (keywords).
|
||||
|
||||
add asynchrounous operation to remote mailbox drivers. this is actually
|
||||
what prevents us from simply using c-client for the previous point and
|
||||
thus simply becoming mailsync.
|
||||
fix maildir_{open_store,list} to handle partial names (last char not slash).
|
||||
|
||||
store message flags in sync database, so _un_setting them will be properly
|
||||
synced as well.
|
||||
add a way to automatically create and sync subfolders.
|
||||
|
||||
handle custom imap flags. currently, isync just fails horribly if it
|
||||
encounters some.
|
||||
could store TUID even when UIDPLUS is supported. would avoid duplicated
|
||||
messages after abort before new UID arrives.
|
||||
|
||||
add options for fine-grained control of syncing operations (--new, --delete &
|
||||
--flags) and direction (--push & --pull).
|
||||
decouple TUID search from append. that's a prerequisite for usable
|
||||
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
|
||||
arriving during a fetch will not be fetched in the current run any more.
|
||||
create dummies describing MIME structure of messages bigger than MaxSize.
|
||||
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
|
||||
IDs - this is a pretty common condition with uw-imap.
|
||||
maybe throw out the ctx->recent stuff - it's used only for one info message.
|
||||
|
||||
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)
|
||||
AM_CONFIG_HEADER(config.h)
|
||||
AM_INIT_AUTOMAKE(isync, 0.9.2)
|
||||
AM_INIT_AUTOMAKE(isync, 1.0.0alpha)
|
||||
|
||||
AM_MAINTAINER_MODE
|
||||
|
||||
AM_PROG_CC_STDC
|
||||
if test "$GCC" = yes; then
|
||||
CFLAGS="$CFLAGS -pipe -W -Wall -Wshadow -Wmissing-prototypes"
|
||||
CFLAGS="$CFLAGS -pipe -W -Wall -Wshadow -Wstrict-prototypes"
|
||||
fi
|
||||
|
||||
AC_CHECK_FUNCS(getopt_long)
|
||||
AC_CHECK_FUNCS(vasprintf)
|
||||
|
||||
AC_CHECK_LIB(socket, socket)
|
||||
AC_CHECK_LIB(nsl, inet_ntoa)
|
||||
AC_CHECK_LIB(socket, socket, [SOCK_LIBS="-lsocket"])
|
||||
AC_CHECK_LIB(nsl, inet_ntoa, [SOCK_LIBS="$SOCK_LIBS -lnsl"])
|
||||
AC_SUBST(SOCK_LIBS)
|
||||
|
||||
ssl=false
|
||||
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])
|
||||
if test "x$ob_cv_with_ssl" != xno; then
|
||||
if test -d "$ob_cv_with_ssl/lib"; then
|
||||
|
@ -25,7 +26,7 @@ if test "x$ob_cv_with_ssl" != xno; then
|
|||
fi
|
||||
AC_CHECK_LIB(crypto, ERR_error_string, [cryptolib=" -lcrypto"])
|
||||
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])
|
||||
ssl=true
|
||||
],[
|
||||
|
@ -34,19 +35,29 @@ if test "x$ob_cv_with_ssl" != xno; then
|
|||
fi
|
||||
])
|
||||
fi
|
||||
AC_SUBST(SSL_LIBS)
|
||||
|
||||
AC_CACHE_CHECK(for db_create in -ldb, ac_cv_db_db_create,
|
||||
[ac_cv_db_dbcreate=no
|
||||
AC_CACHE_CHECK([for Berkley DB 4.2], ac_cv_berkdb4,
|
||||
[ac_cv_berkdb4=no
|
||||
AC_TRY_LINK([#include <db.h>],
|
||||
[db_create();],[ac_cv_db_db_create=yes])])
|
||||
if test $ac_cv_db_db_create=yes; then
|
||||
LIBS="$LIBS -ldb"
|
||||
else
|
||||
AC_MSG_ERROR([Berkley DB not found.
|
||||
You must install libdb including the respective development files/headers.])
|
||||
[DB *db;
|
||||
db->truncate(db, 0, 0, 0);
|
||||
db->open(db, 0, "foo", "foo", DB_HASH, DB_CREATE, 0)],
|
||||
[ac_cv_berkdb4=yes])])
|
||||
if test "x$ac_cv_berkdb4" = xno; then
|
||||
AC_MSG_ERROR([Berkley DB 4.2 not found.
|
||||
You must install libdb4.2 including the respective development files/headers.])
|
||||
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
|
||||
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>
|
||||
Uploaders: Nicolas Boullis <nboullis@debian.org>, Theodore Y. Ts'o <tytso@mit.edu>
|
||||
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
|
||||
Architecture: any
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}
|
||||
Suggests: mutt
|
||||
Description: Synchronize a local maildir with a remote IMAP4 mailbox
|
||||
A command line application which synchronizes a local maildir-style
|
||||
mailbox with a remote IMAP4 mailbox, suitable for use in disconnected
|
||||
mode. Multiple copies of the remote IMAP4 mailbox can be maintained,
|
||||
and all flags and messages are synchronized.
|
||||
Description: Synchronize Maildir and IMAP4 mailboxes
|
||||
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.
|
||||
It is useful for working in disconnected mode, such as on a laptop or with a
|
||||
non-permanent internet collection (dIMAP).
|
||||
.
|
||||
Features:
|
||||
* Fast mode for fetching new mail only
|
||||
* Supports imaps: (port 993) TLS/SSL connections
|
||||
* Supports STARTTLS (RFC2595) for confidentiality
|
||||
* Supports NAMESPACE (RFC2342)
|
||||
* Supports CRAM-MD5 (RFC2095) for authentication
|
||||
* 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)
|
||||
|
|
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_installchangelogs ChangeLog
|
||||
dh_installdocs AUTHORS NEWS README TODO
|
||||
dh_installexamples isyncrc.sample
|
||||
dh_installexamples src/mbsyncrc.sample src/compat/isyncrc.sample
|
||||
dh_installman
|
||||
dh_installdebconf
|
||||
dh_strip
|
||||
dh_compress
|
||||
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
|
||||
|
||||
%description
|
||||
isync is a command line utility for synchronizing a remote IMAP mailbox with a
|
||||
local maildir-style mailbox. This is useful for working in disconnected mode,
|
||||
such as on a laptop. Modifications made locally and remotely are synchronized
|
||||
so that no message status flags are lost.
|
||||
isync is a command line utility which synchronizes mailboxes; currently
|
||||
Maildir and IMAP4 mailboxes are supported.
|
||||
New messages, message deletions and flag changes can be propagated both ways.
|
||||
It is useful for working in disconnected mode, such as on a laptop or with a
|
||||
non-permanent internet collection (dIMAP).
|
||||
|
||||
%prep
|
||||
%setup
|
||||
%build
|
||||
./configure --prefix=/usr
|
||||
make RPM_OPT_FLAGS="$RPM_OPT_FLAGS"
|
||||
|
||||
%install
|
||||
make DESTDIR=$RPM_BUILD_ROOT install
|
||||
|
@ -28,6 +28,11 @@ make DESTDIR=$RPM_BUILD_ROOT install
|
|||
rm -rf $RPM_BUILD_ROOT
|
||||
|
||||
%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/mbsync
|
||||
/usr/bin/mdconvert
|
||||
/usr/bin/get-cert
|
||||
/usr/man/man1/isync.1.gz
|
||||
/usr/man/man1/mbsync.1.gz
|
||||
/usr/man/man1/mdconvert.1.gz
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
.deps
|
||||
Makefile
|
||||
Makefile.in
|
||||
isync
|
||||
mbsync
|
||||
mdconvert
|
||||
|
|
|
@ -1,5 +1,16 @@
|
|||
bin_PROGRAMS = isync
|
||||
isync_SOURCES = main.c imap.c sync.c maildir.c list.c cram.c config.c dotlock.c
|
||||
noinst_HEADERS = isync.h dotlock.h
|
||||
INCLUDES=$(RPM_OPT_FLAGS)
|
||||
DISTCLEANFILES = *~
|
||||
if with_compat
|
||||
compat_dir = compat
|
||||
endif
|
||||
SUBDIRS = $(compat_dir)
|
||||
|
||||
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
|
||||
\" 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) 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
|
||||
|
@ -16,26 +17,27 @@
|
|||
\" 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.
|
||||
..
|
||||
.TH isync 1 "2002 Dec 22"
|
||||
.TH isync 1 "2004 Mar 27"
|
||||
..
|
||||
.SH NAME
|
||||
isync - synchronize IMAP4 and maildir mailboxes
|
||||
isync - synchronize IMAP4 and Maildir mailboxes
|
||||
..
|
||||
.SH SYNOPSIS
|
||||
\fBisync\fR [\fIoptions...\fR] \fImailbox\fR [\fImailbox ...\fR]
|
||||
.br
|
||||
\fBisync\fR [\fIoptions...\fR] \fI-a\fR
|
||||
.br
|
||||
\fBisync\fR [\fIoptions...\fR] \fI-l\fR
|
||||
\fBisync\fR [\fIoptions\fR ...] {\fImailbox\fR ...|\fI-a\fR|\fI-l\fR}
|
||||
..
|
||||
.SH DESCRIPTION
|
||||
\fBisync\fR is a command line application which synchronizes a local
|
||||
maildir-style mailbox with a remote IMAP4 mailbox, suitable for use in
|
||||
IMAP-disconnected mode. Multiple copies of the remote IMAP4 mailbox can
|
||||
\fBisync\fR is a command line application which synchronizes local
|
||||
Maildir mailboxes with remote IMAP4 mailboxes, suitable for use in
|
||||
IMAP-disconnected mode. Multiple copies of the remote IMAP4 mailboxes can
|
||||
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
|
||||
.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.
|
||||
.TP
|
||||
\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.
|
||||
.TP
|
||||
\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.
|
||||
.TP
|
||||
\fB-d\fR, \fB--delete\fR
|
||||
Causes \fBisync\fR to delete messages from the local maildir mailbox
|
||||
which do not exist on the IMAP server. By default, \fIdead\fR messages
|
||||
are \fBnot\fR deleted.
|
||||
Causes \fBisync\fR to propagate message deletions.
|
||||
By default, \fIdead\fR messages are \fBnot\fR deleted.
|
||||
.TP
|
||||
\fB-e\fR, \fB--expunge\fR
|
||||
Causes \fBisync\fR to permanently remove all messages marked for deletion
|
||||
in both the local maildir mailbox and the remote IMAP mailbox. By default,
|
||||
\fIdeleted\fR messages are \fBnot\fR expunged.
|
||||
Causes \fBisync\fR to permanently remove all messages marked for deletion.
|
||||
By default, \fIdeleted\fR messages are \fBnot\fR expunged.
|
||||
.TP
|
||||
\fB-f\fR, \fB--fast\fR
|
||||
Causes \fBisync\fR to skip the step of synchronzing message flags between the
|
||||
local maildir mailbox and the IMAP mailbox. Only new messages existing on the
|
||||
server will be fetched into the local mailbox.
|
||||
Only fetch new messages existing on the server into the local mailbox.
|
||||
Message deletions and flag changes will not be propagated.
|
||||
.TP
|
||||
\fB-h\fR, \fB--help\fR
|
||||
Displays a summary of command line options
|
||||
.TP
|
||||
\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
|
||||
\fB-q\fR, \fB--quiet\fR
|
||||
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
|
||||
(Default: INBOX)
|
||||
.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
|
||||
.TP
|
||||
\fB-u\fR, \fB--user\fR \fIuser\fR
|
||||
|
@ -116,32 +116,49 @@ Displays \fBisync\fR version information.
|
|||
.TP
|
||||
\fB-V\fR, \fB--verbose\fR
|
||||
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
|
||||
\fBisync\fR reads \fI~/.isyncrc\fR to load default configuration data.
|
||||
Each line of the configuration file consists of a command.
|
||||
\fBisync\fR by default reads \fI~/.isyncrc\fR to load configuration data.
|
||||
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:
|
||||
.TP
|
||||
\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.
|
||||
..
|
||||
.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
|
||||
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
|
||||
\fBafter\fR the \fBHost\fR command. Note that some servers support SSL on
|
||||
the default port 143. \fBisync\fR will always attempt to use SSL if available.
|
||||
\fBafter\fR the \fBHost\fR command).
|
||||
Note that modern servers support SSL on the default port 143.
|
||||
\fBisync\fR will always attempt to use SSL if available.
|
||||
..
|
||||
.TP
|
||||
\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
|
||||
\fBBox\fR \fImailbox\fR
|
||||
Defines the name of the remote IMAP mailbox associated with the local
|
||||
maildir mailbox (Default: INBOX)
|
||||
Maildir mailbox (Default: INBOX)
|
||||
..
|
||||
.TP
|
||||
\fBUser\fR \fIusername\fR
|
||||
|
@ -161,19 +178,18 @@ command line.
|
|||
..
|
||||
.TP
|
||||
\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).
|
||||
..
|
||||
.TP
|
||||
\fBDelete\fR \fIyes\fR|\fIno\fR
|
||||
Specifies whether messages in the local copy of the mailbox which don't
|
||||
exist on the server are automatically deleted. (Default: no).
|
||||
Specifies whether message deletions are propagated. (Default: no).
|
||||
\fBNOTE:\fR The \fI-d\fR command line option overrides this setting when
|
||||
set to \fIno\fR.
|
||||
..
|
||||
.TP
|
||||
\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
|
||||
set to \fIno\fR.
|
||||
..
|
||||
|
@ -181,7 +197,7 @@ set to \fIno\fR.
|
|||
\fBMailDir\fR \fIdirectory\fR
|
||||
Specifies the location of your local mailboxes if a relative path is
|
||||
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).
|
||||
..
|
||||
.TP
|
||||
|
@ -190,28 +206,28 @@ Specifies the location of your IMAP mailboxes
|
|||
specified in \fIBox\fR commands (Default: \fI""\fR).
|
||||
\fBNOTE:\fR You \fBmust\fR append the hierarchy delimiter (usually
|
||||
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).
|
||||
..
|
||||
.TP
|
||||
\fBMaxMessages\fR \fIcount\fR
|
||||
Sets the number of messages \fBisync\fR should keep in a 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 (independent of the
|
||||
actual date of the message) will automatically be deleted if you
|
||||
pass \fBisync\fR the delete (-d, --delete) flag.
|
||||
Messages that are flagged (marked as important) will not be automatically
|
||||
deleted.
|
||||
If \fIcount\fR is 0, the maximum number of messages is \fBunlimited\fR
|
||||
(Default: 0).
|
||||
Sets the number of messages \fBisync\fR should keep in the local copy of a
|
||||
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: 0)
|
||||
..
|
||||
.TP
|
||||
\fBMaxSize\fR \fIbytes\fR
|
||||
Sets a threshold for the maximum message size (in bytes) for which \fBisync\fR
|
||||
should transfer over the wire. This is useful for weeding out messages with
|
||||
large attachments. If \fIbytes\fR is 0, the maximum file size is \fBunlimited\fR.
|
||||
Messages larger than that many bytes will not be transferred over the wire.
|
||||
This is useful for weeding out messages with large attachments.
|
||||
If \fIbytes\fR is 0, the maximum file size is \fBunlimited\fR.
|
||||
(Default: 0)
|
||||
..
|
||||
.TP
|
||||
\fBTunnel\fR \fIcommand\fR
|
||||
|
@ -220,19 +236,20 @@ socket. This allows you to run an IMAP session over an SSH tunnel, for
|
|||
example.
|
||||
.TP
|
||||
\fBUseNamespace\fR \fIyes\fR|\fIno\fR
|
||||
Selects whether \fBisync\fR should select mailboxes using the namespace given
|
||||
by the NAMESPACE command. This is useful with broken IMAP servers. (Default:
|
||||
\fIyes\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 \fIFolder\fR was specified.
|
||||
(Default: \fIyes\fR)
|
||||
..
|
||||
.TP
|
||||
\fBRequireCRAM\fR \fIyes\fR|\fIno\fR
|
||||
If set to \fIyes\fR, \fBisync\fR will require that the server accept CRAM-MD5
|
||||
intead of PLAIN to authenticate the user.
|
||||
If set to \fIyes\fR, \fBisync\fR will abort the connection if no CRAM-MD5
|
||||
authentication is possible. (Default: \fIno\fR)
|
||||
..
|
||||
.TP
|
||||
\fBRequireSSL\fR \fIyes\fR|\fIno\fR
|
||||
\fBisync\fR will abort the connection if a TLS/SSL session to the IMAP
|
||||
server can not be established. (Default: \fIyes\fR)
|
||||
\fBisync\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
|
||||
|
@ -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
|
||||
all mailboxes from the local \fIMailDir\fR and remote \fIFolder\fR and map
|
||||
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).
|
||||
..
|
||||
.TP
|
||||
|
@ -278,63 +295,20 @@ the first \fBMailbox\fR command, and then leave out the \fBUser\fR command
|
|||
in the sections for each mailbox.
|
||||
\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
|
||||
.TP
|
||||
.B ~/.isyncrc
|
||||
Default configuration file
|
||||
..
|
||||
.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.
|
||||
.br
|
||||
Use -c /dev/null to work around.
|
||||
.P
|
||||
See the \fBINHERENT PROBLEMS\fR section in the \fBmbsync\fR man page, too.
|
||||
..
|
||||
.SH SEE ALSO
|
||||
mutt(1), maildir(5)
|
||||
mbsync(1), mdconvert(1), mutt(1), maildir(5)
|
||||
.P
|
||||
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;
|
||||
}
|
636
src/config.c
636
src/config.c
|
@ -1,8 +1,7 @@
|
|||
/* $Id$
|
||||
*
|
||||
* isync - IMAP4 to maildir mailbox synchronizer
|
||||
/*
|
||||
* mbsync - mailbox synchronizer
|
||||
* 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
|
||||
* 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
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
@ -33,254 +32,411 @@
|
|||
#include <stdlib.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 */
|
||||
static void
|
||||
config_defaults (config_t * conf)
|
||||
int
|
||||
parse_bool( conffile_t *cfile )
|
||||
{
|
||||
memcpy (conf, &global, sizeof (config_t));
|
||||
}
|
||||
|
||||
static char *
|
||||
my_strndup (const char *s, size_t nchars)
|
||||
{
|
||||
char *r = malloc (sizeof (char) * (nchars + 1));
|
||||
if (r)
|
||||
{
|
||||
memcpy (r, s, nchars);
|
||||
r[nchars] = 0;
|
||||
}
|
||||
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)
|
||||
if (!strcasecmp( cfile->val, "yes" ) ||
|
||||
!strcasecmp( cfile->val, "true" ) ||
|
||||
!strcasecmp( cfile->val, "on" ) ||
|
||||
!strcmp( cfile->val, "1" ))
|
||||
return 1;
|
||||
if (strcasecmp( cfile->val, "no" ) &&
|
||||
strcasecmp( cfile->val, "false" ) &&
|
||||
strcasecmp( cfile->val, "off" ) &&
|
||||
strcmp( cfile->val, "0" ))
|
||||
fprintf( stderr, "%s:%d: invalid boolean value '%s'\n",
|
||||
cfile->file, cfile->line, cfile->val );
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
parse_int( conffile_t *cfile )
|
||||
{
|
||||
char *p;
|
||||
int ret;
|
||||
|
||||
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;
|
||||
snprintf (path, sizeof (path), "%s/%s", pw->pw_dir, p ? p : "");
|
||||
s = path;
|
||||
}
|
||||
else if (*s != '/')
|
||||
{
|
||||
snprintf (path, sizeof (path), "%s/%s",
|
||||
global.maildir ? global.maildir : "", s);
|
||||
s = path;
|
||||
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 strdup (s);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
is_true (const char *val)
|
||||
getopt_helper( conffile_t *cfile, int *cops, int *mops, int *sops, char **sync_state )
|
||||
{
|
||||
return
|
||||
!strcasecmp (val, "yes") ||
|
||||
!strcasecmp (val, "true") ||
|
||||
!strcasecmp (val, "on") ||
|
||||
!strcmp (val, "1");
|
||||
}
|
||||
char *arg;
|
||||
|
||||
void
|
||||
load_config (const char *where, int *o2o)
|
||||
{
|
||||
char path[_POSIX_PATH_MAX];
|
||||
char buf[1024];
|
||||
struct passwd *pw;
|
||||
config_t **stor = &boxes, *cfg;
|
||||
int line = 0;
|
||||
FILE *fp;
|
||||
char *p, *cmd, *val;
|
||||
|
||||
if (!where)
|
||||
{
|
||||
pw = getpwuid (getuid ());
|
||||
snprintf (path, sizeof (path), "%s/.isyncrc", pw->pw_dir);
|
||||
where = path;
|
||||
}
|
||||
|
||||
info ("Reading configuration file %s\n", where);
|
||||
|
||||
fp = fopen (where, "r");
|
||||
if (!fp)
|
||||
{
|
||||
if (errno != ENOENT)
|
||||
perror ("fopen");
|
||||
return;
|
||||
}
|
||||
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 = malloc (sizeof (config_t));
|
||||
stor = &cfg->next;
|
||||
config_defaults (cfg);
|
||||
/* not expanded at this point */
|
||||
cfg->path = strdup (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;
|
||||
/* this only affects the global setting */
|
||||
global.maildir = expand_strdup (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;
|
||||
if (!strcasecmp( "Sync", cfile->cmd )) {
|
||||
arg = cfile->val;
|
||||
do
|
||||
if (!strcasecmp( "Push", arg ))
|
||||
*cops |= XOP_PUSH;
|
||||
else if (!strcasecmp( "Pull", arg ))
|
||||
*cops |= XOP_PULL;
|
||||
else if (!strcasecmp( "ReNew", arg ))
|
||||
*cops |= OP_RENEW;
|
||||
else if (!strcasecmp( "New", arg ))
|
||||
*cops |= OP_NEW;
|
||||
else if (!strcasecmp( "Delete", arg ))
|
||||
*cops |= OP_DELETE;
|
||||
else if (!strcasecmp( "Flags", arg ))
|
||||
*cops |= OP_FLAGS;
|
||||
else if (!strcasecmp( "PullReNew", arg ))
|
||||
*sops |= OP_RENEW;
|
||||
else if (!strcasecmp( "PullNew", arg ))
|
||||
*sops |= OP_NEW;
|
||||
else if (!strcasecmp( "PullDelete", arg ))
|
||||
*sops |= OP_DELETE;
|
||||
else if (!strcasecmp( "PullFlags", arg ))
|
||||
*sops |= OP_FLAGS;
|
||||
else if (!strcasecmp( "PushReNew", arg ))
|
||||
*mops |= OP_RENEW;
|
||||
else if (!strcasecmp( "PushNew", arg ))
|
||||
*mops |= OP_NEW;
|
||||
else if (!strcasecmp( "PushDelete", arg ))
|
||||
*mops |= OP_DELETE;
|
||||
else if (!strcasecmp( "PushFlags", arg ))
|
||||
*mops |= OP_FLAGS;
|
||||
else if (!strcasecmp( "All", arg ) || !strcasecmp( "Full", arg ))
|
||||
*cops |= XOP_PULL|XOP_PUSH;
|
||||
else if (strcasecmp( "None", arg ) && strcasecmp( "Noop", arg ))
|
||||
fprintf( stderr, "%s:%d: invalid Sync arg '%s'\n",
|
||||
cfile->file, cfile->line, arg );
|
||||
while ((arg = next_arg( &cfile->rest )));
|
||||
*mops |= XOP_HAVE_TYPE;
|
||||
} else if (!strcasecmp( "Expunge", cfile->cmd )) {
|
||||
arg = cfile->val;
|
||||
do
|
||||
if (!strcasecmp( "Both", arg ))
|
||||
*cops |= OP_EXPUNGE;
|
||||
else if (!strcasecmp( "Master", arg ))
|
||||
*mops |= OP_EXPUNGE;
|
||||
else if (!strcasecmp( "Slave", arg ))
|
||||
*sops |= OP_EXPUNGE;
|
||||
else if (strcasecmp( "None", arg ))
|
||||
fprintf( stderr, "%s:%d: invalid Expunge arg '%s'\n",
|
||||
cfile->file, cfile->line, arg );
|
||||
while ((arg = next_arg( &cfile->rest )));
|
||||
*mops |= XOP_HAVE_EXPUNGE;
|
||||
} else if (!strcasecmp( "Create", cfile->cmd )) {
|
||||
arg = cfile->val;
|
||||
do
|
||||
if (!strcasecmp( "Both", arg ))
|
||||
*cops |= OP_CREATE;
|
||||
else if (!strcasecmp( "Master", arg ))
|
||||
*mops |= OP_CREATE;
|
||||
else if (!strcasecmp( "Slave", arg ))
|
||||
*sops |= OP_CREATE;
|
||||
else if (strcasecmp( "None", arg ))
|
||||
fprintf( stderr, "%s:%d: invalid Create arg '%s'\n",
|
||||
cfile->file, cfile->line, arg );
|
||||
while ((arg = next_arg( &cfile->rest )));
|
||||
*mops |= XOP_HAVE_CREATE;
|
||||
} else if (!strcasecmp( "SyncState", cfile->cmd ))
|
||||
*sync_state = expand_strdup( cfile->val );
|
||||
else
|
||||
{
|
||||
/* check to see if the full pathname was specified on the
|
||||
* command line.
|
||||
*/
|
||||
char *t = expand_strdup (p->path);
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!strcmp (s, t))
|
||||
{
|
||||
free (t);
|
||||
return p;
|
||||
}
|
||||
free (t);
|
||||
int
|
||||
getcline( conffile_t *cfile )
|
||||
{
|
||||
char *p;
|
||||
|
||||
while (fgets( cfile->buf, cfile->bufl, cfile->fp )) {
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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
393
src/isync.h
393
src/isync.h
|
@ -1,6 +1,5 @@
|
|||
/* $Id$
|
||||
*
|
||||
* isync - IMAP4 to maildir mailbox synchronizer
|
||||
/*
|
||||
* mbsync - mailbox synchronizer
|
||||
* Copyright (C) 2000-2002 Michael R. Elkins <me@mutt.org>
|
||||
* 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
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <db.h>
|
||||
#define as(ar) (sizeof(ar)/sizeof(ar[0]))
|
||||
|
||||
#if HAVE_LIBSSL
|
||||
# include <openssl/ssl.h>
|
||||
#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
|
||||
{
|
||||
int fd;
|
||||
#if HAVE_LIBSSL
|
||||
SSL *ssl;
|
||||
unsigned int use_ssl:1;
|
||||
#endif
|
||||
} Socket_t;
|
||||
#define EXE "mbsync"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Socket_t *sock;
|
||||
int bytes;
|
||||
int offset;
|
||||
char buf[1024];
|
||||
}
|
||||
buffer_t;
|
||||
typedef struct {
|
||||
const char *file;
|
||||
FILE *fp;
|
||||
char *buf;
|
||||
int bufl;
|
||||
int line;
|
||||
char *cmd, *val, *rest;
|
||||
} conffile_t;
|
||||
|
||||
typedef struct config config_t;
|
||||
typedef struct mailbox mailbox_t;
|
||||
typedef struct message message_t;
|
||||
#define OP_NEW (1<<0)
|
||||
#define OP_RENEW (1<<1)
|
||||
#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
|
||||
{
|
||||
char *maildir;
|
||||
char *path; /* path relative to .maildir, or absolute path */
|
||||
char *host;
|
||||
int port;
|
||||
char *user;
|
||||
char *pass;
|
||||
char *folder;
|
||||
char *box;
|
||||
char *inbox;
|
||||
char *alias;
|
||||
char *copy_deleted_to;
|
||||
char *tunnel;
|
||||
unsigned int max_messages;
|
||||
off_t max_size;
|
||||
config_t *next;
|
||||
#if HAVE_LIBSSL
|
||||
char *cert_file;
|
||||
unsigned int use_imaps:1;
|
||||
unsigned int require_ssl:1;
|
||||
unsigned int use_sslv2:1;
|
||||
unsigned int use_sslv3:1;
|
||||
unsigned int use_tlsv1:1;
|
||||
unsigned int require_cram:1;
|
||||
#endif
|
||||
unsigned int use_namespace:1;
|
||||
unsigned int expunge:1;
|
||||
unsigned int delete:1;
|
||||
unsigned int wanted:1;
|
||||
typedef struct driver driver_t;
|
||||
|
||||
typedef struct store_conf {
|
||||
struct store_conf *next;
|
||||
char *name;
|
||||
driver_t *driver;
|
||||
const char *path; /* should this be here? its interpretation is driver-specific */
|
||||
char *map_inbox;
|
||||
char *trash;
|
||||
unsigned max_size; /* off_t is overkill */
|
||||
unsigned trash_remote_new:1, trash_only_new:1;
|
||||
} store_conf_t;
|
||||
|
||||
typedef struct string_list {
|
||||
struct string_list *next;
|
||||
char string[1];
|
||||
} string_list_t;
|
||||
|
||||
typedef struct channel_conf {
|
||||
struct channel_conf *next;
|
||||
char *name;
|
||||
store_conf_t *master, *slave;
|
||||
char *master_name, *slave_name;
|
||||
char *sync_state;
|
||||
string_list_t *patterns;
|
||||
int mops, sops;
|
||||
unsigned max_messages; /* for slave only */
|
||||
} channel_conf_t;
|
||||
|
||||
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 */
|
||||
#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
|
||||
/* main.c */
|
||||
|
||||
struct message
|
||||
{
|
||||
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 int Pid;
|
||||
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
|
||||
extern SSL_CTX *SSLContext;
|
||||
/* util.c */
|
||||
|
||||
char *cram (const char *, const char *, const char *);
|
||||
#endif
|
||||
extern int Verbose, Quiet, Debug;
|
||||
|
||||
char *next_arg (char **);
|
||||
void debug( const char *, ... );
|
||||
void info( const char *, ... );
|
||||
void infoc( char );
|
||||
void warn( const char *, ... );
|
||||
|
||||
int sync_mailbox (mailbox_t *, imap_t *, int, unsigned int, unsigned int);
|
||||
char *next_arg( char ** );
|
||||
|
||||
void load_config (const char *, int *);
|
||||
char * expand_strdup (const char *s);
|
||||
config_t *find_box (const char *);
|
||||
void add_string_list( string_list_t **list, const char *str );
|
||||
void free_string_list( string_list_t *list );
|
||||
|
||||
void imap_close (imap_t *);
|
||||
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 *);
|
||||
void free_generic_messages( message_t * );
|
||||
|
||||
mailbox_t *maildir_open (const char *, int flags);
|
||||
int maildir_expunge (mailbox_t *, int);
|
||||
int maildir_set_uidvalidity (mailbox_t *, unsigned int uidvalidity);
|
||||
void maildir_close (mailbox_t *);
|
||||
int maildir_update_maxuid (mailbox_t * mbox);
|
||||
void strip_cr( msg_data_t *msgdata );
|
||||
|
||||
message_t * find_msg (message_t * list, unsigned int uid);
|
||||
void free_message (message_t *);
|
||||
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 );
|
||||
|
||||
/* parse an IMAP list construct */
|
||||
list_t * parse_list (char *s, char **end);
|
||||
int is_atom (list_t *list);
|
||||
int is_list (list_t *list);
|
||||
int is_nil (list_t *list);
|
||||
void free_list (list_t *list);
|
||||
char *expand_strdup( const char *s );
|
||||
|
||||
#define strfcpy(a,b,c) {strncpy(a,b,c);(a)[c-1]=0;}
|
||||
void sort_ints( int *arr, int len );
|
||||
|
||||
void arc4_init( void );
|
||||
unsigned char arc4_getbyte( void );
|
||||
|
||||
/* sync.c */
|
||||
|
||||
#define SYNC_OK 0
|
||||
#define SYNC_FAIL 1
|
||||
#define SYNC_MASTER_BAD 2
|
||||
#define SYNC_SLAVE_BAD 3
|
||||
|
||||
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);
|
||||
}
|
923
src/main.c
923
src/main.c
File diff suppressed because it is too large
Load Diff
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;
|
||||
}
|
||||
|
1216
src/sync.c
1216
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