bincimap

Log | Files | Refs | LICENSE

commit 85590f390a6aa556b2bc45a5f5cdb1c9c9f37199
parent fd0d887eb0e0c7c035860714c738d987cc37b108
Author: Dominik Schmidt <dominik@schm1dt.ch>
Date:   Sun, 25 Oct 2020 13:29:57 +0100

Release 1.2.13/final

Diffstat:
MAUTHORS | 1+
MChangeLog | 138+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
MINSTALL | 4++--
MREADME.in | 68++++++++++++++++++++++++++++++++++++++------------------------------
MTODO | 2++
Maclocal.m4 | 1625++++++++++++++++++++++++++++++++++++++++++++-----------------------------------
Mbincimap.spec.in | 126+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mconfigure.in | 46+++++++++++++++++++++++++++-------------------
Mman/bincimap-up.1 | 16++++++++++------
Mman/bincimap.conf.5 | 2+-
Mman/bincimapd.1 | 7++++++-
Aservice/log/run | 18++++++++++++++++++
Aservice/log/run-ssl | 18++++++++++++++++++
Aservice/run | 16++++++++++++++++
Aservice/run-ssl | 14++++++++++++++
Msrc/Makefile.am | 2+-
Msrc/address.cc | 2+-
Msrc/address.h | 2+-
Msrc/argparser.cc | 16+++++++++++-----
Msrc/argparser.h | 8++++++--
Msrc/authenticate.cc | 24+++++++++++++++---------
Msrc/authenticate.h | 2+-
Msrc/base64.cc | 2+-
Msrc/base64.h | 2+-
Msrc/bincimap-up.cc | 4++--
Msrc/bincimapd.cc | 20++++++++++++--------
Msrc/broker.cc | 2+-
Msrc/broker.h | 2+-
Msrc/convert.cc | 2+-
Msrc/convert.h | 7+++++--
Msrc/depot.cc | 40++++++++++++++++++++++++++++++----------
Msrc/depot.h | 3++-
Msrc/greeting.cc | 8++++----
Msrc/imapparser.cc | 17+++++++++++------
Msrc/imapparser.h | 2+-
Msrc/io-ssl.cc | 4++--
Msrc/io-ssl.h | 2+-
Msrc/io.cc | 2+-
Msrc/io.h | 2+-
Msrc/mailbox.cc | 6+++---
Msrc/mailbox.h | 4++--
Msrc/maildir-close.cc | 8++++----
Msrc/maildir-create.cc | 2+-
Msrc/maildir-delete.cc | 2+-
Msrc/maildir-expunge.cc | 2+-
Msrc/maildir-readcache.cc | 22++++++++++++++++++++--
Msrc/maildir-scan.cc | 74++++++++++++++++++++++++++++++++++++++++++++++----------------------------
Msrc/maildir-scanfilesnames.cc | 2+-
Msrc/maildir-select.cc | 2+-
Msrc/maildir-updateflags.cc | 26+++++++++++++++++++++-----
Msrc/maildir-writecache.cc | 2+-
Msrc/maildir.cc | 98++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------
Msrc/maildir.h | 5++++-
Msrc/maildirmessage.cc | 184++++++++++++++++++++++++++++++++++++++++++++-----------------------------------
Msrc/maildirmessage.h | 8+++++++-
Msrc/message.h | 4++--
Msrc/mime-getpart.cc | 2+-
Msrc/mime-parsefull.cc | 29+++++++++++++++--------------
Msrc/mime-parseonlyheader.cc | 2+-
Msrc/mime-printbody.cc | 2+-
Msrc/mime-printdoc.cc | 2+-
Msrc/mime-printheader.cc | 2+-
Msrc/mime-utils.h | 2+-
Msrc/mime.cc | 2+-
Msrc/mime.h | 2+-
Msrc/operator-append.cc | 2+-
Msrc/operator-authenticate.cc | 6+++---
Msrc/operator-capability.cc | 4++--
Msrc/operator-check.cc | 2+-
Msrc/operator-close.cc | 3++-
Msrc/operator-copy.cc | 5++++-
Msrc/operator-create.cc | 2+-
Msrc/operator-delete.cc | 2+-
Msrc/operator-examine.cc | 2+-
Msrc/operator-expunge.cc | 20+++++++++++++++-----
Msrc/operator-fetch.cc | 26+++++++++++++++++++++-----
Msrc/operator-list.cc | 21++++++++++++++++-----
Msrc/operator-login.cc | 4++--
Msrc/operator-logout.cc | 2+-
Msrc/operator-lsub.cc | 88+++++++++++++++++++++++++++++++++++++++++++------------------------------------
Msrc/operator-noop-pending.cc | 9++++++---
Msrc/operator-noop.cc | 2+-
Msrc/operator-rename.cc | 2+-
Msrc/operator-search.cc | 4++--
Msrc/operator-select.cc | 23++++++++++++++++-------
Msrc/operator-starttls.cc | 2+-
Msrc/operator-status.cc | 2+-
Msrc/operator-store.cc | 11+++++++----
Msrc/operator-subscribe.cc | 2+-
Msrc/operator-unsubscribe.cc | 2+-
Msrc/operators.h | 2+-
Msrc/pendingupdates.cc | 30+++++++++++++++++++++---------
Msrc/pendingupdates.h | 13+++++++++----
Msrc/recursivedescent.cc | 5+----
Msrc/recursivedescent.h | 2+-
Msrc/regmatch.cc | 2+-
Msrc/regmatch.h | 2+-
Msrc/session-initialize-bincimap-up.cc | 13+++++++------
Msrc/session-initialize-bincimapd.cc | 16++++++++++++----
Msrc/session.cc | 45+++++++++++++++++++++++++++++++++++----------
Msrc/session.h | 3++-
Msrc/status.cc | 2+-
Msrc/status.h | 2+-
Msrc/storage.cc | 20++++++++++++++++++--
Msrc/storage.h | 4+++-
Msrc/tools.cc | 2+-
Msrc/tools.h | 2+-
107 files changed, 2005 insertions(+), 1182 deletions(-)

diff --git a/AUTHORS b/AUTHORS @@ -31,6 +31,7 @@ Zak Johnson <zakj (a) nox.cx> Sergei Kolobov <sergei (a) kolobov.com> Rafal Kupka <kupson (a) kupson.fdns.net> Eivind Kvedalen <bincimap (a) eivind.kvedalen.name> +Jerry LundstrĂm¶ <jerry.lundstrom (a) it.su.se> HIROSHIMA Naoki <naokih (a) iron-horse.org> Greger Stolt Nilsen <greger (a) psychoproject.net> John Starks <jstarks (a) starksnet.net> diff --git a/ChangeLog b/ChangeLog @@ -1,3 +1,141 @@ +* Thu Jul 21 2005 Andreas Aardal Hanssen <andreas-binc at bincimap.org> +- Fixed the INTERNALDATE response (again), so it uses the +DDDD + format instead of GMT, CEST and so on. +- The command line switch for "depot" was fixed. +- When renaming files / setting flags, the file list is read + first, and the files are then renamed afterwards. This fixed + a bug on XFS, where renaming the files also changes the order + in which they are scanned. +- Integrated Jerry Lundström's patch to make sure that the + Mailbox::path variable is not reset when a mailbox is closed. +- Released 1.2.13final + +* Sun Mar 06 2005 Andreas Aardal Hanssen <andreas-binc at bincimap.org> +- Added quoting in the configure script to make it more cross platform. +- Updated Copyright notices to include 2005 +- Remove the log messages about a possible crash when Binc IMAP was + unable to grab the mailbox lock. +- Maildir fix: Always add :2, to files that are moved to cur/. +- Made sure the state of the STARTTLS capability is correct, also when + in STARTTLS mode. +- The time zone is now removed from the greeting if strftime fails (if + the time zone is not set, for example). %Z is used instead of %z, to + avoid text time zones ("GMT" becomes "+0100"). +- Fixed the BODY response, so if no longer includes any extensions. +- The -p short option for --auth-penalty has been removed; it was a + conflicting short option. +- The LIST reference can now end with the delimiter character. +- EINVAL is caught in fsync(), which allows Binc IMAP to work better on + an NFS share. +- Released 1.2.12final + +* Mon Dec 13 2004 Andreas Aardal Hanssen <andreas-binc at bincimap.org> +- Fixed a lockup due to dangling symlinks in the Maildir +- Replaced opendir()/dirfd() with open(), and Binc doesn't + use O_DIRECTORY anymore. +- Fixed a bug with FIELDS in a BODY fetch being empty. +- Fixed so EXAMINE no longer writes the cache file. Ensure that + the read-only flag is always set correctly. +- Fixed so the \Recent flag is always remembered when the flags + are reset. +- When in read-only mode, all messages earlier marked as + expunged are replaced properly in the internal message map. +- Fixed a missing space in the response from RFC822.TEXT. +- Fixed two bugs when saving the subscribed list on a full + file system. +- Some compile fixes +- Released 1.2.11final + +* Sun Sep 19 2004 Andreas Aardal Hanssen <andreas-binc at bincimap.org> +- Released 1.2.10final + +* Mon Sep 13 2004 Andreas Aardal Hanssen <andreas-binc at bincimap.org> +- For proper crash safety also on Linux systems, sync the directories + as well as the files. +- In the MIME parser, count the number of lines and bytes in + the parent multiparts correctly. +- When committing flags changes, restart the filename scan if the + rename fails because the file name suddenly changed. +- Treat INBOX as case-insensitive when using wildcards in LIST and + LSUB. +- Replaced '%i' with '%d' in convert.h to avoid strange problems with + sprintf generating wrong Maildir file names. +- Binc no longer checks invalid mailbox paths like ".." and "". +- Released 1.2.10beta1 + +* Mon Jul 26 2004 Andreas Aardal Hanssen <andreas-binc at bincimap.org> +- Fixed a bug which made all mailboxes read-only if an EXAMINE had + been used throughout the session. + +* Tue Jul 20 2004 Andreas Aardal Hanssen <andreas-binc at bincimap.org> +- Made the README paths correspond to the ones generated by configure. +- Released 1.2.9final + +* Mon Jul 12 2004 Andreas Aardal Hanssen <andreas-binc at bincimap.org> +- Fixed a few bugs where session.setLastError() was used instead of + session.setResponseCode(). +- Fixed a charset detection bug in SEARCH. +- Set Binc to ignore the SIGPIPE signal. +- Released 1.2.9beta2 +- Fixed a compile error. +- Released 1.2.9beta3 + +* Sun Jul 04 2004 Andreas Aardal Hanssen <andreas-binc at bincimap.org> +- Fixed a bug with concurrent access when both clients issued + EXPUNGE requests on messages that had arrived within the same + session. +- Released 1.2.9beta1 + +* Wed Jun 09 2004 Andreas Aardal Hanssen <andreas-binc at bincimap.org> +- Binc IMAP now treats all other checkpassword exit codes than 0, 2 + and 111 as "authentication failed". + +* Sun Jun 06 2004 Andreas Aardal Hanssen <andreas-binc at bincimap.org> +- Instead of keeping silent about a failed pending update check, the + server will not explicitly close the connection, as it was intended + for it to do. +- The cause of an error caused by failures to read the cache or + uidvalidity files is properly reported now. +- If no umask is passed via the conf files, the umask is not set + (inherited by the parent process instead). +- Released 1.2.8beta1 + +* Thu Jun 03 2004 Andreas Aardal Hanssen <andreas-binc at bincimap.org> +- Fixed a bug with Session::loadSubscribe trimming entries read from + .bincimap-subscribed, reported by Seth LaForge. +- Fix a bug with subscribing to mailboxes. Now, mailboxes can only be + subscribed to once. +- Allow FETCH to give FLAGS, EXISTS and RECENT notifications for + tighter synchronization with the depot. + +* Sun May 31 2004 Andreas Aardal Hanssen <andreas-binc at bincimap.org> +- Compile fix for FreeBSD (pid_t) + +* Sun May 30 2004 Andreas Aardal Hanssen <andreas-binc at bincimap.org> +- A compile fix in configure.in by removing unnecessary quoting. + +* Tue May 25 2004 Andreas Aardal Hanssen <andreas-binc at bincimap.org> +- Added Henry Baragar's patches to fix the untagged NO responses + for unsupported commands. The responses are now tagged. + +* Sun May 23 2004 Andreas Aardal Hanssen <andreas-binc at bincimap.org> +- UID STORE now responds with a UID data member as part of the + untagged FETCH responses. +- When copying, the message is now rewound before data is read. This + fixes partial copies of messages that have recently been parsed. +- bincimapd now takes the mailbox path as an option unqualified + argument to bincimapd, which overrides the mailbox path inherited + from bincimap-up or set through command line options. This fixes + a problem with vmailmgr. +- Added Daniel James' patch for fixing fetching of RFC822.TEXT, + which should be equivalent to BODY[TEXT] but included the header + in the response. + +* Fri May 21 2004 Andreas Aardal Hanssen <andreas-binc at bincimap.org> +- Fixed problem with the sequence set '*'. Binc IMAP claimed no + messages matched this set, but now the highest UID or sequence + number matches. + * Sun Apr 18 2004 Andreas Aardal Hanssen <andreas-binc at bincimap.org> - Released 1.2.7final diff --git a/INSTALL b/INSTALL @@ -103,8 +103,8 @@ Installation Names ================== By default, `make install' will install the package's files in -`/opt/bincimap/bin', `/opt/bincimap/man', etc. You can specify an -installation prefix other than `/opt/bincimap' by giving `configure' the +`/usr/local/bin', `/usr/local/share/doc', etc. You can specify an +installation prefix other than `/usr/local' by giving `configure' the option `--prefix=PATH'. You can specify separate installation prefixes for diff --git a/README.in b/README.in @@ -15,13 +15,18 @@ Here is a quick guide on how to setup IMAP on your system. Note that this is not the full documentation for Binc IMAP. You will find more about the server by viewing the man pages and reading -through the bundled documentation under /usr/local/bincimap/doc. +through the bundled documentation under @datadir@/doc. You can also check out the project home page's FAQ and the Life With Binc IMAP community documentation site: http://www.lifewithbincimap.org/ +For hints on how to set up different clients with Binc, please visit +the following page: + +http://www.lifewithbincimap.org/index.php/Main/IMAPClientsWithBinc + +=======================================================================+ | | | The following library is required for Binc IMAP to support SSL: | @@ -68,7 +73,7 @@ to post your problems to the Binc IMAP mailing list. ./configure make -make install # Note: Mac OS X users need to use "sudo make install" +make install # Note: You may need to use "sudo make install" Add --enable-static to ./configure to build a static binary (a binary that does not depend on the shared libraries on @@ -90,30 +95,33 @@ make install # Note: Mac OS X users need to use "sudo make install" "make install" will create the following files: - /usr/local/bin/bincimap-up - /usr/local/bin/bincimapd - /usr/local/bin/checkpassword.pl - /usr/local/bin/tomaildir++ - /usr/local/bin/toimapdir + @bindir@/bincimap-up + @bindir@/bincimapd + @bindir@/checkpassword.pl + @bindir@/tomaildir++ + @bindir@/toimapdir + + @datadir@/doc/bincimap-manual.dvi + @datadir@/doc/bincimap-manual.ps - /usr/local/doc/bincimap-manual.dvi - /usr/local/doc/bincimap-manual.ps + @sysconfdir@/bincimap.conf + @sysconfdir@/xinetd/imap + @sysconfdir@/xinetd/imaps - /usr/local/etc/bincimap.conf - /usr/local/etc/xinetd/imap - /usr/local/etc/xinetd/imaps + @localstatedir@/service/imap/run + @localstatedir@/service/imap/log/run + @localstatedir@/service/imaps/run + @localstatedir@/service/imaps/log/run - /usr/local/service/imap/run - /usr/local/service/imap/log/run - /usr/local/service/imaps/run - /usr/local/service/imaps/log/run + @localstatedir@/log/bincimap + @localstatedir@/log/bincimap-ssl -------------------------------- 2) Apply necessary configuration -------------------------------- Edit the destination bincimap.conf file, which by default is - installed under /usr/local/etc/bincimap.conf. Check each + installed under @sysconfdir@/bincimap.conf. Check each individual setting. * Note the location of your server's SSL PEM-encoded @@ -133,8 +141,8 @@ make install # Note: Mac OS X users need to use "sudo make install" If using daemontools' supervise, tcpserver and multilog, create multilog directores. -mkdir -p /var/log/bincimap{,-ssl} -chown nobody.nobody /var/log/bincimap{,-ssl} +mkdir -p @localstatedir@/log/bincimap{,-ssl} +chown nobody.nobody @localstatedir@/log/bincimap{,-ssl} xinetd users will be more familiar with using syslog. @@ -144,8 +152,8 @@ chown nobody.nobody /var/log/bincimap{,-ssl} With xinetd: - Edit /usr/local/etc/xinetd/bincimap and - /usr/local/etc/xinetd/bincimaps and check that the locations + Edit @sysconfdir@/xinetd/bincimap and + @sysconfdir@/xinetd/bincimaps and check that the locations of configuration files and binaries are correct. Note the location of your checkpassword authenticator in @@ -155,23 +163,23 @@ chown nobody.nobody /var/log/bincimap{,-ssl} You may also want to symlink them to /etc/xinetd.d instead of copying the files. -ln -s /usr/local/etc/xinetd/bincimap /etc/xinetd.d/imap -ln -s /usr/local/etc/xinetd/bincimaps /etc/xinetd.d/imaps +ln -s @sysconfdir@/xinetd/bincimap /etc/xinetd.d/imap +ln -s @sysconfdir@/xinetd/bincimaps /etc/xinetd.d/imaps service xinetd restart With daemontools' supervise: - Edit /usr/local/etc/service/bincimap/run, - /usr/local/etc/service/bincimap/log/run, - /usr/local/etc/service/bincimaps/run and - /usr/local/etc/service/bincimaps/log/run and + Edit @sysconfdir@/service/bincimap/run, + @sysconfdir@/service/bincimap/log/run, + @sysconfdir@/service/bincimaps/run and + @sysconfdir@/service/bincimaps/log/run and check that the locations are correct. Note the location of your authenticator in particular. Then copy or symlink the service files in place. -ln -s /usr/local/etc/service/bincimap /service/imap -ln -s /usr/local/etc/service/bincimaps /service/imaps +ln -s @sysconfdir@/service/bincimap /service/imap +ln -s @sysconfdir@/service/bincimaps /service/imaps ---------------------------- 4) Securing your service @@ -200,7 +208,7 @@ ln -s /usr/local/etc/service/bincimaps /service/imaps user has no rights: Security { - jail path = "/usr/local/bin", + jail path = "@bindir@", jail user = "nobody", jail group = "nobody" } diff --git a/TODO b/TODO @@ -0,0 +1,2 @@ +- Test properly with Mail.app +- Test properly with Mutt diff --git a/aclocal.m4 b/aclocal.m4 @@ -1,163 +1,892 @@ -# generated automatically by aclocal 1.7.2 -*- Autoconf -*- - -# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002 -# Free Software Foundation, Inc. -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY, to the extent permitted by law; without -# even the implied warranty of MERCHANTABILITY or FITNESS FOR A -# PARTICULAR PURPOSE. - -# Like AC_CONFIG_HEADER, but automatically create stamp file. -*- Autoconf -*- - -# Copyright 1996, 1997, 2000, 2001 Free Software Foundation, Inc. - -# 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, 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. - -AC_PREREQ([2.52]) +dnl aclocal.m4 generated automatically by aclocal 1.4-p6 + +dnl Copyright (C) 1994, 1995-8, 1999, 2001 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl This program is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY, to the extent permitted by law; without +dnl even the implied warranty of MERCHANTABILITY or FITNESS FOR A +dnl PARTICULAR PURPOSE. + +# lib-prefix.m4 serial 3 (gettext-0.13) +dnl Copyright (C) 2001-2003 Free Software Foundation, Inc. +dnl This file is free software, distributed under the terms of the GNU +dnl General Public License. As a special exception to the GNU General +dnl Public License, this file may be distributed as part of a program +dnl that contains a configuration script generated by Autoconf, under +dnl the same distribution terms as the rest of that program. + +dnl From Bruno Haible. + +dnl AC_LIB_ARG_WITH is synonymous to AC_ARG_WITH in autoconf-2.13, and +dnl similar to AC_ARG_WITH in autoconf 2.52...2.57 except that is doesn't +dnl require excessive bracketing. +ifdef([AC_HELP_STRING], +[AC_DEFUN([AC_LIB_ARG_WITH], [AC_ARG_WITH([$1],[[$2]],[$3],[$4])])], +[AC_DEFUN([AC_][LIB_ARG_WITH], [AC_ARG_WITH([$1],[$2],[$3],[$4])])]) + +dnl AC_LIB_PREFIX adds to the CPPFLAGS and LDFLAGS the flags that are needed +dnl to access previously installed libraries. The basic assumption is that +dnl a user will want packages to use other packages he previously installed +dnl with the same --prefix option. +dnl This macro is not needed if only AC_LIB_LINKFLAGS is used to locate +dnl libraries, but is otherwise very convenient. +AC_DEFUN([AC_LIB_PREFIX], +[ + AC_BEFORE([$0], [AC_LIB_LINKFLAGS]) + AC_REQUIRE([AC_PROG_CC]) + AC_REQUIRE([AC_CANONICAL_HOST]) + AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) + dnl By default, look in $includedir and $libdir. + use_additional=yes + AC_LIB_WITH_FINAL_PREFIX([ + eval additional_includedir=\"$includedir\" + eval additional_libdir=\"$libdir\" + ]) + AC_LIB_ARG_WITH([lib-prefix], +[ --with-lib-prefix[=DIR] search for libraries in DIR/include and DIR/lib + --without-lib-prefix don't search for libraries in includedir and libdir], +[ + if test "X$withval" = "Xno"; then + use_additional=no + else + if test "X$withval" = "X"; then + AC_LIB_WITH_FINAL_PREFIX([ + eval additional_includedir=\"$includedir\" + eval additional_libdir=\"$libdir\" + ]) + else + additional_includedir="$withval/include" + additional_libdir="$withval/lib" + fi + fi +]) + if test $use_additional = yes; then + dnl Potentially add $additional_includedir to $CPPFLAGS. + dnl But don't add it + dnl 1. if it's the standard /usr/include, + dnl 2. if it's already present in $CPPFLAGS, + dnl 3. if it's /usr/local/include and we are using GCC on Linux, + dnl 4. if it doesn't exist as a directory. + if test "X$additional_includedir" != "X/usr/include"; then + haveit= + for x in $CPPFLAGS; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + if test "X$x" = "X-I$additional_includedir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test "X$additional_includedir" = "X/usr/local/include"; then + if test -n "$GCC"; then + case $host_os in + linux*) haveit=yes;; + esac + fi + fi + if test -z "$haveit"; then + if test -d "$additional_includedir"; then + dnl Really add $additional_includedir to $CPPFLAGS. + CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }-I$additional_includedir" + fi + fi + fi + fi + dnl Potentially add $additional_libdir to $LDFLAGS. + dnl But don't add it + dnl 1. if it's the standard /usr/lib, + dnl 2. if it's already present in $LDFLAGS, + dnl 3. if it's /usr/local/lib and we are using GCC on Linux, + dnl 4. if it doesn't exist as a directory. + if test "X$additional_libdir" != "X/usr/lib"; then + haveit= + for x in $LDFLAGS; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + if test "X$x" = "X-L$additional_libdir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test "X$additional_libdir" = "X/usr/local/lib"; then + if test -n "$GCC"; then + case $host_os in + linux*) haveit=yes;; + esac + fi + fi + if test -z "$haveit"; then + if test -d "$additional_libdir"; then + dnl Really add $additional_libdir to $LDFLAGS. + LDFLAGS="${LDFLAGS}${LDFLAGS:+ }-L$additional_libdir" + fi + fi + fi + fi + fi +]) -# serial 6 +dnl AC_LIB_PREPARE_PREFIX creates variables acl_final_prefix, +dnl acl_final_exec_prefix, containing the values to which $prefix and +dnl $exec_prefix will expand at the end of the configure script. +AC_DEFUN([AC_LIB_PREPARE_PREFIX], +[ + dnl Unfortunately, prefix and exec_prefix get only finally determined + dnl at the end of configure. + if test "X$prefix" = "XNONE"; then + acl_final_prefix="$ac_default_prefix" + else + acl_final_prefix="$prefix" + fi + if test "X$exec_prefix" = "XNONE"; then + acl_final_exec_prefix='${prefix}' + else + acl_final_exec_prefix="$exec_prefix" + fi + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + eval acl_final_exec_prefix=\"$acl_final_exec_prefix\" + prefix="$acl_save_prefix" +]) -# AM_CONFIG_HEADER is obsolete. It has been replaced by AC_CONFIG_HEADERS. -AU_DEFUN([AM_CONFIG_HEADER], [AC_CONFIG_HEADERS($@)]) +dnl AC_LIB_WITH_FINAL_PREFIX([statement]) evaluates statement, with the +dnl variables prefix and exec_prefix bound to the values they will have +dnl at the end of the configure script. +AC_DEFUN([AC_LIB_WITH_FINAL_PREFIX], +[ + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + $1 + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" +]) -# Do all the work for Automake. -*- Autoconf -*- +# lib-link.m4 serial 4 (gettext-0.12) +dnl Copyright (C) 2001-2003 Free Software Foundation, Inc. +dnl This file is free software, distributed under the terms of the GNU +dnl General Public License. As a special exception to the GNU General +dnl Public License, this file may be distributed as part of a program +dnl that contains a configuration script generated by Autoconf, under +dnl the same distribution terms as the rest of that program. + +dnl From Bruno Haible. + +dnl AC_LIB_LINKFLAGS(name [, dependencies]) searches for libname and +dnl the libraries corresponding to explicit and implicit dependencies. +dnl Sets and AC_SUBSTs the LIB${NAME} and LTLIB${NAME} variables and +dnl augments the CPPFLAGS variable. +AC_DEFUN([AC_LIB_LINKFLAGS], +[ + AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) + AC_REQUIRE([AC_LIB_RPATH]) + define([Name],[translit([$1],[./-], [___])]) + define([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-], + [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])]) + AC_CACHE_CHECK([how to link with lib[]$1], [ac_cv_lib[]Name[]_libs], [ + AC_LIB_LINKFLAGS_BODY([$1], [$2]) + ac_cv_lib[]Name[]_libs="$LIB[]NAME" + ac_cv_lib[]Name[]_ltlibs="$LTLIB[]NAME" + ac_cv_lib[]Name[]_cppflags="$INC[]NAME" + ]) + LIB[]NAME="$ac_cv_lib[]Name[]_libs" + LTLIB[]NAME="$ac_cv_lib[]Name[]_ltlibs" + INC[]NAME="$ac_cv_lib[]Name[]_cppflags" + AC_LIB_APPENDTOVAR([CPPFLAGS], [$INC]NAME) + AC_SUBST([LIB]NAME) + AC_SUBST([LTLIB]NAME) + dnl Also set HAVE_LIB[]NAME so that AC_LIB_HAVE_LINKFLAGS can reuse the + dnl results of this search when this library appears as a dependency. + HAVE_LIB[]NAME=yes + undefine([Name]) + undefine([NAME]) +]) -# This macro actually does too much some checks are only needed if -# your package does certain things. But this isn't really a big deal. +dnl AC_LIB_HAVE_LINKFLAGS(name, dependencies, includes, testcode) +dnl searches for libname and the libraries corresponding to explicit and +dnl implicit dependencies, together with the specified include files and +dnl the ability to compile and link the specified testcode. If found, it +dnl sets and AC_SUBSTs HAVE_LIB${NAME}=yes and the LIB${NAME} and +dnl LTLIB${NAME} variables and augments the CPPFLAGS variable, and +dnl #defines HAVE_LIB${NAME} to 1. Otherwise, it sets and AC_SUBSTs +dnl HAVE_LIB${NAME}=no and LIB${NAME} and LTLIB${NAME} to empty. +AC_DEFUN([AC_LIB_HAVE_LINKFLAGS], +[ + AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) + AC_REQUIRE([AC_LIB_RPATH]) + define([Name],[translit([$1],[./-], [___])]) + define([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-], + [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])]) + + dnl Search for lib[]Name and define LIB[]NAME, LTLIB[]NAME and INC[]NAME + dnl accordingly. + AC_LIB_LINKFLAGS_BODY([$1], [$2]) + + dnl Add $INC[]NAME to CPPFLAGS before performing the following checks, + dnl because if the user has installed lib[]Name and not disabled its use + dnl via --without-lib[]Name-prefix, he wants to use it. + ac_save_CPPFLAGS="$CPPFLAGS" + AC_LIB_APPENDTOVAR([CPPFLAGS], [$INC]NAME) + + AC_CACHE_CHECK([for lib[]$1], [ac_cv_lib[]Name], [ + ac_save_LIBS="$LIBS" + LIBS="$LIBS $LIB[]NAME" + AC_TRY_LINK([$3], [$4], [ac_cv_lib[]Name=yes], [ac_cv_lib[]Name=no]) + LIBS="$ac_save_LIBS" + ]) + if test "$ac_cv_lib[]Name" = yes; then + HAVE_LIB[]NAME=yes + AC_DEFINE([HAVE_LIB]NAME, 1, [Define if you have the $1 library.]) + AC_MSG_CHECKING([how to link with lib[]$1]) + AC_MSG_RESULT([$LIB[]NAME]) + else + HAVE_LIB[]NAME=no + dnl If $LIB[]NAME didn't lead to a usable library, we don't need + dnl $INC[]NAME either. + CPPFLAGS="$ac_save_CPPFLAGS" + LIB[]NAME= + LTLIB[]NAME= + fi + AC_SUBST([HAVE_LIB]NAME) + AC_SUBST([LIB]NAME) + AC_SUBST([LTLIB]NAME) + undefine([Name]) + undefine([NAME]) +]) -# Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002 -# Free Software Foundation, Inc. +dnl Determine the platform dependent parameters needed to use rpath: +dnl libext, shlibext, hardcode_libdir_flag_spec, hardcode_libdir_separator, +dnl hardcode_direct, hardcode_minus_L. +AC_DEFUN([AC_LIB_RPATH], +[ + AC_REQUIRE([AC_PROG_CC]) dnl we use $CC, $GCC, $LDFLAGS + AC_REQUIRE([AC_LIB_PROG_LD]) dnl we use $LD, $with_gnu_ld + AC_REQUIRE([AC_CANONICAL_HOST]) dnl we use $host + AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT]) dnl we use $ac_aux_dir + AC_CACHE_CHECK([for shared library run path origin], acl_cv_rpath, [ + CC="$CC" GCC="$GCC" LDFLAGS="$LDFLAGS" LD="$LD" with_gnu_ld="$with_gnu_ld" \ + ${CONFIG_SHELL-/bin/sh} "$ac_aux_dir/config.rpath" "$host" > conftest.sh + . ./conftest.sh + rm -f ./conftest.sh + acl_cv_rpath=done + ]) + wl="$acl_cv_wl" + libext="$acl_cv_libext" + shlibext="$acl_cv_shlibext" + hardcode_libdir_flag_spec="$acl_cv_hardcode_libdir_flag_spec" + hardcode_libdir_separator="$acl_cv_hardcode_libdir_separator" + hardcode_direct="$acl_cv_hardcode_direct" + hardcode_minus_L="$acl_cv_hardcode_minus_L" + dnl Determine whether the user wants rpath handling at all. + AC_ARG_ENABLE(rpath, + [ --disable-rpath do not hardcode runtime library paths], + :, enable_rpath=yes) +]) -# 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, or (at your option) -# any later version. +dnl AC_LIB_LINKFLAGS_BODY(name [, dependencies]) searches for libname and +dnl the libraries corresponding to explicit and implicit dependencies. +dnl Sets the LIB${NAME}, LTLIB${NAME} and INC${NAME} variables. +AC_DEFUN([AC_LIB_LINKFLAGS_BODY], +[ + define([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-], + [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])]) + dnl By default, look in $includedir and $libdir. + use_additional=yes + AC_LIB_WITH_FINAL_PREFIX([ + eval additional_includedir=\"$includedir\" + eval additional_libdir=\"$libdir\" + ]) + AC_LIB_ARG_WITH([lib$1-prefix], +[ --with-lib$1-prefix[=DIR] search for lib$1 in DIR/include and DIR/lib + --without-lib$1-prefix don't search for lib$1 in includedir and libdir], +[ + if test "X$withval" = "Xno"; then + use_additional=no + else + if test "X$withval" = "X"; then + AC_LIB_WITH_FINAL_PREFIX([ + eval additional_includedir=\"$includedir\" + eval additional_libdir=\"$libdir\" + ]) + else + additional_includedir="$withval/include" + additional_libdir="$withval/lib" + fi + fi +]) + dnl Search the library and its dependencies in $additional_libdir and + dnl $LDFLAGS. Using breadth-first-seach. + LIB[]NAME= + LTLIB[]NAME= + INC[]NAME= + rpathdirs= + ltrpathdirs= + names_already_handled= + names_next_round='$1 $2' + while test -n "$names_next_round"; do + names_this_round="$names_next_round" + names_next_round= + for name in $names_this_round; do + already_handled= + for n in $names_already_handled; do + if test "$n" = "$name"; then + already_handled=yes + break + fi + done + if test -z "$already_handled"; then + names_already_handled="$names_already_handled $name" + dnl See if it was already located by an earlier AC_LIB_LINKFLAGS + dnl or AC_LIB_HAVE_LINKFLAGS call. + uppername=`echo "$name" | sed -e 'y|abcdefghijklmnopqrstuvwxyz./-|ABCDEFGHIJKLMNOPQRSTUVWXYZ___|'` + eval value=\"\$HAVE_LIB$uppername\" + if test -n "$value"; then + if test "$value" = yes; then + eval value=\"\$LIB$uppername\" + test -z "$value" || LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$value" + eval value=\"\$LTLIB$uppername\" + test -z "$value" || LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }$value" + else + dnl An earlier call to AC_LIB_HAVE_LINKFLAGS has determined + dnl that this library doesn't exist. So just drop it. + : + fi + else + dnl Search the library lib$name in $additional_libdir and $LDFLAGS + dnl and the already constructed $LIBNAME/$LTLIBNAME. + found_dir= + found_la= + found_so= + found_a= + if test $use_additional = yes; then + if test -n "$shlibext" && test -f "$additional_libdir/lib$name.$shlibext"; then + found_dir="$additional_libdir" + found_so="$additional_libdir/lib$name.$shlibext" + if test -f "$additional_libdir/lib$name.la"; then + found_la="$additional_libdir/lib$name.la" + fi + else + if test -f "$additional_libdir/lib$name.$libext"; then + found_dir="$additional_libdir" + found_a="$additional_libdir/lib$name.$libext" + if test -f "$additional_libdir/lib$name.la"; then + found_la="$additional_libdir/lib$name.la" + fi + fi + fi + fi + if test "X$found_dir" = "X"; then + for x in $LDFLAGS $LTLIB[]NAME; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + case "$x" in + -L*) + dir=`echo "X$x" | sed -e 's/^X-L//'` + if test -n "$shlibext" && test -f "$dir/lib$name.$shlibext"; then + found_dir="$dir" + found_so="$dir/lib$name.$shlibext" + if test -f "$dir/lib$name.la"; then + found_la="$dir/lib$name.la" + fi + else + if test -f "$dir/lib$name.$libext"; then + found_dir="$dir" + found_a="$dir/lib$name.$libext" + if test -f "$dir/lib$name.la"; then + found_la="$dir/lib$name.la" + fi + fi + fi + ;; + esac + if test "X$found_dir" != "X"; then + break + fi + done + fi + if test "X$found_dir" != "X"; then + dnl Found the library. + LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$found_dir -l$name" + if test "X$found_so" != "X"; then + dnl Linking with a shared library. We attempt to hardcode its + dnl directory into the executable's runpath, unless it's the + dnl standard /usr/lib. + if test "$enable_rpath" = no || test "X$found_dir" = "X/usr/lib"; then + dnl No hardcoding is needed. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" + else + dnl Use an explicit option to hardcode DIR into the resulting + dnl binary. + dnl Potentially add DIR to ltrpathdirs. + dnl The ltrpathdirs will be appended to $LTLIBNAME at the end. + haveit= + for x in $ltrpathdirs; do + if test "X$x" = "X$found_dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + ltrpathdirs="$ltrpathdirs $found_dir" + fi + dnl The hardcoding into $LIBNAME is system dependent. + if test "$hardcode_direct" = yes; then + dnl Using DIR/libNAME.so during linking hardcodes DIR into the + dnl resulting binary. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" + else + if test -n "$hardcode_libdir_flag_spec" && test "$hardcode_minus_L" = no; then + dnl Use an explicit option to hardcode DIR into the resulting + dnl binary. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" + dnl Potentially add DIR to rpathdirs. + dnl The rpathdirs will be appended to $LIBNAME at the end. + haveit= + for x in $rpathdirs; do + if test "X$x" = "X$found_dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + rpathdirs="$rpathdirs $found_dir" + fi + else + dnl Rely on "-L$found_dir". + dnl But don't add it if it's already contained in the LDFLAGS + dnl or the already constructed $LIBNAME + haveit= + for x in $LDFLAGS $LIB[]NAME; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + if test "X$x" = "X-L$found_dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$found_dir" + fi + if test "$hardcode_minus_L" != no; then + dnl FIXME: Not sure whether we should use + dnl "-L$found_dir -l$name" or "-L$found_dir $found_so" + dnl here. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" + else + dnl We cannot use $hardcode_runpath_var and LD_RUN_PATH + dnl here, because this doesn't fit in flags passed to the + dnl compiler. So give up. No hardcoding. This affects only + dnl very old systems. + dnl FIXME: Not sure whether we should use + dnl "-L$found_dir -l$name" or "-L$found_dir $found_so" + dnl here. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-l$name" + fi + fi + fi + fi + else + if test "X$found_a" != "X"; then + dnl Linking with a static library. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_a" + else + dnl We shouldn't come here, but anyway it's good to have a + dnl fallback. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$found_dir -l$name" + fi + fi + dnl Assume the include files are nearby. + additional_includedir= + case "$found_dir" in + */lib | */lib/) + basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e 's,/lib/*$,,'` + additional_includedir="$basedir/include" + ;; + esac + if test "X$additional_includedir" != "X"; then + dnl Potentially add $additional_includedir to $INCNAME. + dnl But don't add it + dnl 1. if it's the standard /usr/include, + dnl 2. if it's /usr/local/include and we are using GCC on Linux, + dnl 3. if it's already present in $CPPFLAGS or the already + dnl constructed $INCNAME, + dnl 4. if it doesn't exist as a directory. + if test "X$additional_includedir" != "X/usr/include"; then + haveit= + if test "X$additional_includedir" = "X/usr/local/include"; then + if test -n "$GCC"; then + case $host_os in + linux*) haveit=yes;; + esac + fi + fi + if test -z "$haveit"; then + for x in $CPPFLAGS $INC[]NAME; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + if test "X$x" = "X-I$additional_includedir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test -d "$additional_includedir"; then + dnl Really add $additional_includedir to $INCNAME. + INC[]NAME="${INC[]NAME}${INC[]NAME:+ }-I$additional_includedir" + fi + fi + fi + fi + fi + dnl Look for dependencies. + if test -n "$found_la"; then + dnl Read the .la file. It defines the variables + dnl dlname, library_names, old_library, dependency_libs, current, + dnl age, revision, installed, dlopen, dlpreopen, libdir. + save_libdir="$libdir" + case "$found_la" in + */* | *\\*) . "$found_la" ;; + *) . "./$found_la" ;; + esac + libdir="$save_libdir" + dnl We use only dependency_libs. + for dep in $dependency_libs; do + case "$dep" in + -L*) + additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'` + dnl Potentially add $additional_libdir to $LIBNAME and $LTLIBNAME. + dnl But don't add it + dnl 1. if it's the standard /usr/lib, + dnl 2. if it's /usr/local/lib and we are using GCC on Linux, + dnl 3. if it's already present in $LDFLAGS or the already + dnl constructed $LIBNAME, + dnl 4. if it doesn't exist as a directory. + if test "X$additional_libdir" != "X/usr/lib"; then + haveit= + if test "X$additional_libdir" = "X/usr/local/lib"; then + if test -n "$GCC"; then + case $host_os in + linux*) haveit=yes;; + esac + fi + fi + if test -z "$haveit"; then + haveit= + for x in $LDFLAGS $LIB[]NAME; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + if test "X$x" = "X-L$additional_libdir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test -d "$additional_libdir"; then + dnl Really add $additional_libdir to $LIBNAME. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$additional_libdir" + fi + fi + haveit= + for x in $LDFLAGS $LTLIB[]NAME; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + if test "X$x" = "X-L$additional_libdir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test -d "$additional_libdir"; then + dnl Really add $additional_libdir to $LTLIBNAME. + LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$additional_libdir" + fi + fi + fi + fi + ;; + -R*) + dir=`echo "X$dep" | sed -e 's/^X-R//'` + if test "$enable_rpath" != no; then + dnl Potentially add DIR to rpathdirs. + dnl The rpathdirs will be appended to $LIBNAME at the end. + haveit= + for x in $rpathdirs; do + if test "X$x" = "X$dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + rpathdirs="$rpathdirs $dir" + fi + dnl Potentially add DIR to ltrpathdirs. + dnl The ltrpathdirs will be appended to $LTLIBNAME at the end. + haveit= + for x in $ltrpathdirs; do + if test "X$x" = "X$dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + ltrpathdirs="$ltrpathdirs $dir" + fi + fi + ;; + -l*) + dnl Handle this in the next round. + names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'` + ;; + *.la) + dnl Handle this in the next round. Throw away the .la's + dnl directory; it is already contained in a preceding -L + dnl option. + names_next_round="$names_next_round "`echo "X$dep" | sed -e 's,^X.*/,,' -e 's,^lib,,' -e 's,\.la$,,'` + ;; + *) + dnl Most likely an immediate library name. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$dep" + LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }$dep" + ;; + esac + done + fi + else + dnl Didn't find the library; assume it is in the system directories + dnl known to the linker and runtime loader. (All the system + dnl directories known to the linker should also be known to the + dnl runtime loader, otherwise the system is severely misconfigured.) + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-l$name" + LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-l$name" + fi + fi + fi + done + done + if test "X$rpathdirs" != "X"; then + if test -n "$hardcode_libdir_separator"; then + dnl Weird platform: only the last -rpath option counts, the user must + dnl pass all path elements in one option. We can arrange that for a + dnl single library, but not when more than one $LIBNAMEs are used. + alldirs= + for found_dir in $rpathdirs; do + alldirs="${alldirs}${alldirs:+$hardcode_libdir_separator}$found_dir" + done + dnl Note: hardcode_libdir_flag_spec uses $libdir and $wl. + acl_save_libdir="$libdir" + libdir="$alldirs" + eval flag=\"$hardcode_libdir_flag_spec\" + libdir="$acl_save_libdir" + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$flag" + else + dnl The -rpath options are cumulative. + for found_dir in $rpathdirs; do + acl_save_libdir="$libdir" + libdir="$found_dir" + eval flag=\"$hardcode_libdir_flag_spec\" + libdir="$acl_save_libdir" + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$flag" + done + fi + fi + if test "X$ltrpathdirs" != "X"; then + dnl When using libtool, the option that works for both libraries and + dnl executables is -R. The -R options are cumulative. + for found_dir in $ltrpathdirs; do + LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-R$found_dir" + done + fi +]) -# 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. +dnl AC_LIB_APPENDTOVAR(VAR, CONTENTS) appends the elements of CONTENTS to VAR, +dnl unless already present in VAR. +dnl Works only for CPPFLAGS, not for LIB* variables because that sometimes +dnl contains two or three consecutive elements that belong together. +AC_DEFUN([AC_LIB_APPENDTOVAR], +[ + for element in [$2]; do + haveit= + for x in $[$1]; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + if test "X$x" = "X$element"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + [$1]="${[$1]}${[$1]:+ }$element" + fi + done +]) -# 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. - -# serial 8 - -# There are a few dirty hacks below to avoid letting `AC_PROG_CC' be -# written in clear, in which case automake, when reading aclocal.m4, -# will think it sees a *use*, and therefore will trigger all it's -# C support machinery. Also note that it means that autoscan, seeing -# CC etc. in the Makefile, will ask for an AC_PROG_CC use... - - -AC_PREREQ([2.54]) - -# Autoconf 2.50 wants to disallow AM_ names. We explicitly allow -# the ones we care about. -m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl - -# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) -# AM_INIT_AUTOMAKE([OPTIONS]) -# ----------------------------------------------- -# The call with PACKAGE and VERSION arguments is the old style -# call (pre autoconf-2.50), which is being phased out. PACKAGE -# and VERSION should now be passed to AC_INIT and removed from -# the call to AM_INIT_AUTOMAKE. -# We support both call styles for the transition. After -# the next Automake release, Autoconf can make the AC_INIT -# arguments mandatory, and then we can depend on a new Autoconf -# release and drop the old call support. -AC_DEFUN([AM_INIT_AUTOMAKE], -[AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl - AC_REQUIRE([AC_PROG_INSTALL])dnl -# test to see if srcdir already configured -if test "`cd $srcdir && pwd`" != "`pwd`" && - test -f $srcdir/config.status; then - AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) -fi +# lib-ld.m4 serial 3 (gettext-0.13) +dnl Copyright (C) 1996-2003 Free Software Foundation, Inc. +dnl This file is free software, distributed under the terms of the GNU +dnl General Public License. As a special exception to the GNU General +dnl Public License, this file may be distributed as part of a program +dnl that contains a configuration script generated by Autoconf, under +dnl the same distribution terms as the rest of that program. + +dnl Subroutines of libtool.m4, +dnl with replacements s/AC_/AC_LIB/ and s/lt_cv/acl_cv/ to avoid collision +dnl with libtool.m4. + +dnl From libtool-1.4. Sets the variable with_gnu_ld to yes or no. +AC_DEFUN([AC_LIB_PROG_LD_GNU], +[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], acl_cv_prog_gnu_ld, +[# I'd rather use --version here, but apparently some GNU ld's only accept -v. +case `$LD -v 2>&1 </dev/null` in +*GNU* | *'with BFD'*) + acl_cv_prog_gnu_ld=yes ;; +*) + acl_cv_prog_gnu_ld=no ;; +esac]) +with_gnu_ld=$acl_cv_prog_gnu_ld +]) -# test whether we have cygpath -if test -z "$CYGPATH_W"; then - if (cygpath --version) >/dev/null 2>/dev/null; then - CYGPATH_W='cygpath -w' +dnl From libtool-1.4. Sets the variable LD. +AC_DEFUN([AC_LIB_PROG_LD], +[AC_ARG_WITH(gnu-ld, +[ --with-gnu-ld assume the C compiler uses GNU ld [default=no]], +test "$withval" = no || with_gnu_ld=yes, with_gnu_ld=no) +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl +# Prepare PATH_SEPARATOR. +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' else - CYGPATH_W=echo + PATH_SEPARATOR=: fi + rm -f conf$$.sh fi -AC_SUBST([CYGPATH_W]) - -# Define the identity of the package. -dnl Distinguish between old-style and new-style calls. -m4_ifval([$2], -[m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl - AC_SUBST([PACKAGE], [$1])dnl - AC_SUBST([VERSION], [$2])], -[_AM_SET_OPTIONS([$1])dnl - AC_SUBST([PACKAGE], [AC_PACKAGE_TARNAME])dnl - AC_SUBST([VERSION], [AC_PACKAGE_VERSION])])dnl - -_AM_IF_OPTION([no-define],, -[AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package]) - AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl - -# Some tools Automake needs. -AC_REQUIRE([AM_SANITY_CHECK])dnl -AC_REQUIRE([AC_ARG_PROGRAM])dnl -AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version}) -AM_MISSING_PROG(AUTOCONF, autoconf) -AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version}) -AM_MISSING_PROG(AUTOHEADER, autoheader) -AM_MISSING_PROG(MAKEINFO, makeinfo) -AM_MISSING_PROG(AMTAR, tar) -AM_PROG_INSTALL_SH -AM_PROG_INSTALL_STRIP -# We need awk for the "check" target. The system "awk" is bad on -# some platforms. -AC_REQUIRE([AC_PROG_AWK])dnl -AC_REQUIRE([AC_PROG_MAKE_SET])dnl - -_AM_IF_OPTION([no-dependencies],, -[AC_PROVIDE_IFELSE([AC_PROG_CC], - [_AM_DEPENDENCIES(CC)], - [define([AC_PROG_CC], - defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl -AC_PROVIDE_IFELSE([AC_PROG_CXX], - [_AM_DEPENDENCIES(CXX)], - [define([AC_PROG_CXX], - defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl -]) +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + AC_MSG_CHECKING([for ld used by GCC]) + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [[\\/]* | [A-Za-z]:[\\/]*)] + [re_direlt='/[^/][^/]*/\.\./'] + # Canonicalize the path of ld + ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'` + while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do + ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + AC_MSG_CHECKING([for GNU ld]) +else + AC_MSG_CHECKING([for non-GNU ld]) +fi +AC_CACHE_VAL(acl_cv_path_LD, +[if test -z "$LD"; then + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + acl_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some GNU ld's only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$acl_cv_path_LD" -v 2>&1 < /dev/null` in + *GNU* | *'with BFD'*) + test "$with_gnu_ld" != no && break ;; + *) + test "$with_gnu_ld" != yes && break ;; + esac + fi + done + IFS="$ac_save_ifs" +else + acl_cv_path_LD="$LD" # Let the user override the test with a path. +fi]) +LD="$acl_cv_path_LD" +if test -n "$LD"; then + AC_MSG_RESULT($LD) +else + AC_MSG_RESULT(no) +fi +test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH]) +AC_LIB_PROG_LD_GNU ]) +# Like AC_CONFIG_HEADER, but automatically create stamp file. + +AC_DEFUN([AM_CONFIG_HEADER], +[AC_PREREQ([2.12]) +AC_CONFIG_HEADER([$1]) +dnl When config.status generates a header, we must update the stamp-h file. +dnl This file resides in the same directory as the config header +dnl that is generated. We must strip everything past the first ":", +dnl and everything past the last "/". +AC_OUTPUT_COMMANDS(changequote(<<,>>)dnl +ifelse(patsubst(<<$1>>, <<[^ ]>>, <<>>), <<>>, +<<test -z "<<$>>CONFIG_HEADERS" || echo timestamp > patsubst(<<$1>>, <<^\([^:]*/\)?.*>>, <<\1>>)stamp-h<<>>dnl>>, +<<am_indx=1 +for am_file in <<$1>>; do + case " <<$>>CONFIG_HEADERS " in + *" <<$>>am_file "*<<)>> + echo timestamp > `echo <<$>>am_file | sed -e 's%:.*%%' -e 's%[^/]*$%%'`stamp-h$am_indx + ;; + esac + am_indx=`expr "<<$>>am_indx" + 1` +done<<>>dnl>>) +changequote([,]))]) + +# Do all the work for Automake. This macro actually does too much -- +# some checks are only needed if your package does certain things. +# But this isn't really a big deal. + +# serial 1 + +dnl Usage: +dnl AM_INIT_AUTOMAKE(package,version, [no-define]) -# When config.status generates a header, we must update the stamp-h file. -# This file resides in the same directory as the config header -# that is generated. The stamp files are numbered to have different names. - -# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the -# loop where config.status creates the headers, so we can generate -# our stamp files there. -AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], -[_am_stamp_count=`expr ${_am_stamp_count-0} + 1` -echo "timestamp for $1" >`AS_DIRNAME([$1])`/stamp-h[]$_am_stamp_count]) +AC_DEFUN([AM_INIT_AUTOMAKE], +[AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl +AC_REQUIRE([AC_PROG_INSTALL]) +PACKAGE=[$1] +AC_SUBST(PACKAGE) +VERSION=[$2] +AC_SUBST(VERSION) +dnl test to see if srcdir already configured +if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then + AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) +fi +ifelse([$3],, +AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package]) +AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])) +AC_REQUIRE([AM_SANITY_CHECK]) +AC_REQUIRE([AC_ARG_PROGRAM]) +dnl FIXME This is truly gross. +missing_dir=`cd $ac_aux_dir && pwd` +AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version}, $missing_dir) +AM_MISSING_PROG(AUTOCONF, autoconf, $missing_dir) +AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version}, $missing_dir) +AM_MISSING_PROG(AUTOHEADER, autoheader, $missing_dir) +AM_MISSING_PROG(MAKEINFO, makeinfo, $missing_dir) +AC_REQUIRE([AC_PROG_MAKE_SET])]) # Copyright 2002 Free Software Foundation, Inc. @@ -179,103 +908,37 @@ echo "timestamp for $1" >`AS_DIRNAME([$1])`/stamp-h[]$_am_stamp_count]) # ---------------------------- # Automake X.Y traces this macro to ensure aclocal.m4 has been # generated from the m4 files accompanying Automake X.Y. -AC_DEFUN([AM_AUTOMAKE_VERSION],[am__api_version="1.7"]) +AC_DEFUN([AM_AUTOMAKE_VERSION],[am__api_version="1.4"]) # AM_SET_CURRENT_AUTOMAKE_VERSION # ------------------------------- # Call AM_AUTOMAKE_VERSION so it can be traced. # This function is AC_REQUIREd by AC_INIT_AUTOMAKE. AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], - [AM_AUTOMAKE_VERSION([1.7.2])]) - -# Helper functions for option handling. -*- Autoconf -*- - -# Copyright 2001, 2002 Free Software Foundation, Inc. - -# 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, 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. - -# serial 2 - -# _AM_MANGLE_OPTION(NAME) -# ----------------------- -AC_DEFUN([_AM_MANGLE_OPTION], -[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) - -# _AM_SET_OPTION(NAME) -# ------------------------------ -# Set option NAME. Presently that only means defining a flag for this option. -AC_DEFUN([_AM_SET_OPTION], -[m4_define(_AM_MANGLE_OPTION([$1]), 1)]) - -# _AM_SET_OPTIONS(OPTIONS) -# ---------------------------------- -# OPTIONS is a space-separated list of Automake options. -AC_DEFUN([_AM_SET_OPTIONS], -[AC_FOREACH([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) - -# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) -# ------------------------------------------- -# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. -AC_DEFUN([_AM_IF_OPTION], -[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) + [AM_AUTOMAKE_VERSION([1.4-p6])]) # # Check to make sure that the build environment is sane. # -# Copyright 1996, 1997, 2000, 2001 Free Software Foundation, Inc. - -# 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, 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. - -# serial 3 - -# AM_SANITY_CHECK -# --------------- AC_DEFUN([AM_SANITY_CHECK], [AC_MSG_CHECKING([whether build environment is sane]) # Just in case sleep 1 -echo timestamp > conftest.file +echo timestamp > conftestfile # Do `set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( - set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null` - if test "$[*]" = "X"; then + set X `ls -Lt $srcdir/configure conftestfile 2> /dev/null` + if test "[$]*" = "X"; then # -L didn't work. - set X `ls -t $srcdir/configure conftest.file` + set X `ls -t $srcdir/configure conftestfile` fi - rm -f conftest.file - if test "$[*]" != "X $srcdir/configure conftest.file" \ - && test "$[*]" != "X conftest.file $srcdir/configure"; then + if test "[$]*" != "X $srcdir/configure conftestfile" \ + && test "[$]*" != "X conftestfile $srcdir/configure"; then # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a @@ -285,7 +948,7 @@ if ( alias in your environment]) fi - test "$[2]" = conftest.file + test "[$]2" = conftestfile ) then # Ok. @@ -294,518 +957,22 @@ else AC_MSG_ERROR([newly created file is older than distributed files! Check your system clock]) fi +rm -f conftest* AC_MSG_RESULT(yes)]) -# -*- Autoconf -*- - - -# Copyright 1997, 1999, 2000, 2001 Free Software Foundation, Inc. - -# 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, 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. - -# serial 3 - -# AM_MISSING_PROG(NAME, PROGRAM) -# ------------------------------ +dnl AM_MISSING_PROG(NAME, PROGRAM, DIRECTORY) +dnl The program must properly implement --version. AC_DEFUN([AM_MISSING_PROG], -[AC_REQUIRE([AM_MISSING_HAS_RUN]) -$1=${$1-"${am_missing_run}$2"} -AC_SUBST($1)]) - - -# AM_MISSING_HAS_RUN -# ------------------ -# Define MISSING if not defined so far and test if it supports --run. -# If it does, set am_missing_run to use it, otherwise, to nothing. -AC_DEFUN([AM_MISSING_HAS_RUN], -[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl -test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing" -# Use eval to expand $SHELL -if eval "$MISSING --run true"; then - am_missing_run="$MISSING --run " +[AC_MSG_CHECKING(for working $2) +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if ($2 --version) < /dev/null > /dev/null 2>&1; then + $1=$2 + AC_MSG_RESULT(found) else - am_missing_run= - AC_MSG_WARN([`missing' script is too old or missing]) + $1="$3/missing $2" + AC_MSG_RESULT(missing) fi -]) - -# AM_AUX_DIR_EXPAND - -# Copyright 2001 Free Software Foundation, Inc. - -# 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, 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. - -# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets -# $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to -# `$srcdir', `$srcdir/..', or `$srcdir/../..'. -# -# Of course, Automake must honor this variable whenever it calls a -# tool from the auxiliary directory. The problem is that $srcdir (and -# therefore $ac_aux_dir as well) can be either absolute or relative, -# depending on how configure is run. This is pretty annoying, since -# it makes $ac_aux_dir quite unusable in subdirectories: in the top -# source directory, any form will work fine, but in subdirectories a -# relative path needs to be adjusted first. -# -# $ac_aux_dir/missing -# fails when called from a subdirectory if $ac_aux_dir is relative -# $top_srcdir/$ac_aux_dir/missing -# fails if $ac_aux_dir is absolute, -# fails when called from a subdirectory in a VPATH build with -# a relative $ac_aux_dir -# -# The reason of the latter failure is that $top_srcdir and $ac_aux_dir -# are both prefixed by $srcdir. In an in-source build this is usually -# harmless because $srcdir is `.', but things will broke when you -# start a VPATH build or use an absolute $srcdir. -# -# So we could use something similar to $top_srcdir/$ac_aux_dir/missing, -# iff we strip the leading $srcdir from $ac_aux_dir. That would be: -# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` -# and then we would define $MISSING as -# MISSING="\${SHELL} $am_aux_dir/missing" -# This will work as long as MISSING is not called from configure, because -# unfortunately $(top_srcdir) has no meaning in configure. -# However there are other variables, like CC, which are often used in -# configure, and could therefore not use this "fixed" $ac_aux_dir. -# -# Another solution, used here, is to always expand $ac_aux_dir to an -# absolute PATH. The drawback is that using absolute paths prevent a -# configured tree to be moved without reconfiguration. - -# Rely on autoconf to set up CDPATH properly. -AC_PREREQ([2.50]) - -AC_DEFUN([AM_AUX_DIR_EXPAND], [ -# expand $ac_aux_dir to an absolute path -am_aux_dir=`cd $ac_aux_dir && pwd` -]) - -# AM_PROG_INSTALL_SH -# ------------------ -# Define $install_sh. - -# Copyright 2001 Free Software Foundation, Inc. - -# 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, 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. - -AC_DEFUN([AM_PROG_INSTALL_SH], -[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl -install_sh=${install_sh-"$am_aux_dir/install-sh"} -AC_SUBST(install_sh)]) - -# AM_PROG_INSTALL_STRIP - -# Copyright 2001 Free Software Foundation, Inc. - -# 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, 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. - -# One issue with vendor `install' (even GNU) is that you can't -# specify the program used to strip binaries. This is especially -# annoying in cross-compiling environments, where the build's strip -# is unlikely to handle the host's binaries. -# Fortunately install-sh will honor a STRIPPROG variable, so we -# always use install-sh in `make install-strip', and initialize -# STRIPPROG with the value of the STRIP variable (set by the user). -AC_DEFUN([AM_PROG_INSTALL_STRIP], -[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl -# Installed binaries are usually stripped using `strip' when the user -# run `make install-strip'. However `strip' might not be the right -# tool to use in cross-compilation environments, therefore Automake -# will honor the `STRIP' environment variable to overrule this program. -dnl Don't test for $cross_compiling = yes, because it might be `maybe'. -if test "$cross_compiling" != no; then - AC_CHECK_TOOL([STRIP], [strip], :) -fi -INSTALL_STRIP_PROGRAM="\${SHELL} \$(install_sh) -c -s" -AC_SUBST([INSTALL_STRIP_PROGRAM])]) - -# serial 4 -*- Autoconf -*- - -# Copyright 1999, 2000, 2001 Free Software Foundation, Inc. - -# 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, 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. - - -# There are a few dirty hacks below to avoid letting `AC_PROG_CC' be -# written in clear, in which case automake, when reading aclocal.m4, -# will think it sees a *use*, and therefore will trigger all it's -# C support machinery. Also note that it means that autoscan, seeing -# CC etc. in the Makefile, will ask for an AC_PROG_CC use... - - - -# _AM_DEPENDENCIES(NAME) -# ---------------------- -# See how the compiler implements dependency checking. -# NAME is "CC", "CXX", "GCJ", or "OBJC". -# We try a few techniques and use that to set a single cache variable. -# -# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was -# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular -# dependency, and given that the user is not expected to run this macro, -# just rely on AC_PROG_CC. -AC_DEFUN([_AM_DEPENDENCIES], -[AC_REQUIRE([AM_SET_DEPDIR])dnl -AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl -AC_REQUIRE([AM_MAKE_INCLUDE])dnl -AC_REQUIRE([AM_DEP_TRACK])dnl - -ifelse([$1], CC, [depcc="$CC" am_compiler_list=], - [$1], CXX, [depcc="$CXX" am_compiler_list=], - [$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'], - [$1], GCJ, [depcc="$GCJ" am_compiler_list='gcc3 gcc'], - [depcc="$$1" am_compiler_list=]) - -AC_CACHE_CHECK([dependency style of $depcc], - [am_cv_$1_dependencies_compiler_type], -[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then - # We make a subdir and do the tests there. Otherwise we can end up - # making bogus files that we don't know about and never remove. For - # instance it was reported that on HP-UX the gcc test will end up - # making a dummy file named `D' -- because `-MD' means `put the output - # in D'. - mkdir conftest.dir - # Copy depcomp to subdir because otherwise we won't find it if we're - # using a relative directory. - cp "$am_depcomp" conftest.dir - cd conftest.dir - - am_cv_$1_dependencies_compiler_type=none - if test "$am_compiler_list" = ""; then - am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` - fi - for depmode in $am_compiler_list; do - # We need to recreate these files for each test, as the compiler may - # overwrite some of them when testing with obscure command lines. - # This happens at least with the AIX C compiler. - echo '#include "conftest.h"' > conftest.c - echo 'int i;' > conftest.h - echo "${am__include} ${am__quote}conftest.Po${am__quote}" > confmf - - case $depmode in - nosideeffect) - # after this tag, mechanisms are not by side-effect, so they'll - # only be used when explicitly requested - if test "x$enable_dependency_tracking" = xyes; then - continue - else - break - fi - ;; - none) break ;; - esac - # We check with `-c' and `-o' for the sake of the "dashmstdout" - # mode. It turns out that the SunPro C++ compiler does not properly - # handle `-M -o', and we need to detect this. - if depmode=$depmode \ - source=conftest.c object=conftest.o \ - depfile=conftest.Po tmpdepfile=conftest.TPo \ - $SHELL ./depcomp $depcc -c -o conftest.o conftest.c >/dev/null 2>&1 && - grep conftest.h conftest.Po > /dev/null 2>&1 && - ${MAKE-make} -s -f confmf > /dev/null 2>&1; then - am_cv_$1_dependencies_compiler_type=$depmode - break - fi - done - - cd .. - rm -rf conftest.dir -else - am_cv_$1_dependencies_compiler_type=none -fi -]) -AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) -AM_CONDITIONAL([am__fastdep$1], [ - test "x$enable_dependency_tracking" != xno \ - && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) -]) - - -# AM_SET_DEPDIR -# ------------- -# Choose a directory name for dependency files. -# This macro is AC_REQUIREd in _AM_DEPENDENCIES -AC_DEFUN([AM_SET_DEPDIR], -[rm -f .deps 2>/dev/null -mkdir .deps 2>/dev/null -if test -d .deps; then - DEPDIR=.deps -else - # MS-DOS does not allow filenames that begin with a dot. - DEPDIR=_deps -fi -rmdir .deps 2>/dev/null -AC_SUBST([DEPDIR]) -]) - - -# AM_DEP_TRACK -# ------------ -AC_DEFUN([AM_DEP_TRACK], -[AC_ARG_ENABLE(dependency-tracking, -[ --disable-dependency-tracking Speeds up one-time builds - --enable-dependency-tracking Do not reject slow dependency extractors]) -if test "x$enable_dependency_tracking" != xno; then - am_depcomp="$ac_aux_dir/depcomp" - AMDEPBACKSLASH='\' -fi -AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) -AC_SUBST([AMDEPBACKSLASH]) -]) - -# Generate code to set up dependency tracking. -*- Autoconf -*- - -# Copyright 1999, 2000, 2001, 2002 Free Software Foundation, Inc. - -# 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, 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. - -#serial 2 - -# _AM_OUTPUT_DEPENDENCY_COMMANDS -# ------------------------------ -AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], -[for mf in $CONFIG_FILES; do - # Strip MF so we end up with the name of the file. - mf=`echo "$mf" | sed -e 's/:.*$//'` - # Check whether this is an Automake generated Makefile or not. - # We used to match only the files named `Makefile.in', but - # some people rename them; so instead we look at the file content. - # Grep'ing the first line is not enough: some people post-process - # each Makefile.in and add a new line on top of each file to say so. - # So let's grep whole file. - if grep '^#.*generated by automake' $mf > /dev/null 2>&1; then - dirpart=`AS_DIRNAME("$mf")` - else - continue - fi - grep '^DEP_FILES *= *[[^ @%:@]]' < "$mf" > /dev/null || continue - # Extract the definition of DEP_FILES from the Makefile without - # running `make'. - DEPDIR=`sed -n -e '/^DEPDIR = / s///p' < "$mf"` - test -z "$DEPDIR" && continue - # When using ansi2knr, U may be empty or an underscore; expand it - U=`sed -n -e '/^U = / s///p' < "$mf"` - test -d "$dirpart/$DEPDIR" || mkdir "$dirpart/$DEPDIR" - # We invoke sed twice because it is the simplest approach to - # changing $(DEPDIR) to its actual value in the expansion. - for file in `sed -n -e ' - /^DEP_FILES = .*\\\\$/ { - s/^DEP_FILES = // - :loop - s/\\\\$// - p - n - /\\\\$/ b loop - p - } - /^DEP_FILES = / s/^DEP_FILES = //p' < "$mf" | \ - sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do - # Make sure the directory exists. - test -f "$dirpart/$file" && continue - fdir=`AS_DIRNAME(["$file"])` - AS_MKDIR_P([$dirpart/$fdir]) - # echo "creating $dirpart/$file" - echo '# dummy' > "$dirpart/$file" - done -done -])# _AM_OUTPUT_DEPENDENCY_COMMANDS - - -# AM_OUTPUT_DEPENDENCY_COMMANDS -# ----------------------------- -# This macro should only be invoked once -- use via AC_REQUIRE. -# -# This code is only required when automatic dependency tracking -# is enabled. FIXME. This creates each `.P' file that we will -# need in order to bootstrap the dependency handling code. -AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], -[AC_CONFIG_COMMANDS([depfiles], - [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], - [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) -]) - -# Check to see how 'make' treats includes. -*- Autoconf -*- - -# Copyright (C) 2001, 2002 Free Software Foundation, Inc. - -# 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, 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. - -# serial 2 - -# AM_MAKE_INCLUDE() -# ----------------- -# Check to see how make treats includes. -AC_DEFUN([AM_MAKE_INCLUDE], -[am_make=${MAKE-make} -cat > confinc << 'END' -doit: - @echo done -END -# If we don't find an include directive, just comment out the code. -AC_MSG_CHECKING([for style of include used by $am_make]) -am__include="#" -am__quote= -_am_result=none -# First try GNU make style include. -echo "include confinc" > confmf -# We grep out `Entering directory' and `Leaving directory' -# messages which can occur if `w' ends up in MAKEFLAGS. -# In particular we don't look at `^make:' because GNU make might -# be invoked under some other name (usually "gmake"), in which -# case it prints its new name instead of `make'. -if test "`$am_make -s -f confmf 2> /dev/null | grep -v 'ing directory'`" = "done"; then - am__include=include - am__quote= - _am_result=GNU -fi -# Now try BSD make style include. -if test "$am__include" = "#"; then - echo '.include "confinc"' > confmf - if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then - am__include=.include - am__quote="\"" - _am_result=BSD - fi -fi -AC_SUBST(am__include) -AC_SUBST(am__quote) -AC_MSG_RESULT($_am_result) -rm -f confinc confmf -]) - -# AM_CONDITIONAL -*- Autoconf -*- - -# Copyright 1997, 2000, 2001 Free Software Foundation, Inc. - -# 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, 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. - -# serial 5 - -AC_PREREQ(2.52) - -# AM_CONDITIONAL(NAME, SHELL-CONDITION) -# ------------------------------------- -# Define a conditional. -AC_DEFUN([AM_CONDITIONAL], -[ifelse([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], - [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl -AC_SUBST([$1_TRUE]) -AC_SUBST([$1_FALSE]) -if $2; then - $1_TRUE= - $1_FALSE='#' -else - $1_TRUE='#' - $1_FALSE= -fi -AC_CONFIG_COMMANDS_PRE( -[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then - AC_MSG_ERROR([conditional "$1" was never defined. -Usually this means the macro was only invoked conditionally.]) -fi])]) +AC_SUBST($1)]) diff --git a/bincimap.spec.in b/bincimap.spec.in @@ -188,6 +188,132 @@ install man/bincimap.conf.5 $MAN/man5 #----------------------------------------------------------------------- %changelog +* Sun Mar 06 2005 Andreas Aardal Hanssen <andreas-binc@bincimap.org> +- Added quoting in the configure script to make it more cross platform. +- Updated Copyright notices to include 2005 +- Remove the log messages about a possible crash when Binc IMAP was + unable to grab the mailbox lock. +- Maildir fix: Always add :2, to files that are moved to cur/. +- Made sure the state of the STARTTLS capability is correct, also when + in STARTTLS mode. +- The time zone is now removed from the greeting if strftime fails (if + the time zone is not set, for example). %Z is used instead of %z, to + avoid text time zones ("GMT" becomes "+0100"). +- Fixed the BODY response, so if no longer includes any extensions. +- The -p short option for --auth-penalty has been removed; it was a + conflicting short option. +- The LIST reference can now end with the delimiter character. +- EINVAL is caught in fsync(), which allows Binc IMAP to work better on + an NFS share. +- Released 1.2.12final + +* Mon Dec 13 2004 Andreas Aardal Hanssen <andreas-binc@bincimap.org> +- Fixed a lockup due to dangling symlinks in the Maildir +- Replaced opendir()/dirfd() with open(), and Binc doesn't + use O_DIRECTORY anymore. +- Fixed a bug with FIELDS in a BODY fetch being empty. +- Fixed so EXAMINE no longer writes the cache file. Ensure that + the read-only flag is always set correctly. +- Fixed so the \Recent flag is always remembered when the flags + are reset. +- When in read-only mode, all messages earlier marked as + expunged are replaced properly in the internal message map. +- Fixed a missing space in the response from RFC822.TEXT. +- Fixed two bugs when saving the subscribed list on a full + file system. +- Some compile fixes +- Released 1.2.11final + +* Sun Sep 19 2004 Andreas Aardal Hanssen <andreas-binc@bincimap.org> +- Released 1.2.10final + +* Mon Sep 13 2004 Andreas Aardal Hanssen <andreas-binc@bincimap.org> +- For proper crash safety also on Linux systems, sync the directories + as well as the files. +- In the MIME parser, count the number of lines and bytes in + the parent multiparts correctly. +- When committing flags changes, restart the filename scan if the + rename fails because the file name suddenly changed. +- Treat INBOX as case-insensitive when using wildcards in LIST and + LSUB. +- Replaced '%i' with '%d' in convert.h to avoid strange problems with + sprintf generating wrong Maildir file names. +- Binc no longer checks invalid mailbox paths like ".." and "". +- Released 1.2.10beta1 + +* Mon Jul 26 2004 Andreas Aardal Hanssen <andreas-binc@bincimap.org> +- Fixed a bug which made all mailboxes read-only if an EXAMINE had + been used throughout the session. + +* Tue Jul 20 2004 Andreas Aardal Hanssen <andreas-binc@bincimap.org> +- Made the README paths correspond to the ones generated by configure. +- Released 1.2.9final + +* Mon Jul 12 2004 Andreas Aardal Hanssen <andreas-binc@bincimap.org> +- Fixed a few bugs where session.setLastError() was used instead of + session.setResponseCode(). +- Fixed a charset detection bug in SEARCH. +- Set Binc to ignore the SIGPIPE signal. +- Released 1.2.9beta2 +- Fixed a compile error. +- Released 1.2.9beta3 + +* Sun Jul 04 2004 Andreas Aardal Hanssen <andreas-binc@bincimap.org> +- Fixed a bug with concurrent access when both clients issued + EXPUNGE requests on messages that had arrived within the same + session. +- Released 1.2.9beta1 + +* Wed Jun 09 2004 Andreas Aardal Hanssen <andreas-binc@bincimap.org> +- Binc IMAP now treats all other checkpassword exit codes than 0, 2 + and 111 as "authentication failed". + +* Sun Jun 06 2004 Andreas Aardal Hanssen <andreas-binc@bincimap.org> +- Instead of keeping silent about a failed pending update check, the + server will not explicitly close the connection, as it was intended + for it to do. +- The cause of an error caused by failures to read the cache or + uidvalidity files is properly reported now. +- If no umask is passed via the conf files, the umask is not set + (inherited by the parent process instead). +- Released 1.2.8beta1 + +* Thu Jun 03 2004 Andreas Aardal Hanssen <andreas-binc@bincimap.org> +- Fixed a bug with Session::loadSubscribe trimming entries read from + .bincimap-subscribed, reported by Seth LaForge. +- Fix a bug with subscribing to mailboxes. Now, mailboxes can only be + subscribed to once. +- Allow FETCH to give FLAGS, EXISTS and RECENT notifications for + tighter synchronization with the depot. + +* Sun May 31 2004 Andreas Aardal Hanssen <andreas-binc@bincimap.org> +- Compile fix for FreeBSD (pid_t) + +* Sun May 30 2004 Andreas Aardal Hanssen <andreas-binc@bincimap.org> +- A compile fix in configure.in by removing unnecessary quoting. + +* Tue May 25 2004 Andreas Aardal Hanssen <andreas-binc@bincimap.org> +- Added Henry Baragar's patches to fix the untagged NO responses + for unsupported commands. The responses are now tagged. + +* Sun May 23 2004 Andreas Aardal Hanssen <andreas-binc@bincimap.org> +- UID STORE now responds with a UID data member as part of the + untagged FETCH responses. +- When copying, the message is now rewound before data is read. This + fixes partial copies of messages that have recently been parsed. +- bincimapd now takes the mailbox path as an option unqualified + argument to bincimapd, which overrides the mailbox path inherited + from bincimap-up or set through command line options. This fixes + a problem with vmailmgr. +- Added Daniel James' patch for fixing fetching of RFC822.TEXT, + which should be equivalent to BODY[TEXT] but included the header + in the response. + +* Fri May 21 2004 Andreas Aardal Hanssen <andreas-binc@bincimap.org> +- Fixed problem with the sequence set '*'. Binc IMAP claimed no + messages matched this set, but now the highest UID or sequence + number matches. + * Sun Apr 18 2004 Andreas Aardal Hanssen <andreas-binc@bincimap.org> - Released 1.2.7final diff --git a/configure.in b/configure.in @@ -10,10 +10,10 @@ dnl USA. dnl Process this file with autoconf to produce a configure script. dnl AC_PREREQ(2.57) -AC_INIT(bincimap, 1.2.7final, andreas-binc@bincimap.org) -AC_CONFIG_SRCDIR([config.h.in]) -AM_CONFIG_HEADER([config.h]) -AM_INIT_AUTOMAKE +AC_INIT(bincimap, 1.2.13final, andreas-binc@bincimap.org) +AC_CONFIG_SRCDIR(config.h.in) +AM_CONFIG_HEADER(config.h) +AM_INIT_AUTOMAKE(bincimap, 1.2.13final) dnl Checks for programs. AC_PROG_CXX @@ -40,7 +40,7 @@ bindir=$(eval echo $(eval echo ${bindir})) AC_MSG_CHECKING(--bindir) if [[ "x$bindir" = "xNONE/bin" ]]; then AC_MSG_RESULT([$prefix/bin]) - bindir=$prefix/bin + bindir="$prefix/bin" else AC_MSG_RESULT(using $bindir) fi @@ -51,7 +51,7 @@ sysconfdir=$(eval echo $(eval echo ${sysconfdir})) AC_MSG_CHECKING(--sysconfdir) if [[ "x$sysconfdir" = "xNONE/etc" ]]; then AC_MSG_RESULT([$prefix/etc]) - sysconfdir=$prefix/etc + sysconfdir="$prefix/etc" else AC_MSG_RESULT(using $sysconfdir) fi @@ -61,7 +61,7 @@ localstatedir=$(eval echo $(eval echo ${localstatedir})) AC_MSG_CHECKING(--localstatedir) if [[ "x$localstatedir" = "xNONE/var" ]]; then AC_MSG_RESULT([$prefix/var]) - localstatedir=$prefix/var + localstatedir="$prefix/var" else AC_MSG_RESULT(using $localstatedir) fi @@ -71,7 +71,7 @@ datadir=$(eval echo $(eval echo ${datadir})) AC_MSG_CHECKING(--datadir) if [[ "x$datadir" = "xNONE/share" ]]; then AC_MSG_RESULT([$prefix/share]) - datadir=$prefix/share + datadir="$prefix/share" else AC_MSG_RESULT(using $datadir) fi @@ -95,7 +95,7 @@ dnl --------------------------------------------------------------------------- AC_ARG_ENABLE(static, AC_HELP_STRING([--enable-static], [Enable static compile]), - [ if [[ "x$enableval" != "xno" ]]; then STATIC=" -static --all-static"; fi ], []) + [ if [[ "x$enableval" != "xno" ]]; then STATIC="-static"; fi ], []) AC_SUBST(STATIC) AC_MSG_CHECKING(wether to compile static or shared) @@ -123,6 +123,14 @@ else fi dnl --------------------------------------------------------------------------- +dnl Checks for the dl library, which is required on some platforms for +dnl static compiles. + +AC_CHECK_LIB(dl, dlopen, LIBDL=-ldl, LIBDL=) +AC_SUBST(LIBDL) +AC_SUBST(LIBSSL) + +dnl --------------------------------------------------------------------------- dnl Checks if we can compile and link against OpenSSL. Does a check dnl against the headers, trying different standard paths for the installation dnl of the include/openssl/... files. Then does the same with the libraries. @@ -146,13 +154,13 @@ AC_HELP_STRING([--without-ssl], [Disable SSL support]), if [[ "$WITH_SSL" = "1" ]]; then AC_MSG_CHECKING(whether -lsocket is available) - export LDTMP=$LIBS + export LDTMP="$LIBS" export LIBS="$LIBS -lsocket" AC_TRY_LINK([], [], LIBSOCKET="-lsocket"; AC_MSG_RESULT(yes), AC_MSG_RESULT(no)) - export LIBS=$LDTMP + export LIBS="$LDTMP" AC_MSG_CHECKING(for OpenSSL includes) - export CXXTMP=$CXXFLAGS + export CXXTMP="$CXXFLAGS" for k in . $SSLINCLUDEPATH /usr/include /usr/local/include /usr/local/ssl/include /usr/local/openssl/include /opt/ssl/include /opt/openssl/include; do export CXXFLAGS="$CXXTMP -I$k" AC_TRY_COMPILE([#include <openssl/ssl.h>], [SSL_write(0, 0, 0);], INCLUDESSL="-I$k"; AC_MSG_RESULT($k), []) @@ -161,20 +169,20 @@ if [[ "$WITH_SSL" = "1" ]]; then if [[ "x$INCLUDESSL" = "x" ]]; then AC_MSG_RESULT(not found) - export CXXFLAGS=$CXXTMP + export CXXFLAGS="$CXXTMP" fi AC_MSG_CHECKING(for OpenSSL libraries) - export LIBTMP=$LIBS - export LDTMP=$LDFLAGS + export LIBTMP="$LIBS" + export LDTMP="$LDFLAGS" for k in . $SSLLIBPATH /usr/lib /usr/local/lib /usr/local/ssl/lib /usr/local/openssl/lib /opt/ssl/lib /opt/openssl/lib; do export LDFLAGS="$LDTMP -L$k" - export LIBS="$LIBTMP -lssl -lcrypto $LIBSOCKET" - AC_TRY_LINK([#include <openssl/ssl.h>], [SSL_write(0, 0, 0);], LIBSSL="-L$k -lssl -lcrypto $LIBSOCKET"; AC_MSG_RESULT($k), [])  + export LIBS="$LIBTMP -lssl -lcrypto $LIBSOCKET $LIBDL" + AC_TRY_LINK([#include <openssl/ssl.h>], [SSL_write(0, 0, 0);], LIBSSL="-L$k -lssl -lcrypto $LIBSOCKET"; AC_MSG_RESULT($k), []) if [[ "x$LIBSSL" != "x" ]]; then break; fi done - export LIBS=$LIBTMP - export LDFLAGS=$LDTMP + export LIBS="$LIBTMP" + export LDFLAGS="$LDTMP" if [[ "x$LIBSSL" = "x" ]]; then AC_MSG_RESULT(not found) diff --git a/man/bincimap-up.1 b/man/bincimap-up.1 @@ -3,7 +3,7 @@ bincimap-up \- Authentication stub for Binc IMAP .SH "SYNOPSIS" -.B bincimap-up [ options... ] -- <authenticator> bincimapd +.B bincimap-up [ options... ] -- <authenticator> bincimapd [mailboxpath] .SH "DESCRIPTION" @@ -27,7 +27,7 @@ If set, allows plain text authentication in an unencrypted (SSL/TLS) IMAP session. .TP -\fB\-p, \-\-auth-penalty=<n>\fR +\fB\ \-\-auth-penalty=<n>\fR Server will sleep for <n> seconds if the client issues a username/password pair that fails to authenticate. @@ -205,17 +205,21 @@ with an example .B /opt location for the conf file and using .I checkpassword -as the authenticator. Notice that both the authentication stub and -the authenticated daemon must both have command line arguments, and that +as the authenticator. Notice that both the authentication stub and the +authenticated daemon must both have command line arguments, and that the authenticator comes after '--'. +Also notice that after bincimapd comes the mailbox path. This is +already set in bincimap.conf, so it's not necessary here, but shown +only for the sake of demonstration. + .RS .nf /opt/bincimap/bin/bincimap-up \\ --conf=/opt/bincimap/etc/bincimap.conf \\ -- \\ /bin/checkpassword \\ - /opt/bincimap/bin/bincimapd + /opt/bincimap/bin/bincimapd Maildir .fi .RE @@ -250,7 +254,7 @@ Global configurations file. All entries in this file can be overrun with command line arguments. .SH "COPYRIGHT" -Copyright (C) 2002-2004 Andreas Aardal Hanssen +Copyright (C) 2002-2005 Andreas Aardal Hanssen This is free software; see the source for copying conditions. There is NO warranty. diff --git a/man/bincimap.conf.5 b/man/bincimap.conf.5 @@ -262,7 +262,7 @@ m { .RE .SH "COPYRIGHT" -Copyright (C) 2002-2004 Andreas Aardal Hanssen +Copyright (C) 2002-2005 Andreas Aardal Hanssen This is free software; see the source for copying conditions. There is NO warranty. diff --git a/man/bincimapd.1 b/man/bincimapd.1 @@ -32,6 +32,11 @@ inherit options from bincimap-up through the environment. Passing arguments to bincimapd will override settings inherited from bincimap-up. +bincimapd takes one optional unqualified argument in addition to +regular command line options: the \fBMailbox path\fR. Appending a +path as an option to bincimapd will override any mailbox path set by +command line options or inherited from bincimap-up. + For a complete listing of options for bincimapd, see the bincimap-up man page. @@ -96,7 +101,7 @@ Note that it is essential that the authenticator invoked by bincimap-up does not clear the environment. .SH "COPYRIGHT" -Copyright (C) 2002-2004 Andreas Aardal Hanssen +Copyright (C) 2002-2005 Andreas Aardal Hanssen This is free software; see the source for copying conditions. There is NO warranty. diff --git a/service/log/run b/service/log/run @@ -0,0 +1,18 @@ +#!/bin/sh +# 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. + +# 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 Street #330, Boston, MA 02111-1307, +# USA. + +# $Id: run.in,v 1.1 2003/08/23 12:53:25 andreaha Exp $ +# daemontools supervise run-file for Binc IMAP Service. + +exec 2>&1 + +exec multilog t n5 s1048576 /usr/local/var/log/bincimap + diff --git a/service/log/run-ssl b/service/log/run-ssl @@ -0,0 +1,18 @@ +#!/bin/sh +# 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. + +# 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 Street #330, Boston, MA 02111-1307, +# USA. + +# $Id: run-ssl.in,v 1.1 2003/08/23 12:53:25 andreaha Exp $ +# daemontools supervise run-file for Binc IMAP Service. + +exec 2>&1 + +exec multilog t n5 s1048576 /usr/local/var/log/bincimap-ssl + diff --git a/service/run b/service/run @@ -0,0 +1,16 @@ +#!/bin/sh +# $Id: run.in,v 1.1.1.1 2003/08/18 18:06:05 andreaha Exp $ +# daemontools supervise run-file for Binc IMAP Service. + +exec 2>&1 + +exec tcpserver -c 100 -u 0 -g 0 \ + -l $(hostname) -HDRP \ + 0 143 \ + /usr/local/bin/bincimap-up \ + --logtype=multilog \ + --conf=/usr/local/etc/bincimap.conf -- \ + /bin/checkpassword \ + /usr/local/bin/bincimapd + + diff --git a/service/run-ssl b/service/run-ssl @@ -0,0 +1,14 @@ +#!/bin/sh +# $Id: run-ssl.in,v 1.1.1.1 2003/08/18 18:06:05 andreaha Exp $ +# daemontools supervise run-file for Binc IMAP Service. + +exec 2>&1 + +exec tcpserver -c 100 -u 0 -g 0 \ + -l $(hostname) -HDRP \ + 0 993 \ + /usr/local/bin/bincimap-up \ + --logtype=multilog \ + --conf=/usr/local/etc/bincimap.conf --ssl -- \ + /bin/checkpassword \ + /usr/local/bin/bincimapd diff --git a/src/Makefile.am b/src/Makefile.am @@ -18,7 +18,7 @@ bincimapd_SOURCES = address.cc address.h argparser.cc argparser.h authenticate.c bincimap_up_SOURCES = argparser.cc argparser.h authenticate.cc authenticate.h base64.cc base64.h bincimap-up.cc broker.cc broker.h convert.cc convert.h greeting.cc imapparser.cc imapparser.h io.cc io.h io-ssl.cc io-ssl.h operators.h operator-authenticate.cc operator-capability.cc operator-noop.cc operator-login.cc operator-logout.cc operator-starttls.cc recursivedescent.cc recursivedescent.h session.h session.cc session-initialize-bincimap-up.cc status.cc status.h storage.cc storage.h tools.cc tools.h #-------------------------------------------------------------------------- -bincimap_up_LDADD = @LIBSSL@ +bincimap_up_LDADD = @LIBSSL@ @LIBDL@ #-------------------------------------------------------------------------- bincimapd_LDFLAGS = @STATIC@ -DBINCIMAPD diff --git a/src/address.cc b/src/address.cc @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 diff --git a/src/address.h b/src/address.h @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 diff --git a/src/argparser.cc b/src/argparser.cc @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 @@ -61,15 +61,15 @@ bool CommandLineArgs::parse(int argc, char *argv[]) for (int i = 1; i < argc; ++i) { string s = argv[i]; if (s.length() < 2) { - errString = "syntax error: " + s; - return false; + unqualified.push_back(s); + continue; } if (s[0] != '-') { // read value of last argument if (lastKey == "") { - errString = "syntax error: " + s; - return false; + unqualified.push_back(s); + continue; } if (lastIsBoolean && (s != "yes" && s != "no")) { @@ -354,3 +354,9 @@ void CommandLineArgs::setTail(const string &str) { tail = str; } + +//---------------------------------------------------------------------- +const vector<string> &CommandLineArgs::getUnqualifiedArgs() const +{ + return unqualified; +} diff --git a/src/argparser.h b/src/argparser.h @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 @@ -33,8 +33,9 @@ */ #ifndef ARGPARSER_H_INCLUDED #define ARGPARSER_H_INCLUDED -#include <string> #include <map> +#include <string> +#include <vector> namespace Binc { class ArgOpts { @@ -75,6 +76,8 @@ namespace Binc { void setTail(const std::string &str); + const std::vector<std::string> &getUnqualifiedArgs() const; + private: void registerArg(const std::string &arg, const std::string &desc, bool boolean, bool optional); @@ -83,6 +86,7 @@ namespace Binc { std::map<std::string, ArgOpts> reg; std::map<std::string, std::string> args; std::map<std::string, bool> passedArgs; + std::vector<std::string> unqualified; std::string tail; std::string head; int ac; diff --git a/src/authenticate.cc b/src/authenticate.cc @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 @@ -225,6 +225,7 @@ int Binc::authenticate(Depot &depot, const string &username, bool error = false; // write the userid + signal(SIGPIPE, SIG_IGN); if (write(authintercom[1], username.c_str(), username.length()) != (int) username.length()) @@ -328,6 +329,7 @@ int Binc::authenticate(Depot &depot, const string &username, } for (;;) { + signal(SIGPIPE, SIG_IGN); int w = write(intercomw[1], data.c_str(), data.length()); if (w > 0) Session::getInstance().addReadBytes(w); @@ -406,22 +408,26 @@ int Binc::authenticate(Depot &depot, const string &username, switch (WEXITSTATUS(result)) { case 0: break; - case 1: - // authentication failed - sleep - logger << "<" << username - << "> authentication failed: wrong userid or password" << endl; - sleep(atoi(authpenalty)); - return 2; - case 111: case 2: // internal error logger << "<" << username << "> authentication failed: " + << (authenticated ? "authenticator " : "server ") + << " returned 2 (invalid use of authenticator)" << endl; + return -1; + case 111: + // internal error + logger << "<" << username << "> authentication failed: " << (authenticated ? "authenticator " : "server ") << " returned " << WEXITSTATUS(result) << " (internal error)" << endl; return -1; + case 1: default: - break; + // authentication failed - sleep. + logger << "<" << username + << "> authentication failed: wrong userid or password" << endl; + sleep(atoi(authpenalty)); + return 2; } return 0; diff --git a/src/authenticate.h b/src/authenticate.h @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 diff --git a/src/base64.cc b/src/base64.cc @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 diff --git a/src/base64.h b/src/base64.h @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 diff --git a/src/bincimap-up.cc b/src/bincimap-up.cc @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 @@ -142,7 +142,7 @@ int main(int argc, char *argv[]) Operator *o = broker->get(request.getName()); if (!o) { - com << "* NO The command \"" + com << request.getTag() << " NO The command \"" << (request.getUidMode() ? "UID " : "") << request.getName() << "\" is unsupported in this state. " diff --git a/src/bincimapd.cc b/src/bincimapd.cc @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 @@ -93,6 +93,8 @@ int main(int argc, char *argv[]) } Request request; + session.setLastError(""); + session.clearResponseCode(); recovery = false; BrokerFactory &brokerFactory = BrokerFactory::getInstance(); @@ -129,9 +131,10 @@ int main(int argc, char *argv[]) Operator *o = broker->get(request.getName()); if (!o) { - com << "* NO The command \"" - << (request.getUidMode() ? "UID " : "") << request.getName() - << "\" is not supported." << endl; + com << request.getTag() << " NO The command \"" + << (request.getUidMode() ? "UID " : "") + << request.getName() + << "\" is unsupported in this state. " << endl; recovery = true; continue; } @@ -160,8 +163,8 @@ int main(int argc, char *argv[]) switch (o->process(*dep, request)) { case Operator::OK: - com << request.getTag() << " OK " << request.getName() - << " completed" << endl; + com << request.getTag() << " OK " << session.getResponseCode() + << request.getName() << " completed" << endl; break; case Operator::NO: com << request.getTag() << " NO " << session.getResponseCode() @@ -169,8 +172,9 @@ int main(int argc, char *argv[]) session.clearResponseCode(); break; case Operator::BAD: - com << request.getTag() << " BAD " << request.getName() - << " failed: " << session.getLastError() << endl; + com << request.getTag() << " BAD " << session.getResponseCode() + << request.getName() << " failed: " << session.getLastError() + << endl; break; case Operator::NOTHING: break; diff --git a/src/broker.cc b/src/broker.cc @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 diff --git a/src/broker.h b/src/broker.h @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 diff --git a/src/convert.cc b/src/convert.cc @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 diff --git a/src/convert.h b/src/convert.h @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 @@ -54,7 +54,7 @@ namespace Binc { inline std::string toString(int i_in) { char intbuf[16]; - snprintf(intbuf, sizeof(intbuf), "%i", i_in); + snprintf(intbuf, sizeof(intbuf), "%d", i_in); return std::string(intbuf); } @@ -272,6 +272,9 @@ namespace Binc { } else if (*i == '*') regex += ".*?"; else if (*i == '%') { + regex += "(\\"; + regex += delimiter; + regex += "){0,1}"; regex += "[^\\"; regex += delimiter; regex += "]*?"; diff --git a/src/depot.cc b/src/depot.cc @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 @@ -192,6 +192,12 @@ Mailbox *Depot::getSelected(void) const } //-------------------------------------------------------------------- +void Depot::resetSelected(void) +{ + selectedmailbox = 0; +} + +//-------------------------------------------------------------------- Mailbox *Depot::getDefault(void) const { return defaultmailbox; @@ -201,10 +207,8 @@ Mailbox *Depot::getDefault(void) const bool Depot::createMailbox(const string &s_in) const { const string &mailboxname = mailboxToFilename(toCanonMailbox(s_in)); - if (mailboxname == "") { - setLastError("invalid mailbox name"); + if (mailboxname == "") return false; - } Mailbox *mailbox = getDefault(); if (mailbox == 0) { @@ -225,6 +229,8 @@ bool Depot::createMailbox(const string &s_in) const bool Depot::deleteMailbox(const string &s_in) const { const string &mailboxname = mailboxToFilename(toCanonMailbox(s_in)); + if (mailboxname == "") + return false; Mailbox *mailbox = get(s_in); if (mailbox == 0) { @@ -248,6 +254,8 @@ bool Depot::renameMailbox(const string &s_in, const string &t_in) const const string &source = mailboxToFilename(s_in).c_str(); const string &dest = mailboxToFilename(t_in).c_str(); + if (source == "" || dest == "") + return false; int nrenamed = 0; const iterator e = end(); @@ -297,20 +305,29 @@ bool Depot::renameMailbox(const string &s_in, const string &t_in) const bool Depot::getStatus(const std::string &s_in, Status &dest) const { const string mailbox = toCanonMailbox(s_in); + if (mailbox == "") { + setLastError("Unrecognized mailbox: " + toImapString(s_in)); + return false; + } + + string mailboxFilename = mailboxToFilename(mailbox); + if (mailboxFilename == "") + return false; + Mailbox *m = get(mailbox); if (m == 0) { setLastError("Unrecognized mailbox: " + toImapString(s_in)); return false; } - - int statusid = m->getStatusID(mailboxToFilename(mailbox)); + + int statusid = m->getStatusID(mailboxFilename); if (mailboxstatuses.find(mailbox) != mailboxstatuses.end()) { dest = mailboxstatuses[mailbox]; if (dest.getStatusID() == statusid) return true; } - if (!m->getStatus(mailboxToFilename(mailbox), dest)) { + if (!m->getStatus(mailboxFilename, dest)) { setLastError(m->getLastError()); return false; } @@ -493,15 +510,18 @@ string MaildirPPDepot::mailboxToFilename(const string &m) const //-------------------------------------------------------------------- string MaildirPPDepot::filenameToMailbox(const string &m) const { - if (m == ".") return "INBOX"; - else if (m.find(delimiter) != string::npos) return ""; + if (m == "." || m == "..") + return "INBOX"; + else if (m.find(delimiter) != string::npos) + return ""; else if (m != "" && m[0] == '.') { string tmp = m; for (string::iterator i = tmp.begin(); i != tmp.end(); ++i) if (*i == '.') *i = delimiter; return "INBOX" + tmp; - } else return ""; + } else + return ""; } //-------------------------------------------------------------------- diff --git a/src/depot.h b/src/depot.h @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 @@ -114,6 +114,7 @@ namespace Binc { bool setSelected(Mailbox *); Mailbox *getSelected(void) const; + void resetSelected(void); bool getStatus(const std::string &s_in, Status &dest) const; diff --git a/src/greeting.cc b/src/greeting.cc @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 @@ -61,8 +61,8 @@ void Binc::showGreeting(void) char mytime[ISO8601SIZE]; unsigned int size = strftime(mytime, sizeof(mytime), - "%Y-%m-%d %H:%M:%S %Z", mytm); - if (size >= sizeof(mytime)) + "%Y-%m-%d %H:%M:%S %z", mytm); + if (size >= sizeof(mytime) || size == 0) mytime[0] = 0; string version; @@ -72,6 +72,6 @@ void Binc::showGreeting(void) version = "v"VERSION" "; com << "* OK Welcome to Binc IMAP " << version - << "Copyright (C) 2002-2004 Andreas Aardal Hanssen at " + << "Copyright (C) 2002-2005 Andreas Aardal Hanssen at " << mytime << endl; } diff --git a/src/imapparser.cc b/src/imapparser.cc @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 @@ -150,6 +150,7 @@ const string &Request::getDate(void) const void Request::setCharSet(const string &s_in) { charset = s_in; + uppercase(charset); } //------------------------------------------------------------------------ @@ -363,11 +364,15 @@ string BincImapParserFetchAtt::toString(void) if (headerlist.size() != 0) { tmp += " ("; - for (vector<string>::iterator i = headerlist.begin(); - i != headerlist.end(); ++i) { - if (i != headerlist.begin()) - tmp += " "; - tmp += *i; + if (headerlist.size() == 0) { + tmp += "\"\""; + } else { + for (vector<string>::iterator i = headerlist.begin(); + i != headerlist.end(); ++i) { + if (i != headerlist.begin()) + tmp += " "; + tmp += Binc::toImapString(*i); + } } tmp += ")"; } diff --git a/src/imapparser.h b/src/imapparser.h @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 diff --git a/src/io-ssl.cc b/src/io-ssl.cc @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 @@ -146,7 +146,7 @@ bool SSLEnabledIO::setModeSSL(void) } if (session.globalconfig["SSL"]["verify peer"] == "yes") - SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, 0); + SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, 0); else SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, 0); diff --git a/src/io-ssl.h b/src/io-ssl.h @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 diff --git a/src/io.cc b/src/io.cc @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 diff --git a/src/io.h b/src/io.h @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 diff --git a/src/mailbox.cc b/src/mailbox.cc @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 @@ -72,9 +72,9 @@ bool Mailbox::isReadOnly(void) const } //------------------------------------------------------------------------ -void Mailbox::setReadOnly(void) +void Mailbox::setReadOnly(bool readOnly) { - readOnly = true; + this->readOnly = readOnly; } //------------------------------------------------------------------------ diff --git a/src/mailbox.h b/src/mailbox.h @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 @@ -116,7 +116,7 @@ namespace Binc { virtual void bumpUidValidity(const std::string &) const = 0; //-- Specific for one mailbox - void setReadOnly(void); + void setReadOnly(bool readOnly); bool isReadOnly(void) const; virtual const std::string getTypeName(void) const = 0; diff --git a/src/maildir-close.cc b/src/maildir-close.cc @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 @@ -51,10 +51,10 @@ void Binc::Maildir::closeMailbox(void) if (!selected) return; - if (mailboxchanged) { + if (mailboxchanged && !readOnly) writeCache(); - mailboxchanged = false; - } + + mailboxchanged = false; if (uidnextchanged) { const string uidvalfilename = path + "/bincimap-uidvalidity"; diff --git a/src/maildir-create.cc b/src/maildir-create.cc @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 diff --git a/src/maildir-delete.cc b/src/maildir-delete.cc @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 diff --git a/src/maildir-expunge.cc b/src/maildir-expunge.cc @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 diff --git a/src/maildir-readcache.cc b/src/maildir-readcache.cc @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 @@ -56,21 +56,31 @@ Maildir::ReadCacheResult Maildir::readCache(void) string section, key, value; string uidvalfileversion; + if (!uidvalfile.ok()) { + uidnext = 1; + uidvalidity = time(0); + uidvalfiledropped = true; + setLastError(uidvalfile.getLastError()); + return NoCache; + } + uidvalidity = 0; uidnext = 0; - while (uidvalfile.get(&section, &key, &value)) + while (uidvalfile.get(&section, &key, &value)) { if (section == "depot" && key == "_uidvalidity") uidvalidity = (unsigned int) atoi(value); else if (section == "depot" && key == "_uidnext") uidnext = (unsigned int) atoi(value); else if (section == "depot" && key == "_version") uidvalfileversion = value; + } if (!uidvalfile.eof()) { uidnext = 1; uidvalidity = time(0); uidvalfiledropped = true; + setLastError(uidvalfile.getLastError()); return NoCache; } @@ -91,6 +101,14 @@ Maildir::ReadCacheResult Maildir::readCache(void) unsigned int _internaldate = 0; string _id; + if (!cache.ok()) { + uidnext = 1; + uidvalidity = time(0); + uidvalfiledropped = true; + setLastError(uidvalfile.getLastError()); + return NoCache; + } + while (cache.get(&section, &key, &value)) { if (section == "depot" && key == "_version" && value != CACHEFILEVERSION) { uidnext = 1; diff --git a/src/maildir-scan.cc b/src/maildir-scan.cc @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 @@ -72,12 +72,16 @@ namespace { } struct stat mystat; - logger << "possible crash detected. waiting for mailbox lock " << lock << "." << endl; if (lstat(lock.c_str(), &mystat) == 0) { if ((time(0) - mystat.st_ctime) > 300) { - if (unlink(lock.c_str()) == 0) continue; - else logger << "failed to force mailbox lock: " << lock - << ", " << string(strerror(errno)) << endl; + if (unlink(lock.c_str()) == 0) { + logger << "5 minute old lock detected: " << lock + << ", lock deleted." << endl; + continue; + } else { + logger << "failed to force mailbox lock: " << lock + << ", " << string(strerror(errno)) << endl; + } } } else { if (errno != ENOENT) { @@ -183,7 +187,7 @@ Maildir::ScanResult Maildir::scan(bool forceScan) case Error: // An error with reading the cache files when it's not the first // time we scan the depot is treated as an error. - if (!firstscan) { + if (!firstscan && !readOnly) { old_cur_st_mtime = (time_t) 0; old_cur_st_ctime = (time_t) 0; old_new_st_mtime = (time_t) 0; @@ -233,6 +237,12 @@ Maildir::ScanResult Maildir::scan(bool forceScan) struct stat mystat; if (stat(fullfilename.c_str(), &mystat) != 0) { if (errno == ENOENT) { + // prevent looping due to stale symlinks + if (lstat(fullfilename.c_str(), &mystat) == 0) { + logger << "dangling symlink: " << fullfilename << endl; + continue; + } + // a rare race between readdir and stat force us to restart // the scan. closedir(pdir); @@ -277,8 +287,9 @@ Maildir::ScanResult Maildir::scan(bool forceScan) } // move files from new/ to cur/ + string newName = curpath + pdirent->d_name; if (rename((newpath + pdirent->d_name).c_str(), - (curpath + pdirent->d_name).c_str()) != 0) { + (newName + ":2,").c_str()) != 0) { logger << "error moving messages from" " new to cur: skipping " << newpath << pdirent->d_name << ": " << strerror(errno) << endl; @@ -299,9 +310,6 @@ Maildir::ScanResult Maildir::scan(bool forceScan) // Then, scan cur // open directory - int oldmess = 0; - int newmess = 0; - if ((pdir = opendir(curpath.c_str())) == 0) { string reason = "Maildir::scan::opendir(\"" + curpath + "\") == 0 ("; reason += strerror(errno); @@ -316,7 +324,7 @@ Maildir::ScanResult Maildir::scan(bool forceScan) index.clearFileNames(); // this is to sort recent messages by internaldate - multimap<time_t, MaildirMessage> tempMessageMap; + multimap<unsigned int, MaildirMessage> tempMessageMap; // scan all entries while ((pdirent = readdir(pdir)) != 0) { @@ -350,14 +358,17 @@ Maildir::ScanResult Maildir::scan(bool forceScan) } } - index.insert(uniquename, 0, filename); - struct stat mystat; MaildirMessage *message = get(uniquename); if (!message || message->getInternalDate() == 0) { string fullfilename = curpath + filename; if (stat(fullfilename.c_str(), &mystat) != 0) { if (errno == ENOENT) { + // prevent looping due to stale symlinks + if (lstat(fullfilename.c_str(), &mystat) == 0) { + logger << "dangling symlink: " << fullfilename << endl; + continue; + } // a rare race between readdir and stat force us to restart // the scan. index.clearFileNames(); @@ -379,10 +390,11 @@ Maildir::ScanResult Maildir::scan(bool forceScan) mailboxchanged = true; } - + + index.insert(uniquename, 0, filename); + // If we have this message in memory already.. if (message) { - oldmess++; if (message->getInternalDate() == 0) { mailboxchanged = true; @@ -392,39 +404,41 @@ Maildir::ScanResult Maildir::scan(bool forceScan) // then confirm that this message was not expunged message->setUnExpunged(); - // update the flags with what new flags we found in the filename + // update the flags with what new flags we found in the filename, + // but keep the \Recent flag regardless. if (mflags != (message->getStdFlags() & ~Message::F_RECENT)) { + int oldflags = message->getStdFlags(); message->resetStdFlags(); - message->setStdFlag(mflags); + message->setStdFlag(mflags | (oldflags & Message::F_RECENT)); } continue; } - newmess++; - // Wait with delegating UIDs until all entries have been // read. Only then can we sort by internaldate and delegate new - // UIDs. + // UIDs in the proper order. MaildirMessage m(*this); m.setUID(0); m.setSize(0); m.setInternalDate(mystat.st_mtime); - m.setStdFlag(mflags | Message::F_RECENT); + m.setStdFlag((mflags | Message::F_RECENT) & ~Message::F_EXPUNGED); m.setUnique(uniquename); - tempMessageMap.insert(make_pair(mystat.st_mtime, m)); + tempMessageMap.insert(make_pair((unsigned int) mystat.st_mtime, m)); mailboxchanged = true; } closedir(pdir); - // Recent messages are added, ordered by internaldate. + // Recent messages are added, ordered by internaldate. Also delegate + // UIDs. { - multimap<time_t, MaildirMessage>::iterator i = tempMessageMap.begin(); + int readonlyuidnext = uidnext; + multimap<unsigned int, MaildirMessage>::iterator i = tempMessageMap.begin(); while (i != tempMessageMap.end()) { - i->second.setUID(uidnext++); - multimap<time_t, MaildirMessage>::iterator itmp = i; + i->second.setUID(readOnly ? readonlyuidnext++ : uidnext++); + multimap<unsigned int, MaildirMessage>::iterator itmp = i; ++itmp; add(i->second); tempMessageMap.erase(i); @@ -435,8 +449,10 @@ Maildir::ScanResult Maildir::scan(bool forceScan) tempMessageMap.clear(); - // Messages that existed in the cache that we read, but did not - // exist in the Maildir, are removed from the messages list. + // Some messages may have been detected by another server, and then + // written to the cache, and then expunged again without us + // accessing the cache nor the maildir. We need to remove those from + // our internal message list. Mailbox::iterator jj = begin(SequenceSet::all(), INCLUDE_EXPUNGED | SQNR_MODE); while (jj != end()) { MaildirMessage &message = (MaildirMessage &)*jj; @@ -446,6 +462,8 @@ Maildir::ScanResult Maildir::scan(bool forceScan) jj.erase(); continue; } + } else if (message.getInternalFlags() & MaildirMessage::JustArrived) { + message.clearInternalFlag(MaildirMessage::JustArrived); } ++jj; diff --git a/src/maildir-scanfilesnames.cc b/src/maildir-scanfilesnames.cc @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 diff --git a/src/maildir-select.cc b/src/maildir-select.cc @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 diff --git a/src/maildir-updateflags.cc b/src/maildir-updateflags.cc @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 @@ -51,6 +51,7 @@ void Binc::Maildir::updateFlags(void) if (readOnly) return; + // open the cur/ directory string curpath = path + "/cur/"; DIR *pdir = opendir(curpath.c_str()); if (pdir == 0) { @@ -60,12 +61,20 @@ void Binc::Maildir::updateFlags(void) logger << reason << endl; return; } - + + // read all entries in the directory + vector<string> entries; struct dirent *pdirent; while ((pdirent = readdir(pdir)) != 0) { string filename = pdirent->d_name; if (filename[0] == '.') continue; + entries.push_back(filename); + } + closedir(pdir); + + for (vector<string>::const_iterator it = entries.begin(); it != entries.end(); ++it) { + string filename = *it; string uniquename; string::size_type pos; @@ -90,7 +99,16 @@ void Binc::Maildir::updateFlags(void) if (srcname != destname) { if (rename(srcname.c_str(), destname.c_str()) != 0) { if (errno == ENOENT) { - // FIXME: restart scan + closedir(pdir); + pdir = opendir(curpath.c_str()); + if (pdir == 0) { + string reason = "failed to open " + curpath + ": "; + reason += strerror(errno); + logger << reason << endl; + return; + } + + continue; } logger << "warning: rename(" << srcname @@ -104,6 +122,4 @@ void Binc::Maildir::updateFlags(void) continue; } } - - closedir(pdir); } diff --git a/src/maildir-writecache.cc b/src/maildir-writecache.cc @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 diff --git a/src/maildir.cc b/src/maildir.cc @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 @@ -75,12 +75,15 @@ Maildir::iterator::iterator(Maildir *home, unsigned int _mod) : BaseIterator(1), mailbox(home), bset(_bset), mod(_mod), i(it) { + uidmax = home->getMaxUid(); + sqnrmax = home->getMaxSqnr(); } //------------------------------------------------------------------------ Maildir::iterator::iterator(const iterator &copy) : BaseIterator(copy.sqnr), mailbox(copy.mailbox), - bset(copy.bset), mod(copy.mod), i(copy.i) + bset(copy.bset), mod(copy.mod), i(copy.i), uidmax(copy.uidmax), + sqnrmax(copy.sqnrmax) { } @@ -92,6 +95,8 @@ Maildir::iterator &Maildir::iterator::operator =(const iterator &copy) bset = copy.bset; mod = copy.mod; i = copy.i; + uidmax = copy.uidmax; + sqnrmax = copy.sqnrmax; return *this; } @@ -146,7 +151,16 @@ void Maildir::iterator::reposition(void) continue; } - if (!bset.isInSet(mod & SQNR_MODE ? sqnr : message.getUID())) { + bool inset = false; + if (mod & SQNR_MODE) { + if (bset.isInSet(sqnr) || (!bset.isLimited() && sqnr == sqnrmax)) + inset = true; + } else { + if (bset.isInSet(message.getUID()) || (!bset.isLimited() && message.getUID() == uidmax)) + inset = true; + } + + if (!inset) { ++i; if (!message.isExpunged()) ++sqnr; @@ -221,6 +235,7 @@ bool Maildir::getUpdates(bool doscan, unsigned int type, unsigned int exists = 0; unsigned int recent = 0; + bool displayExists = false; // count messages, find recent if (!readOnly && (type & PendingUpdates::EXPUNGE)) { @@ -233,6 +248,8 @@ bool Maildir::getUpdates(bool doscan, unsigned int type, if (message.isExpunged()) { updates.addExpunged(i.getSqnr()); i.erase(); + mailboxchanged = true; + displayExists = true; } else ++i; } @@ -247,7 +264,7 @@ bool Maildir::getUpdates(bool doscan, unsigned int type, if (message.getStdFlags() & Message::F_RECENT) ++recent; } - if (exists != oldexists) + if (displayExists || exists != oldexists) updates.setExists(oldexists = exists); if (recent != oldrecent) @@ -260,7 +277,7 @@ bool Maildir::getUpdates(bool doscan, unsigned int type, if (message.hasFlagsChanged()) { int flags = message.getStdFlags(); - updates.addFlagUpdates(i.getSqnr(), flags); + updates.addFlagUpdates(i.getSqnr(), message.getUID(), flags); message.setFlagsUnchanged(); } @@ -273,6 +290,9 @@ bool Maildir::getUpdates(bool doscan, unsigned int type, //------------------------------------------------------------------------ bool Maildir::isMailbox(const std::string &s_in) const { + if (s_in == "") + return false; + struct stat mystat; return ((stat((s_in + "/cur").c_str(), &mystat) == 0 @@ -320,6 +340,9 @@ bool Maildir::isMarked(const std::string &s_in) const //------------------------------------------------------------------------ unsigned int Maildir::getStatusID(const string &path) const { + if (path == "") + return 0; + unsigned int statusid = 0; struct stat mystat; if (stat((path + "/new").c_str(), &mystat) == 0) @@ -428,48 +451,58 @@ bool Maildir::getStatus(const string &path, Status &s) const //------------------------------------------------------------------------ unsigned int Maildir::getMaxUid(void) const { - unsigned int max = 0; - Mailbox::iterator i = begin(SequenceSet::all(), SKIP_EXPUNGED | SQNR_MODE); - for (; i != end(); ++i) - if ((*i).getUID() > max) - max = (*i).getUID(); + MessageMap::const_iterator i = messages.end(); + if (i == messages.begin()) + return 0; - return max; + --i; + for (;;) { + const MaildirMessage &message = i->second; + if (message.isExpunged()) { + if (i == messages.begin()) + return 0; + --i; + } else { + return message.getUID(); + } + } + + return 0; } //------------------------------------------------------------------------ unsigned int Maildir::getMaxSqnr(void) const { - unsigned int max = 0; - Mailbox::iterator i = begin(SequenceSet::all(), SKIP_EXPUNGED | SQNR_MODE); - for (; i != end(); ++i) - if (i.getSqnr() > max) - max = i.getSqnr(); + int sqnr = messages.size(); + MessageMap::const_iterator i = messages.end(); + if (i == messages.begin()) + return 0; + + --i; + for (;;) { + const MaildirMessage &message = i->second; + if (message.isExpunged()) { + if (i == messages.begin()) + return 0; + --sqnr; + --i; + } else { + return sqnr; + } + } - return max; + return 0; } //------------------------------------------------------------------------ unsigned int Maildir::getUidValidity(void) const { - // Why scan? - // if (uidvalidity < 1) { - // FIXME: Catch any error here - // scan(); - //} - return uidvalidity; } //------------------------------------------------------------------------ unsigned int Maildir::getUidNext(void) const { - // Why scan? - //if (uidnext < 1) { - // FIXME: Catch any error here - //scan(); - //} - return uidnext; } @@ -534,7 +567,7 @@ bool Maildir::commitNewMessages(const string &mbox) ssid << (int) tv.tv_sec << "." << "R" << (int) rand() << "M" << (int) tv.tv_usec - << "P" << session.getPid() + << "P" << (int) session.getPid() << "Q" << numDeliveries++ << "." << session.getHostname(); @@ -689,7 +722,7 @@ bool Maildir::fastCopy(Message &m, Mailbox &desttype, ssid << (int) tv.tv_sec << "." << "R" << (int) rand() << "M" << (int) tv.tv_usec - << "P" << session.getPid() + << "P" << (int) session.getPid() << "Q" << numDeliveries++ << "." << session.getHostname(); @@ -740,6 +773,9 @@ MaildirMessage *Maildir::get(const std::string &id) //------------------------------------------------------------------------ void Maildir::add(MaildirMessage &m) { + MessageMap::iterator it = messages.find(m.getUID()); + if (it != messages.end()) + messages.erase(it); messages.insert(make_pair(m.getUID(), m)); index.insert(m.getUnique(), m.getUID()); } diff --git a/src/maildir.h b/src/maildir.h @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 @@ -107,6 +107,9 @@ namespace Binc { int mod; MessageMap::iterator i; + unsigned int uidmax; + unsigned int sqnrmax; + iterator(iterator &external); }; diff --git a/src/maildirmessage.cc b/src/maildirmessage.cc @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 @@ -126,7 +126,7 @@ namespace { } //---------------------------------------------------------------------- - void bodyStructure(IO &io, const MimePart *message, bool extended = true) + void bodyStructure(IO &io, const MimePart *message, bool extended) { HeaderItem hitem; if (message->isMultipart() && message->members.size() > 0) { @@ -134,107 +134,110 @@ namespace { for (vector<MimePart>::const_iterator i = message->members.begin(); i != message->members.end(); ++i) - bodyStructure(io, &(*i)); + bodyStructure(io, &(*i), extended); io << " "; io << toImapString(message->getSubType()); - io << " "; - vector<string> parameters; - vector<string> headers; - string tmp; + if (extended) { + io << " "; - string type, subtype; + vector<string> parameters; + vector<string> headers; + string tmp; - tmp = ""; - if (message->h.getFirstHeader("content-type", hitem)) { - tmp = unfold(hitem.getValue()); - trim(tmp); + string type, subtype; - vector<string> v; - split(tmp, ";", v); + tmp = ""; + if (message->h.getFirstHeader("content-type", hitem)) { + tmp = unfold(hitem.getValue()); + trim(tmp); + + vector<string> v; + split(tmp, ";", v); - for (vector<string>::const_iterator i = v.begin(); i != v.end(); ++i) { - string element = *i; - trim(element); - if (element.find('=') != string::npos) { - string::size_type pos = element.find('='); - string s = element.substr(0, pos); - string t = element.substr(pos + 1); - trim(s, " \""); - trim(t, " \""); - parameters.push_back(s); - parameters.push_back(t); + for (vector<string>::const_iterator i = v.begin(); i != v.end(); ++i) { + string element = *i; + trim(element); + if (element.find('=') != string::npos) { + string::size_type pos = element.find('='); + string s = element.substr(0, pos); + string t = element.substr(pos + 1); + trim(s, " \""); + trim(t, " \""); + parameters.push_back(s); + parameters.push_back(t); + } } - } - if (parameters.size() != 0) { - io << "("; - for (vector<string>::const_iterator i = parameters.begin(); - i != parameters.end(); ++i) { - if (i != parameters.begin()) - io << " "; - io << toImapString(*i); - } - io << ")"; + if (parameters.size() != 0) { + io << "("; + for (vector<string>::const_iterator i = parameters.begin(); + i != parameters.end(); ++i) { + if (i != parameters.begin()) + io << " "; + io << toImapString(*i); + } + io << ")"; + } else + io << "NIL"; } else io << "NIL"; - } else - io << "NIL"; - // CONTENT-DISPOSITION - io << " "; - tmp = ""; - if (message->h.getFirstHeader("content-disposition", hitem)) { - tmp = hitem.getValue(); - trim(tmp); + // CONTENT-DISPOSITION + io << " "; + tmp = ""; + if (message->h.getFirstHeader("content-disposition", hitem)) { + tmp = hitem.getValue(); + trim(tmp); - vector<string> v; - split(tmp, ";", v); - if (v.size() > 0) { - string disp = v[0]; - trim(disp); - io << "(" << toImapString(disp); - io << " "; - if (v.size() > 1) { - io << "("; - vector<string>::const_iterator i = v.begin(); - ++i; - bool wrote = false; - while (i != v.end()) { - string s = *i; - trim(s); + vector<string> v; + split(tmp, ";", v); + if (v.size() > 0) { + string disp = v[0]; + trim(disp); + io << "(" << toImapString(disp); + io << " "; + if (v.size() > 1) { + io << "("; + vector<string>::const_iterator i = v.begin(); + ++i; + bool wrote = false; + while (i != v.end()) { + string s = *i; + trim(s); - string::size_type pos = s.find('='); - string key = s.substr(0, pos); - string value = s.substr(pos + 1); - trim(key); - trim(value); + string::size_type pos = s.find('='); + string key = s.substr(0, pos); + string value = s.substr(pos + 1); + trim(key); + trim(value); - trim(key, " \""); - trim(value, " \""); + trim(key, " \""); + trim(value, " \""); - if (!wrote) wrote = true; - else io << " "; - io << toImapString(key); + if (!wrote) wrote = true; + else io << " "; + io << toImapString(key); - io << " "; - io << toImapString(value); + io << " "; + io << toImapString(value); - ++i; - } + ++i; + } + io << ")"; + } else + io << "NIL"; io << ")"; - } else + } else io << "NIL"; - io << ")"; } else io << "NIL"; - } else - io << "NIL"; - // CONTENT-LANGUAGE - io << " "; - printOneHeader(io, message, "content-language"); + // CONTENT-LANGUAGE + io << " "; + printOneHeader(io, message, "content-language"); + } io << ")"; } else { @@ -336,7 +339,7 @@ namespace { io << " "; envelope(io, &message->members[0]); io << " "; - bodyStructure(io, &message->members[0]); + bodyStructure(io, &message->members[0], extended); io << " "; io << message->getNofBodyLines(); } @@ -615,7 +618,14 @@ int MaildirMessage::getFile(void) const oflags |= O_LARGEFILE; #endif while ((fd = open(fpath.c_str(), oflags)) == -1) { - if (errno != ENOENT) { + if (errno == ENOENT) { + struct stat st; + if (lstat(fpath.c_str(), &st) != -1) { + IO &logger = IOFactory::getInstance().get(2); + logger << "dangling symlink: " << fpath << endl; + return -1; + } + } else { IO &logger = IOFactory::getInstance().get(2); logger << "unable to open " << fpath << ": " << strerror(errno) << endl; @@ -671,6 +681,17 @@ string MaildirMessage::getFileName(void) const } //------------------------------------------------------------------------ +void MaildirMessage::rewind(void) +{ + if (fd == -1) { + if ((fd == getFile()) == -1) + return; + } + + lseek(fd, 0, SEEK_SET); +} + +//------------------------------------------------------------------------ int MaildirMessage::readChunk(string &chunk) { if (fd == -1) { @@ -678,7 +699,6 @@ int MaildirMessage::readChunk(string &chunk) return -1; } - char buffer[1024]; ssize_t readBytes = read(fd, buffer, (size_t) sizeof(buffer)); if (readBytes == -1) { diff --git a/src/maildirmessage.h b/src/maildirmessage.h @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 @@ -162,6 +162,12 @@ namespace Binc { time_t getInternalDate(void) const; /*! + Resets the current read position to the first character of this + message. + */ + void rewind(void); + + /*! Reads a chunk of up to 4096 bytes from a message. Call close() before readChunk() to read the first chunk from a message. diff --git a/src/message.h b/src/message.h @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 @@ -93,7 +93,7 @@ namespace Binc { virtual void setInternalDate(time_t) = 0; virtual time_t getInternalDate(void) const = 0; - // virtual void rewind(void) = 0; + virtual void rewind(void) = 0; virtual int readChunk(std::string &) = 0; virtual bool appendChunk(const std::string &) = 0; virtual void close(void) = 0; diff --git a/src/mime-getpart.cc b/src/mime-getpart.cc @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 diff --git a/src/mime-parsefull.cc b/src/mime-parsefull.cc @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 @@ -423,19 +423,6 @@ int Binc::MimePart::parseFull(const string &toboundary, int &boundarysize) const } } - // make sure bodylength doesn't overflow - bodylength = crlfoffset; - if (bodylength >= bodystartoffsetcrlf) { - bodylength -= bodystartoffsetcrlf; - if (bodylength >= (unsigned int) boundarysize) { - bodylength -= (unsigned int) boundarysize; - } else { - bodylength = 0; - } - } else { - bodylength = 0; - } - // read all mime parts. if (!foundendofpart && !eof) { bool quit = false; @@ -451,6 +438,7 @@ int Binc::MimePart::parseFull(const string &toboundary, int &boundarysize) const } members.push_back(m); + nlines += m.getNofLines(); } while (!quit); } @@ -551,6 +539,19 @@ int Binc::MimePart::parseFull(const string &toboundary, int &boundarysize) const } } + // make sure bodylength doesn't overflow + bodylength = crlfoffset; + if (bodylength >= bodystartoffsetcrlf) { + bodylength -= bodystartoffsetcrlf; + if (bodylength >= (unsigned int) boundarysize) { + bodylength -= (unsigned int) boundarysize; + } else { + bodylength = 0; + } + } else { + bodylength = 0; + } + } else { // If toboundary is empty, then we read until the end of the // file. Otherwise we will read until we encounter toboundary. diff --git a/src/mime-parseonlyheader.cc b/src/mime-parseonlyheader.cc @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 diff --git a/src/mime-printbody.cc b/src/mime-printbody.cc @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 diff --git a/src/mime-printdoc.cc b/src/mime-printdoc.cc @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 diff --git a/src/mime-printheader.cc b/src/mime-printheader.cc @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 diff --git a/src/mime-utils.h b/src/mime-utils.h @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 diff --git a/src/mime.cc b/src/mime.cc @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 diff --git a/src/mime.h b/src/mime.h @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 diff --git a/src/operator-append.cc b/src/operator-append.cc @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 diff --git a/src/operator-authenticate.cc b/src/operator-authenticate.cc @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 @@ -88,7 +88,7 @@ Operator::ProcessResult AuthenticateOperator::process(Depot &depot, // we only allow this type of authentication over a plain // connection if it is passed as argument or given in the conf // file. - if (!session.command.ssl && !allowplain && !getenv("ALLOWPLAIN")) { + if (!session.command.ssl && session["sslmode"] != "yes" && !allowplain && !getenv("ALLOWPLAIN")) { session.setLastError("Plain text password authentication" " is disallowed. Please try enabling SSL" " or TLS in your mail client."); @@ -141,7 +141,7 @@ Operator::ProcessResult AuthenticateOperator::process(Depot &depot, } else if (authtype == "PLAIN") { // we only allow this type of authentication over an SSL encrypted // connection. - if (!session.command.ssl && !allowplain && !getenv("ALLOWPLAIN")) { + if (!session.command.ssl && session["sslmode"] != "yes" && !allowplain && !getenv("ALLOWPLAIN")) { session.setLastError("Plain text password authentication" " is disallowed. Please try enabling SSL" " or TLS in your mail client."); diff --git a/src/operator-capability.cc b/src/operator-capability.cc @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 @@ -93,7 +93,7 @@ Operator::ProcessResult CapabilityOperator::process(Depot &depot, const bool allowplain = (session.globalconfig["Authentication"]["allow plain auth in non ssl"] == "yes"); - if (session.command.ssl || allowplain || getenv("ALLOWPLAIN")) + if (session.command.ssl || session["sslmode"] == "yes" || allowplain || getenv("ALLOWPLAIN")) com << " AUTH=LOGIN AUTH=PLAIN"; else com << " LOGINDISABLED"; diff --git a/src/operator-check.cc b/src/operator-check.cc @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 diff --git a/src/operator-close.cc b/src/operator-close.cc @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 @@ -74,6 +74,7 @@ Operator::ProcessResult CloseOperator::process(Depot &depot, Mailbox *mailbox = depot.getSelected(); mailbox->expungeMailbox(); mailbox->closeMailbox(); + depot.resetSelected(); Session &session = Session::getInstance(); session.setState(Session::AUTHENTICATED); diff --git a/src/operator-copy.cc b/src/operator-copy.cc @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 @@ -116,6 +116,9 @@ Operator::ProcessResult CopyOperator::process(Depot &depot, dest->setStdFlag(source.getStdFlags()); dest->setInternalDate(source.getInternalDate()); + // Reset the read position to the beginning of the source message + source.rewind(); + // Copy chunks from the source message over to the destination // message. string chunk; diff --git a/src/operator-create.cc b/src/operator-create.cc @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 diff --git a/src/operator-delete.cc b/src/operator-delete.cc @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 diff --git a/src/operator-examine.cc b/src/operator-examine.cc @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 diff --git a/src/operator-expunge.cc b/src/operator-expunge.cc @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 @@ -74,10 +74,20 @@ Operator::ProcessResult ExpungeOperator::process(Depot &depot, Mailbox *mailbox = depot.getSelected(); mailbox->expungeMailbox(); - pendingUpdates(mailbox, PendingUpdates::EXPUNGE - | PendingUpdates::EXISTS - | PendingUpdates::RECENT - | PendingUpdates::FLAGS, true); + if (!pendingUpdates(mailbox, PendingUpdates::EXPUNGE + | PendingUpdates::EXISTS + | PendingUpdates::RECENT + | PendingUpdates::FLAGS, true, false, true)) { + Session &session = Session::getInstance(); + IO &com = IOFactory::getInstance().get(1); + IO &logger = IOFactory::getInstance().get(2); + logger << "when scanning mailbox: " + << session.getLastError() << endl; + com << "* BYE " << session.getLastError() << endl; + com.flushContent(); + session.setState(Session::LOGOUT); + return NOTHING; + } return OK; } diff --git a/src/operator-fetch.cc b/src/operator-fetch.cc @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 @@ -42,6 +42,7 @@ #include "mailbox.h" #include "operators.h" #include "imapparser.h" +#include "pendingupdates.h" #include "recursivedescent.h" #include "session.h" #include "convert.h" @@ -217,7 +218,7 @@ Operator::ProcessResult FetchOperator::process(Depot &depot, char internal[64]; string iDateStr; if (strftime(internal, sizeof(internal), - "%d-%b-%Y %H:%M:%S %Z", _tm) != 0) + "%d-%b-%Y %H:%M:%S %z", _tm) != 0) iDateStr = internal; else iDateStr = "NIL"; @@ -363,16 +364,16 @@ Operator::ProcessResult FetchOperator::process(Depot &depot, unsigned int size; if (fatt.sectiontext == "" && fatt.section == "") size = message.getDocSize(fatt.offsetstart, - fatt.offsetlength); + fatt.offsetlength, true); else size = message.getBodySize(fatt.section, fatt.offsetstart, fatt.offsetlength); - com << "{" << size << "}\r\n"; + com << " {" << size << "}\r\n"; if (fatt.sectiontext == "" && fatt.section == "") message.printDoc(fatt.offsetstart, - fatt.offsetlength); + fatt.offsetlength, true); else message.printBody(fatt.section, fatt.offsetstart, fatt.offsetlength); @@ -403,6 +404,21 @@ Operator::ProcessResult FetchOperator::process(Depot &depot, if (updateFlags) mailbox->updateFlags(); + if (!pendingUpdates(mailbox, + PendingUpdates::FLAGS + | PendingUpdates::EXISTS + | PendingUpdates::RECENT + | PendingUpdates::EXPUNGE, + true)) { + IO &logger = IOFactory::getInstance().get(2); + logger << "when scanning mailbox: " + << session.getLastError() << endl; + com << "* BYE " << session.getLastError() << endl; + com.flushContent(); + session.setState(Session::LOGOUT); + return NOTHING; + } + return OK; } diff --git a/src/operator-list.cc b/src/operator-list.cc @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 @@ -105,11 +105,20 @@ Operator::ProcessResult ListOperator::process(Depot &depot, trim(wildcard, string(&delim, 1)); // convert wildcard to regular expression - const string &regex = toRegex(wildcard, depot.getDelimiter()); + string regex = toRegex(wildcard, depot.getDelimiter()); + string wildcardLower = regex; + lowercase(wildcardLower); + if (wildcardLower.substr(0, 6) == "^inbox") + regex = "^[iI][nN][bB][oO][xX]" + regex.substr(6); // remove leading or trailing delimiter in reference string ref = command.getMailbox(); trim(ref, string(&delim, 1)); + wildcardLower = ref; + lowercase(wildcardLower); + if (wildcardLower.substr(0, 5) == "inbox" + && (wildcardLower.length() == 5 || wildcardLower[5] == delim)) + ref = "INBOX" + ref.substr(5); // a map from mailbox name to flags map<string, unsigned int> mailboxes; @@ -121,6 +130,9 @@ Operator::ProcessResult ListOperator::process(Depot &depot, // read through all entries in depository. for (Depot::iterator i = depot.begin("."); i != depot.end(); ++i) { const string path = *i; + if (path == "") + continue; + const string mpath = depot.filenameToMailbox(path); Mailbox *m = 0; @@ -192,9 +204,8 @@ Operator::ProcessResult ListOperator::process(Depot &depot, // finally, print all mailbox entries with flags. map<string, unsigned int>::iterator i = mailboxes.begin(); for (; i != mailboxes.end(); ++i) { - if (ref == "" || ((ref.length() <= i->first.length()) - && (i->first.substr(0, ref.length()) == ref))) - if (regexMatch(i->first, regex) == 0) { + if (ref == "" || (ref.length() <= i->first.length() && ref == i->first.substr(0, ref.length()))) + if (regexMatch(i->first.substr(ref.length()), regex) == 0) { com << "* LIST ("; string sep = ""; diff --git a/src/operator-login.cc b/src/operator-login.cc @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 @@ -88,7 +88,7 @@ Operator::ProcessResult LoginOperator::process(Depot &depot, const bool allowplain = (session.globalconfig["Authentication"]["allow plain auth in non ssl"] == "yes"); - if (!session.command.ssl && !allowplain && !getenv("ALLOWPLAIN")) { + if (!session.command.ssl && session["sslmode"] != "yes" && !allowplain && !getenv("ALLOWPLAIN")) { session.setLastError("Plain text password authentication" " is disallowed. Please try enabling SSL" " or TLS in your mail client."); diff --git a/src/operator-logout.cc b/src/operator-logout.cc @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 diff --git a/src/operator-lsub.cc b/src/operator-lsub.cc @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 @@ -95,12 +95,20 @@ Operator::ProcessResult LsubOperator::process(Depot &depot, trim(wildcard, string(&delim, 1)); // convert wildcard to regular expression - const string &regex = toRegex(wildcard, depot.getDelimiter()); + string regex = toRegex(wildcard, depot.getDelimiter()); + string wildcardLower = regex; + lowercase(wildcardLower); + if (wildcardLower.substr(0, 6) == "^inbox") + regex = "^[iI][nN][bB][oO][xX]" + regex.substr(6); // remove leading or trailing delimiter in reference string ref = command.getMailbox(); - while (ref.length() > 1 && ref[0] == depot.getDelimiter()) - ref = ref.substr(1); + trim(ref, string(&delim, 1)); + wildcardLower = ref; + lowercase(wildcardLower); + if (wildcardLower.substr(0, 5) == "inbox" + && (wildcardLower.length() == 5 || wildcardLower[5] == delim)) + ref = "INBOX" + ref.substr(5); // a multimap from mailbox name to flags multimap<string, int> mailboxes; @@ -108,6 +116,9 @@ Operator::ProcessResult LsubOperator::process(Depot &depot, // read through all entries in depository. for (Depot::iterator i = depot.begin("."); i != depot.end(); ++i) { const string path = *i; + if (path == "") + continue; + const string mpath = depot.filenameToMailbox(path); Mailbox *m = 0; @@ -176,47 +187,44 @@ Operator::ProcessResult LsubOperator::process(Depot &depot, // finally, print all mailbox entries with flags. for (vector<string>::const_iterator j = subscribed.begin(); j != subscribed.end(); ++j) { - if (ref != "" && (ref.length() > (*j).length() - || ((*j).substr(0, ref.length()) != ref))) - continue; - - if (regexMatch((*j).substr(ref.length()), regex) != 0) - continue; + if (ref == "" || (ref.length() <= (*j).length() && ref == (*j).substr(0, ref.length()))) + if (regexMatch((*j).substr(ref.length()), regex) == 0) { - int flags = 0; + int flags = 0; - for (i = mailboxes.begin(); i != mailboxes.end(); ++i) { - if (i->first == *j) { - flags = i->second; - break; - } - } - - com << "* LSUB ("; - string sep = ""; - - bool noselect = false; - if (!(flags & DIR_SELECT)) { - com << sep << "\\Noselect"; - sep = " "; - noselect = true; - } + for (i = mailboxes.begin(); i != mailboxes.end(); ++i) { + if (i->first == *j) { + flags = i->second; + break; + } + } + + com << "* LSUB ("; + string sep = ""; + + bool noselect = false; + if (!(flags & DIR_SELECT)) { + com << sep << "\\Noselect"; + sep = " "; + noselect = true; + } - if (!noselect) { - if (flags & DIR_MARKED) - com << sep << "\\Marked"; - else - com << sep << "\\Unmarked"; - sep = " "; - } - - if (flags & DIR_NOINFERIORS) - com << sep << "\\Noinferiors"; + if (!noselect) { + if (flags & DIR_MARKED) + com << sep << "\\Marked"; + else + com << sep << "\\Unmarked"; + sep = " "; + } + + if (flags & DIR_NOINFERIORS) + com << sep << "\\Noinferiors"; - com << ") \"" << depot.getDelimiter() << "\" " - << toImapString(*j) << endl; + com << ") \"" << depot.getDelimiter() << "\" " + << toImapString(*j) << endl; + } } - + return OK; } diff --git a/src/operator-noop-pending.cc b/src/operator-noop-pending.cc @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 @@ -65,7 +65,7 @@ Operator::ProcessResult NoopPendingOperator::process(Depot &depot, Request &command) { Mailbox *mailbox = depot.getSelected(); - if (!pendingUpdates(mailbox, + if (mailbox && !pendingUpdates(mailbox, PendingUpdates::EXPUNGE | PendingUpdates::EXISTS | PendingUpdates::RECENT @@ -73,9 +73,12 @@ Operator::ProcessResult NoopPendingOperator::process(Depot &depot, Session &session = Session::getInstance(); IO &com = IOFactory::getInstance().get(1); IO &logger = IOFactory::getInstance().get(2); - com << "* BYE " << session.getLastError() << endl; logger << "when scanning mailbox: " << session.getLastError() << endl; + com << "* BYE " << session.getLastError() << endl; + com.flushContent(); + session.setState(Session::LOGOUT); + return NOTHING; } return OK; diff --git a/src/operator-noop.cc b/src/operator-noop.cc @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 diff --git a/src/operator-rename.cc b/src/operator-rename.cc @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 diff --git a/src/operator-search.cc b/src/operator-search.cc @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 @@ -541,7 +541,7 @@ Operator::ProcessResult SearchOperator::process(Depot &depot, Mailbox *mailbox = depot.getSelected(); if (command.getCharSet() != "" && command.getCharSet() != "US-ASCII") { - session.setLastError("[BADCHARSET (\"US-ASCII\")]"); + session.setResponseCode("BADCHARSET (\"US-ASCII\")"); return NO; } diff --git a/src/operator-select.cc b/src/operator-select.cc @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 @@ -82,10 +82,15 @@ Operator::ProcessResult SelectOperator::process(Depot &depot, const string &srcmailbox = command.getMailbox(); const string &canonmailbox = toCanonMailbox(srcmailbox); + if (canonmailbox == "") { + session.setLastError("invalid mailbox"); + return NO; + } Mailbox *mailbox = depot.getSelected(); if (mailbox != 0) { mailbox->closeMailbox(); + depot.resetSelected(); mailbox = 0; } @@ -95,8 +100,15 @@ Operator::ProcessResult SelectOperator::process(Depot &depot, return NO; } - if (!mailbox->selectMailbox(canonmailbox, - depot.mailboxToFilename(canonmailbox))) { + string mailboxFilename = depot.mailboxToFilename(canonmailbox); + if (mailboxFilename == "") { + session.setLastError("invalid mailbox"); + return NO; + } + + mailbox->setReadOnly(examine); + + if (!mailbox->selectMailbox(canonmailbox, mailboxFilename)) { logger << "selecting mailbox failed" << endl; session.setLastError(mailbox->getLastError()); return NO; @@ -148,13 +160,10 @@ Operator::ProcessResult SelectOperator::process(Depot &depot, session.setState(Session::SELECTED); depot.setSelected(mailbox); - if (examine) - mailbox->setReadOnly(); - logger.setLogPrefix(session.getUserID() + "@" + session.getIP() + ":" + srcmailbox); - session.setLastError(examine ? "[READ-ONLY]" : "[READ-WRITE]"); + session.setResponseCode(examine ? "READ-ONLY" : "READ-WRITE"); return OK; } diff --git a/src/operator-starttls.cc b/src/operator-starttls.cc @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 diff --git a/src/operator-status.cc b/src/operator-status.cc @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 diff --git a/src/operator-store.cc b/src/operator-store.cc @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 @@ -127,12 +127,15 @@ Operator::ProcessResult StoreOperator::process(Depot &depot, if (command.getMode().find(".SILENT") != string::npos) pendingUpdates(mailbox, PendingUpdates::EXISTS - | PendingUpdates::RECENT, false); + | PendingUpdates::RECENT, false, false, false, + command.getUidMode()); else pendingUpdates(mailbox, PendingUpdates::EXISTS - | PendingUpdates::RECENT - | PendingUpdates::FLAGS, false); + | PendingUpdates::RECENT + | PendingUpdates::EXPUNGE + | PendingUpdates::FLAGS, false, false, false, + command.getUidMode()); return OK; } diff --git a/src/operator-subscribe.cc b/src/operator-subscribe.cc @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 diff --git a/src/operator-unsubscribe.cc b/src/operator-unsubscribe.cc @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 diff --git a/src/operators.h b/src/operators.h @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 diff --git a/src/pendingupdates.cc b/src/pendingupdates.cc @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 @@ -70,9 +70,10 @@ void PendingUpdates::addExpunged(unsigned int uid) } //------------------------------------------------------------------------ -void PendingUpdates::addFlagUpdates(unsigned int uid, unsigned int flags) +void PendingUpdates::addFlagUpdates(unsigned int sqnr, unsigned int uid, unsigned int flags) { - flagupdates[uid] = flags; + flagupdates[sqnr] = flags; + sqnrtouid[sqnr] = uid; } //------------------------------------------------------------------------ @@ -165,8 +166,9 @@ PendingUpdates::flagupdates_const_iterator::flagupdates_const_iterator(void) } //------------------------------------------------------------------------ -PendingUpdates::flagupdates_const_iterator::flagupdates_const_iterator(map<unsigned int, unsigned int>::iterator i) : internal(i) +PendingUpdates::flagupdates_const_iterator::flagupdates_const_iterator(map<unsigned int, unsigned int>::iterator i, map<unsigned int, unsigned int> *sqnrmap) : internal(i) { + sqnrtouid = sqnrmap; } //------------------------------------------------------------------------ @@ -184,13 +186,13 @@ bool PendingUpdates::flagupdates_const_iterator::operator != (flagupdates_const_ //------------------------------------------------------------------------ PendingUpdates::flagupdates_const_iterator PendingUpdates::beginFlagUpdates(void) { - return flagupdates_const_iterator(flagupdates.begin()); + return flagupdates_const_iterator(flagupdates.begin(), &sqnrtouid); } //------------------------------------------------------------------------ PendingUpdates::flagupdates_const_iterator PendingUpdates::endFlagUpdates(void) { - return flagupdates_const_iterator(flagupdates.end()); + return flagupdates_const_iterator(flagupdates.end(), &sqnrtouid); } //------------------------------------------------------------------------ @@ -205,9 +207,15 @@ unsigned int PendingUpdates::flagupdates_const_iterator::second(void) const return internal->second; } +//------------------------------------------------------------------------ +unsigned int PendingUpdates::flagupdates_const_iterator::getUID(void) const +{ + return (*sqnrtouid)[internal->first]; +} + //-------------------------------------------------------------------- bool Binc::pendingUpdates(Mailbox *mailbox, int type, bool rescan, bool showAll, - bool forceScan) + bool forceScan, bool uidfetchflags) { Session &session = Session::getInstance(); IO &com = IOFactory::getInstance().get(1); @@ -252,14 +260,18 @@ bool Binc::pendingUpdates(Mailbox *mailbox, int type, bool rescan, bool showAll, if (flags & Message::F_RECENT) flagv.push_back("\\Recent"); if (flags & Message::F_FLAGGED) flagv.push_back("\\Flagged"); - com << "* " << i.first() << " FETCH (FLAGS ("; + com << "* " << i.first() << " FETCH (FLAGS ("; for (vector<string>::const_iterator k = flagv.begin(); k != flagv.end(); ++k) { if (k != flagv.begin()) com << " "; com << *k; } - com << "))" << endl; + com << ")"; + if (uidfetchflags) + com << " UID " << i.getUID(); + + com << ")" << endl; ++i; } diff --git a/src/pendingupdates.h b/src/pendingupdates.h @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 @@ -78,17 +78,20 @@ namespace Binc { class flagupdates_const_iterator { private: std::map<unsigned int, unsigned int>::iterator internal; + std::map<unsigned int, unsigned int> *sqnrtouid; public: unsigned int first(void) const; unsigned int second(void) const; + unsigned int getUID(void) const; void operator ++ (void); bool operator != (flagupdates_const_iterator) const; //-- flagupdates_const_iterator(void); - flagupdates_const_iterator(std::map<unsigned int, unsigned int>::iterator i); + flagupdates_const_iterator(std::map<unsigned int, unsigned int>::iterator i, + std::map<unsigned int, unsigned int> *); }; //-- @@ -97,7 +100,8 @@ namespace Binc { //-- void addExpunged(unsigned int uid); - void addFlagUpdates(unsigned int uid, unsigned int flags); + void addFlagUpdates(unsigned int sqnr, unsigned int uid, + unsigned int flags); void setExists(unsigned int n); void setRecent(unsigned int n); unsigned int getExists(void) const; @@ -112,6 +116,7 @@ namespace Binc { private: std::vector<unsigned int> expunges; std::map<unsigned int, unsigned int> flagupdates; + std::map<unsigned int, unsigned int> sqnrtouid; unsigned int exists; unsigned int recent; @@ -119,7 +124,7 @@ namespace Binc { bool newrecent; }; - bool Binc::pendingUpdates(Mailbox *, int type, bool rescan, bool showAll = false, bool forceScan = false); + bool pendingUpdates(Mailbox *, int type, bool rescan, bool showAll = false, bool forceScan = false, bool uidfetchflags = false); } #endif diff --git a/src/recursivedescent.cc b/src/recursivedescent.cc @@ -15,7 +15,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 @@ -63,9 +63,6 @@ Operator::ParseResult Binc::expectThisString(const string &s_in) IO &com = IOFactory::getInstance().get(1); Session &session = Session::getInstance(); -#ifdef DEBUG - cout << "expectThisString(\"" << s_in << "\")" << endl << flush; -#endif string tmp; bool match = true; diff --git a/src/recursivedescent.h b/src/recursivedescent.h @@ -15,7 +15,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 diff --git a/src/regmatch.cc b/src/regmatch.cc @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 diff --git a/src/regmatch.h b/src/regmatch.h @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 diff --git a/src/session-initialize-bincimap-up.cc b/src/session-initialize-bincimap-up.cc @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 @@ -189,7 +189,7 @@ bool Session::initialize(int argc, char *argv[]) // Set SSL mode if --ssl is passed if (session.command.ssl) if (sslio->setModeSSL()) { - session.add("sslmode", "true"); + session.add("sslmode", "yes"); } else { session.setLastError("SSL negotiation failed: " + sslio->getLastError()); @@ -220,10 +220,11 @@ bool Session::initialize(int argc, char *argv[]) // umask settings string umsk = session.globalconfig["Mailbox"]["umask"]; - if (umsk == "" || !isdigit(umsk[0])) umsk = "0777"; - unsigned int mode; - sscanf(session.globalconfig["Mailbox"]["umask"].c_str(), "%o", &mode); - umask((mode_t) mode); + if (umsk != "") { + unsigned int mode; + sscanf(session.globalconfig["Mailbox"]["umask"].c_str(), "%o", &mode); + umask((mode_t) mode); + } // If the depot was not initialized properly, return false. return true; diff --git a/src/session-initialize-bincimapd.cc b/src/session-initialize-bincimapd.cc @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 @@ -222,6 +222,8 @@ bool Session::initialize(int argc, char *argv[]) brokerfactory.assign("UNSUBSCRIBE", new UnsubscribeOperator()); string path = session.globalconfig["Mailbox"]["path"]; + if (session.args.getUnqualifiedArgs().size() > 0) + path = session.args.getUnqualifiedArgs()[0]; if (path == "") path = "."; else if (chdir(path.c_str()) != 0) { mkdir(path.c_str(), 0777); @@ -247,6 +249,9 @@ bool Session::initialize(int argc, char *argv[]) // Read timeout settings from global config idletimeout = atoi(session.globalconfig["Session"]["idle timeout"]); + if (idletimeout < 30 * 60) + idletimeout = 30 * 60; + transfertimeout = atoi(session.globalconfig["Session"]["transfer timeout"]); // Set transfer timeout @@ -258,9 +263,12 @@ bool Session::initialize(int argc, char *argv[]) com.setBufferSize(buffersize >= 0 ? buffersize : 0); // umask settings - unsigned int mode; - sscanf(session.globalconfig["Mailbox"]["umask"].c_str(), "%o", &mode); - umask((mode_t) mode); + string umsk = session.globalconfig["Mailbox"]["umask"]; + if (umsk != "") { + unsigned int mode; + sscanf(session.globalconfig["Mailbox"]["umask"].c_str(), "%o", &mode); + umask((mode_t) mode); + } const string details = logindetails; string::size_type det = details.find('+'); diff --git a/src/session.cc b/src/session.cc @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 @@ -180,7 +180,7 @@ bool Session::parseRequestLine(int argc, char * argv[]) args.addOptional("s|ssl", "Toggle enabling of SSL", true); args.addOptional("c|conf", "Sets the path to the config file", false); args.addOptional("a|allow-plain", "Allow authentication when not in SSL", true); - args.addOptional("p|auth-penalty", "Sets the auth penalty", false); + args.addOptional("auth-penalty", "Sets the auth penalty", false); args.addOptional("d|disable-starttls", "Toggles disabling of STARTTLS", false); args.addOptional("L|logtype", "Sets the method used for logging", false); args.addOptional("I|ip-variable", "Sets the env variable that contains the remote IP", false); @@ -236,6 +236,9 @@ void Session::assignCommandLineArgs(void) if (args.hasArg("ip-variable")) globalconfig["Log"]["environment ip variable"] = args["ip-variable"]; + if (args.hasArg("depot")) + globalconfig["Mailbox"]["depot"] = args["depot"]; + if (args.hasArg("mailbox-type")) globalconfig["Mailbox"]["type"] = args["mailbox-type"]; @@ -447,6 +450,12 @@ const std::string &Session::getHostname(void) //---------------------------------------------------------------------- void Session::subscribeTo(const std::string mailbox) { + for (vector<string>::iterator i = subscribed.begin(); + i != subscribed.end(); ++i) { + if (*i == mailbox) + return; + } + subscribed.push_back(mailbox); } @@ -473,14 +482,18 @@ void Session::loadSubscribes(void) // try loading the .bincimap-subscribed file bool ok = false; FILE *fp = fopen(".bincimap-subscribed", "r"); + map<string, bool> addedEntries; if (fp) { int c; string current; while ((c = fgetc(fp)) != EOF) { if (c == '\n') { - trim(current); if (current != "") { - subscribed.push_back(current); + if (addedEntries.find(current) == addedEntries.end()) { + subscribed.push_back(current); + addedEntries[current] = true; + } + current = ""; } } else @@ -543,28 +556,40 @@ bool Session::saveSubscribes(void) const if (fd == -1) { logger << "unable to create temporary file \"" << tpl << "\"" << endl; + delete [] ftemplate; return false; } + map<string, bool> addedEntries; for (vector<string>::const_iterator i = subscribed.begin(); i != subscribed.end(); ++i) { - string w = (*i) + "\n"; - if (write(fd, w.c_str(), w.length()) != (ssize_t) w.length()) { - logger << "failed to write to " << tpl << ": " + if (addedEntries.find(*i) == addedEntries.end()) { + addedEntries[*i] = true; + string w = (*i) + "\n"; + if (write(fd, w.c_str(), w.length()) != (ssize_t) w.length()) { + logger << "failed to write to " << tpl << ": " << strerror(errno) << endl; - break; + break; + } } } - fsync(fd); - close(fd); + if (fsync(fd) != 0 && errno != EINVAL || close(fd) != 0) { + logger << "failed to close " << ftemplate + << ": " << strerror(errno) << endl; + delete [] ftemplate; + return false; + } + if (rename(ftemplate, ".bincimap-subscribed") != 0) { logger << "failed to rename " << ftemplate << " to .bincimap-subscribed: " << strerror(errno) << endl; + delete [] ftemplate; return false; } + delete [] ftemplate; return true; } diff --git a/src/session.h b/src/session.h @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 @@ -40,6 +40,7 @@ #include <string> #include <vector> #include <map> +#include <sys/types.h> #include "argparser.h" namespace Binc { diff --git a/src/status.cc b/src/status.cc @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 diff --git a/src/status.h b/src/status.h @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 diff --git a/src/storage.cc b/src/storage.cc @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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,6 +35,7 @@ #include <config.h> #endif #include "storage.h" +#include <fcntl.h> #include <errno.h> #include <stdio.h> #include <unistd.h> @@ -277,6 +278,12 @@ Storage::~Storage(void) } //------------------------------------------------------------------------ +bool Storage::ok(void) const +{ + return fp != 0; +} + +//------------------------------------------------------------------------ bool Storage::get(string *section, string *key, string *value) { if (mode == WriteOnly) { @@ -572,7 +579,7 @@ bool Storage::commit(void) unlink(fileName.c_str()); } - if (fsync(fd) != 0) { + if (fsync(fd) != 0 && errno != EINVAL) { lastError = "when syncing \"" + fileName + "\":"; lastError += strerror(errno); return false; @@ -595,5 +602,14 @@ bool Storage::commit(void) fd = 0; + string::size_type pos = fileName.rfind('/'); + string dirName = pos ? fileName.substr(0, pos) : "."; + int dfd = open(dirName.c_str(), O_RDONLY); + if (dfd == -1 || fsync(dfd) != 0 && errno != EINVAL || close(dfd) != 0) { + lastError = "when syncing \"" + dirName + "\":"; + lastError += strerror(errno); + return false; + } + return true; } diff --git a/src/storage.h b/src/storage.h @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 @@ -51,6 +51,8 @@ namespace Binc { Storage(const std::string &fileName, Mode mode); ~Storage(void); + bool ok(void) const; + bool eof(void) const; bool get(std::string *section, std::string *key, diff --git a/src/tools.cc b/src/tools.cc @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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 diff --git a/src/tools.h b/src/tools.h @@ -14,7 +14,7 @@ * ChangeLog: * * -------------------------------------------------------------------- - * Copyright 2002-2004 Andreas Aardal Hanssen + * Copyright 2002-2005 Andreas Aardal Hanssen * * 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