summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2003-10-22 22:39:09 +0000
committerLennart Poettering <lennart@poettering.net>2003-10-22 22:39:09 +0000
commit6b459521ce990c3e626190f66ece300daae70dac (patch)
treec4300270e776acc711d16b5ab5e7775edea590f7
create trunk directory and move everything into it
git-svn-id: file:///home/lennart/svn/public/libnewmail/trunk@29 2d4e79f2-dfba-0310-a9f4-9628e67fcdf4
-rw-r--r--LICENSE340
-rw-r--r--Makefile.am41
-rwxr-xr-xbootstrap.sh40
-rw-r--r--configure.ac111
-rw-r--r--doc/Makefile.am52
-rw-r--r--doc/README.html.in213
-rw-r--r--doc/doxygen.conf.in996
-rw-r--r--doc/style.css29
-rw-r--r--examples/Makefile.am19
-rw-r--r--examples/foobar.imap6
-rw-r--r--examples/local.maildir2
-rw-r--r--examples/local.unix2
-rw-r--r--examples/waldo.pop34
-rw-r--r--src/Makefile.am58
-rw-r--r--src/config.c123
-rw-r--r--src/config.h75
-rw-r--r--src/easy.c61
-rw-r--r--src/imap.c370
-rw-r--r--src/maildir.c210
-rw-r--r--src/md5.c381
-rw-r--r--src/md5.h91
-rw-r--r--src/module.h70
-rw-r--r--src/newmail.c339
-rw-r--r--src/newmail.h254
-rw-r--r--src/nm-spoolhack.c196
-rw-r--r--src/nmail-async.c183
-rw-r--r--src/nmail.c93
-rw-r--r--src/pop3.c417
-rw-r--r--src/sockwrap.c224
-rw-r--r--src/sockwrap.h32
-rw-r--r--src/unix.c218
-rw-r--r--src/util.c102
-rw-r--r--src/util.h59
33 files changed, 5411 insertions, 0 deletions
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..d60c31a
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..2441372
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,41 @@
+# $Id$
+#
+# This file is part of libnewmail.
+#
+# libnewmail 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.
+#
+# libnewmail 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 libnewmail; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+
+EXTRA_DIST = bootstrap.sh README LICENSE
+SUBDIRS=src doc examples
+
+MAINTAINERCLEANFILES = README
+noinst_DATA = README
+
+README:
+ rm -f
+ $(MAKE) -C doc README
+ ln -s doc/README
+
+homepage:
+ test -d $$HOME/homepage/lennart
+ mkdir -p $$HOME/homepage/lennart/projects/libnewmail
+ cp *.tar.gz $$HOME/homepage/lennart/projects/libnewmail
+ cp doc/README.html doc/style.css $$HOME/homepage/lennart/projects/libnewmail
+ cp $$HOME/homepage/lennart/projects/libnewmail/README.html $$HOME/homepage/lennart/projects/libnewmail/index.html
+ cp -av doc/reference/ $$HOME/homepage/lennart/projects/libnewmail/
+
+distcleancheck:
+ @:
+
+.PHONY: homepage distcleancheck
diff --git a/bootstrap.sh b/bootstrap.sh
new file mode 100755
index 0000000..0bb3b10
--- /dev/null
+++ b/bootstrap.sh
@@ -0,0 +1,40 @@
+#!/bin/sh
+# $Id: bootstrap.sh 16 2003-07-06 12:15:37Z lennart $
+
+# This file is part of libnewmail.
+#
+# libnewmail 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.
+#
+# libnewmail 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 libnewmail; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+
+if [ "x$1" = "xam" ] ; then
+ set -ex
+ automake -a -c --foreign
+ ./config.status
+else
+ set -ex
+
+ rm -rf autom4te.cache
+ rm -f config.cache
+
+ aclocal
+ libtoolize -c --force
+ autoheader
+ automake -a -c
+ autoconf -Wall
+
+ ./configure --sysconfdir=/etc "$@"
+
+ make clean
+fi
+
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..b145fe2
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,111 @@
+# -*- Autoconf -*-
+# Process this file with autoconf to produce a configure script.
+
+# $Id: configure.ac 41 2003-10-20 21:53:46Z lennart $
+
+# This file is part of libnewmail.
+#
+# libnewmail 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.
+#
+# libnewmail 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 libnewmail; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+
+AC_PREREQ(2.57)
+AC_INIT([libnewmail],[0.3],[mzarjznvy (at) 0pointer (dot) de])
+AC_CONFIG_SRCDIR([src/newmail.c])
+AC_CONFIG_HEADERS([config.h])
+AM_INIT_AUTOMAKE([foreign -Wall])
+
+# Checks for programs.
+AC_PROG_CC
+AC_LIBLTDL_INSTALLABLE
+AC_SUBST(INCLTDL)
+AC_SUBST(LIBLTDL)
+AC_LIBTOOL_DLOPEN
+AC_PROG_LIBTOOL
+
+AC_SUBST(PACKAGE_URL, [http://0pointer.de/lennart/projects/libnewmail/])
+
+# If using GCC specifiy some additional parameters
+if test "x$GCC" = "xyes" ; then
+ CFLAGS="$CFLAGS -pipe -Wall"
+fi
+
+if type -p stow > /dev/null && test -d /usr/local/stow ; then
+ AC_MSG_NOTICE([*** Found /usr/local/stow: installing to /usr/local/stow/${PACKAGE_NAME}-${PACKAGE_VERSION} ***])
+ AC_PREFIX_DEFAULT([/usr/local/stow/${PACKAGE_NAME}-${PACKAGE_VERSION}])
+fi
+
+# Checks for libraries.
+AC_CHECK_LIB([oop], [oop_sys_run])
+AM_PATH_LIBGNUTLS(0.8.6,, AC_MSG_ERROR([[*** gnutls was not found ***]]))
+
+# Checks for header files.
+AC_HEADER_DIRENT
+AC_HEADER_STDC
+AC_HEADER_SYS_WAIT
+AC_CHECK_HEADERS([limits.h netdb.h netinet/in.h stdlib.h string.h sys/socket.h unistd.h])
+
+# Checks for typedefs, structures, and compiler characteristics.
+AC_C_CONST
+AC_TYPE_PID_T
+AC_TYPE_SIZE_T
+AC_HEADER_TIME
+
+# Checks for library functions.
+AC_FUNC_CLOSEDIR_VOID
+AC_FUNC_FORK
+AC_FUNC_MALLOC
+AC_TYPE_SIGNAL
+AC_FUNC_STAT
+AC_CHECK_FUNCS([atexit gethostbyname gethostname memset realpath socket strcasecmp strchr strcspn strerror strpbrk strrchr strspn])
+
+# DOXYGEN documentation generation
+AC_ARG_ENABLE(doxygen,
+ AC_HELP_STRING([--disable-doxygen], [Turn off doxygen usage for documentation generation]),
+[case "${enableval}" in
+ yes) doxygen=yes ;;
+ no) doxygen=no ;;
+ *) AC_MSG_ERROR(bad value ${enableval} for --disable-doxygen) ;;
+esac],[doxygen=yes])
+
+if test x$doxygen = xyes ; then
+ AC_CHECK_PROG(have_doxygen, doxygen, yes, no)
+
+ if test x$have_doxygen = xno ; then
+ AC_MSG_ERROR([*** Sorry, you have to install doxygen or use --disable-doxygen ***])
+ fi
+fi
+
+AM_CONDITIONAL([USE_DOXYGEN], [test "x$doxygen" = xyes])
+
+# LYNX documentation generation
+AC_ARG_ENABLE(lynx,
+ AC_HELP_STRING([--disable-lynx], [Turn off lynx usage for documentation generation]),
+[case "${enableval}" in
+ yes) lynx=yes ;;
+ no) lynx=no ;;
+ *) AC_MSG_ERROR(bad value ${enableval} for --disable-lynx) ;;
+esac],[lynx=yes])
+
+if test x$lynx = xyes ; then
+ AC_CHECK_PROG(have_lynx, lynx, yes, no)
+
+ if test x$have_lynx = xno ; then
+ AC_MSG_ERROR([*** Sorry, you have to install lynx or use --disable-lynx ***])
+ fi
+fi
+
+AM_CONDITIONAL([USE_LYNX], [test "x$lynx" = xyes])
+
+AC_CONFIG_FILES([Makefile src/Makefile doc/Makefile doc/README.html doc/doxygen.conf examples/Makefile])
+AC_OUTPUT
diff --git a/doc/Makefile.am b/doc/Makefile.am
new file mode 100644
index 0000000..79f3826
--- /dev/null
+++ b/doc/Makefile.am
@@ -0,0 +1,52 @@
+# $Id$
+
+# This file is part of libnewmail.
+#
+# libnewmail 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.
+#
+# libnewmail 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 libnewmail; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+
+noinst_DATA = README.html README reference
+EXTRA_DIST = $(noinst_DATA) style.css README.html.in reference
+
+MAINTAINERCLEANFILES = README README.html
+CLEANFILES =
+
+if USE_DOXYGEN
+reference: doxygen.conf
+ doxygen doxygen.conf
+ touch reference
+
+doxygen:
+ touch doxygen.conf
+ $(MAKE) reference
+
+maintainer-clean-local:
+ rm -rf reference
+endif
+
+if USE_LYNX
+README: README.html
+ lynx --dump $^ | sed 's,file://localhost/.*/doc/README.html,README,' | sed 's,file://localhost/.*/doc/reference/,reference/,' > $@
+
+CLEANFILES += README
+endif
+
+tidy: README.html
+ tidy -e < README.html
+
+if USE_DOXYGEN
+.PHONY: doxygen tidy
+else
+.PHONY: tidy
+endif
diff --git a/doc/README.html.in b/doc/README.html.in
new file mode 100644
index 0000000..129a6c9
--- /dev/null
+++ b/doc/README.html.in
@@ -0,0 +1,213 @@
+<?xml version="1.0" encoding="iso-8895-15"?> <!-- -*-html-helper-*- -->
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+
+<!-- $Id$ -->
+
+<head>
+<title>libnewmail @PACKAGE_VERSION@</title>
+<link rel="stylesheet" type="text/css" href="style.css" />
+</head>
+
+<body>
+<h1><a name="top">libnewmail @PACKAGE_VERSION@</a></h1>
+
+<p><i>Copyright 2003 Lennart Poettering &lt;@PACKAGE_BUGREPORT@&gt;</i></p>
+
+<ul class="toc">
+ <li><a href="#license">License</a></li>
+ <li><a href="#news">News</a></li>
+ <li><a href="#overview">Overview</a></li>
+ <li><a href="#status">Status</a></li>
+ <li><a href="#documentation">Documentation</a></li>
+ <li><a href="#requirements">Requirements</a></li>
+ <li><a href="#installation">Installation</a></li>
+ <li><a href="#acks">Acknowledgements</a></li>
+ <li><a href="#download">Download</a></li>
+</ul>
+
+<h2><a name="license">License</a></h2>
+
+<p>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.</p>
+
+<p>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.</p>
+
+<p>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., 675 Mass Ave, Cambridge, MA 02139, USA.</p>
+
+<h2><a name="news">News</a></h2>
+
+<div class="news-date">Wed Oct 22 2003: </div> <p class="news-text"><a
+href="libnewmail-0.3.tar.gz">Version 0.3</a> released; changes
+include: add new tool <tt>nm-spoolhack</tt> for emulating unix mail
+spools, build fixes, added some <tt>const</tt>s to the headers,
+library is not completely API- but ABI-compatible (!) to previous versions.</p>
+
+<div class="news-date">Fri June 5 2003: </div>
+<p class="news-text"><a href="libnewmail-0.2.tar.gz">Version 0.2</a> released; changes include: added missing headers</p>
+
+<div class="news-date">Wed June 4 2003: </div>
+<p class="news-text"><a href="libnewmail-0.1.tar.gz">Version 0.1</a> released</p>
+
+<h2><a name="overview">Overview</a></h2>
+
+<p><tt>libnewmail</tt> is a generic mail checking library for
+Unix/Linux and other operating systems. It supports a simple API, an
+extensible plugin architecture and asynchronous queries among other
+features. It is intented to be a replacement for all that crappy and
+incomplete code of all those mail checking utilities
+available. Applications linking to <tt>libnewmail</tt> may enumerate
+configured mailboxes, query mail box information and status and
+request a mail spool auto-detection for users without any libnewmail
+specific configuration. The library offers a clean API to implement
+your own mail checking plugins. Programs using <tt>libnewmail</tt> may
+query for both the boolean availability and the number of available
+mails. (The former is usually much faster than the latter) The library
+is able to distuingish between new (unread) and old (read, current)
+mails. It includes two CLI tools <tt>nmail</tt> and
+<tt>nmail-async</tt> using the <tt>libnewmail</tt> API for mail
+checking. They are intended to be an example how to use the API with
+either the synchronous or the asynchronous interface.</p>
+
+<h2><a name="status">Status</a></h2>
+
+<p>Currently <tt>libnewmail</tt> includes plugins for the following mailbox
+protocols:</p>
+
+<ul>
+ <li>Unix mail spool (<tt>libunix.so</tt>)</li>
+ <li>qmail Maildir (<tt>libmaildir.so</tt>) </li>
+ <li>POP3 with SSL and APOP (<tt>libpop3.so</tt>)</li>
+ <li>IMAP4rev1 with SSL (<tt>libimap.so</tt>)</li>
+</ul>
+
+<p>There is an API for a graphical configuration interface. However,
+this is currently a NOOP. This feature will be added eventually.</p>
+
+<h2><a name="documentation">Documentation</a></h2>
+
+<p>An extensive API reference is <a
+href="reference/html/index.html">available</a>, for both the
+public and the plugin interface.</p>
+
+<p><tt>libnewmail</tt> searches for mailbox configuration in
+<tt>/etc/newmail/</tt> and <tt>~/.newmail/</tt>. For each configured
+mail spool a distinct file exists in one of these directories. The
+filename consists of a descriptive text and a plugin specification
+seperated by a dot. e.g. <tt>my_funny_mailserver.pop3</tt> is a
+configuration file for a mail server accessed via the POP3
+plugin. Depending on the used
+plugin, the configuration file may contain different configuration
+directives. Each directive must be on a seperate line, leading
+white spaces are ignored, as are lines beginning with # or empty
+lines. Unknown directives are silently ignored. Some configuration
+values (especially paths) are subject to a "specials"
+expansion. The following specials are known:
+</p>
+
+<ul>
+ <li><tt>%h</tt> - home directory of user</li>
+ <li><tt>%H</tt> - host name</li>
+ <li><tt>%u</tt> - user name</li>
+</ul>
+
+<h3>libunix.so</h3>
+
+<p>This plugin for accessing unix mail spools knows the following directives:</p>
+
+<ul>
+ <li><tt>Path</tt>: path to the mail spool; subject to specials expansions, defaults to <tt>/var/mail/%u</tt></li>
+</ul>
+
+<h3>libmaildir.so</h3>
+
+<p>This plugin for accessing qmail Maildirs knows the following directives:</p>
+
+<ul>
+ <li><tt>Path</tt>: path to the maildir; subject to specials expansions, defaults to <tt>%h/Maildir</tt></li>
+</ul>
+
+<h3>libpop3.so</h3>
+
+<p>This plugin for accessing POP3 mail spools knows the following directives:</p>
+
+<ul>
+ <li><tt>Hostname</tt>: Host name of the POP3 server, defaults to <tt>localhost</tt></li>
+ <li><tt>Username</tt>: User name on the POP3 server, defaults to local user name</li>
+ <li><tt>Password</tt>: Password on the POP3 server</li>
+ <li><tt>UseSSL</tt>: Enable SSL? (<tt>Yes</tt> or <tt>No</tt>, defaults to <tt>No</tt>)</li>
+ <li><tt>Port</tt>: Which port? (Defaults to 110 whith UseSSL off and 995 otherwise</li>
+ <li><tt>Debug</tt>: Request that every POP3 command is written to STDOUT on query? (<tt>Yes</tt> or <tt>No</tt>, defaults <tt>No</tt>)</li>
+</ul>
+
+<h3>libimap.so</h3>
+
+<p>This plugin for accessing IMAP4rev1 mail spools knows the following directives:</p>
+
+<ul>
+ <li><tt>Hostname</tt>: Host name of the IMAP server, defaults to <tt>localhost</tt></li>
+ <li><tt>Username</tt>: User name on the IMAP server, defaults to local user name</li>
+ <li><tt>Password</tt>: Password on the IMAP server</li>
+ <li><tt>UseSSL</tt>: Enable SSL? (<tt>Yes</tt> or <tt>No</tt>, defaults to <tt>No</tt>)</li>
+ <li><tt>Port</tt>: Which port? (Defaults to 143 whith UseSSL off and 993 otherwise</li>
+ <li><tt>Debug</tt>: Request that every IMAP command is written to STDOUT on query? (<tt>Yes</tt> or <tt>No</tt>, defaults <tt>No</tt>)</li>
+ <li><tt>Folder</tt>: Which folder shall be queried? Defaults to "INBOX".</li>
+</ul>
+
+<p>The default mail spool my be defined by creating a symbolic
+link named <tt>.default</tt> in <tt>~/.newmail</tt>, which points
+to the select configuration file.</p>
+
+<p>See the <tt>examples</tt> directory in the distribution for
+some examples of configuration files.</p>
+
+<h2><a name="requirements">Requirements</a></h2>
+
+<p><tt>libnewmail</tt> was developed and tested on Debian
+GNU/Linux "testing" from May 2003, it should work on most other
+Linux distributions and
+Unix versions since it uses GNU Autoconf and GNU libtool for source
+code configuration and shared library management.</p>
+
+<p>The library uses <a href="http://www.liboop.org/">liboop</a> for
+main loop abstraction for asynchronous queries and may thus be
+integrated with GTK+ and other toolkits supported by liboop.</p>
+
+<p><tt>libnewmail</tt> uses <a
+href="http://www.gnu.org/software/gnutls/gnutls.html">GnuTLS</a> for
+SSL encryption of POP3 and IMAP4 remote mailbox access.</p>
+
+<h2><a name="installation">Installation</a></h2>
+
+<p>As this package is made with the GNU autotools you should run
+<tt>./configure</tt> inside the distribution directory for configuring
+the source tree. After that you should run <tt>make</tt> for
+compilation and <tt>make install</tt> (as root) for installation of
+<tt>libnewmail</tt>.</p>
+
+<h2><a name="acks">Acknowledgements</a></h2>
+
+<p>This software includes an implementation of the MD5 algorithm by
+L. Peter Deutsch. Thanks to him for this.</p>
+
+<h2><a name="download">Download</a></h2>
+
+<p>The newest release is always available from <a href="@PACKAGE_URL@">@PACKAGE_URL@</a></p>
+
+<p>The current release is <a href="@PACKAGE_URL@libnewmail-@PACKAGE_VERSION@.tar.gz">@PACKAGE_VERSION@</a></p>
+
+<p>Get <tt>libnewmail</tt>'s development sources from the <a href="http://subversion.tigris.org/">Subversion</a> <a href="https://seth.intheinter.net:8081/svn/libnewmail/">repository</a>.</p>
+
+<hr/>
+<address>Lennart Poettering &lt;@PACKAGE_BUGREPORT@&gt;, October 2003</address>
+<div><i>$Id: README.html.in 43 2003-10-20 22:13:53Z lennart $</i></div>
+
+</body>
+</html>
diff --git a/doc/doxygen.conf.in b/doc/doxygen.conf.in
new file mode 100644
index 0000000..7bdf492
--- /dev/null
+++ b/doc/doxygen.conf.in
@@ -0,0 +1,996 @@
+# $Id: doxygen.conf.in 9 2003-07-05 15:14:33Z lennart $
+
+# Doxyfile 1.2.18
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+# TAG = value [value, ...]
+# For lists items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# General configuration options
+#---------------------------------------------------------------------------
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME = "@PACKAGE_NAME@"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER = "@PACKAGE_VERSION@"
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = reference
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch,
+# Finnish, French, German, Greek, Hungarian, Italian, Japanese, Japanese-en
+# (Japanese with english messages), Korean, Norwegian, Polish, Portuguese,
+# Romanian, Russian, Serbian, Slovak, Slovene, Spanish, Swedish and Ukrainian.
+
+OUTPUT_LANGUAGE = English
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS = YES
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these class will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES = YES
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF = YES
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all inherited
+# members of a class in the documentation of that class as if those members were
+# ordinary class members. Constructors, destructors and assignment operators of
+# the base classes will not be shown.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. It is allowed to use relative paths in the argument list.
+
+STRIP_FROM_PATH =
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower case letters. If set to YES upper case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# users are adviced to set this option to NO.
+
+CASE_SENSE_NAMES = YES
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful is your file systems
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS = YES
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like the Qt-style comments (thus requiring an
+# explict @brief command for a brief description.
+
+JAVADOC_AUTOBRIEF = YES
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the DETAILS_AT_TOP tag is set to YES then Doxygen
+# will output the detailed description near the top, like JavaDoc.
+# If set to NO, the detailed description appears after the member
+# documentation.
+
+DETAILS_AT_TOP = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# reimplements.
+
+INHERIT_DOCS = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE = 4
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST = NO
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST = NO
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST = NO
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES =
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or define consist of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and defines in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C.
+# For instance some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources
+# only. Doxygen will then generate output that is more tailored for Java.
+# For instance namespaces will be presented as packages, qualified scopes
+# will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text.
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT = ../src/
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx *.hpp
+# *.h++ *.idl *.odl
+
+FILE_PATTERNS = *.h
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or directories
+# that are symbolic links (a Unix filesystem feature) are excluded from the input.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+
+EXCLUDE_PATTERNS = md5.[ch] md5.[ch] imap.[ch] maildir.[ch] pop3.[ch] unix.[ch] sockwrap.[ch] nmail-async.[ch] nmail.[ch]
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH = "../src/"
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS = nmail.c nmail-async.c nm-spoolhack.c easy.c
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output.
+
+INPUT_FILTER =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+
+SOURCE_BROWSER = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES = NO
+
+# If the REFERENCED_BY_RELATION tag is set to YES (the default)
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES (the default)
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX = NO
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet
+
+HTML_STYLESHEET =
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS = YES
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compressed HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output dir.
+
+CHM_FILE =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non empty doxygen will try to run
+# the html help compiler on the generated index.hhp.
+
+HHC_LOCATION =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the Html help documentation and to the tree view.
+
+TOC_EXPAND = NO
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX = NO
+
+# This tag can be used to set the number of enum values (range [1..20])
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be
+# generated containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript and frames is required (for instance Mozilla, Netscape 4.0+,
+# or Internet explorer 4.0+). Note that for large projects the tree generation
+# can take a very long time. In such cases it is better to disable this feature.
+# Windows users are probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW = YES
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH = 250
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, a4wide, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS = NO
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX = NO
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimised for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assigments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN = YES
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_XML = NO
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD =
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_PREDEFINED tags.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed.
+
+PREDEFINED =
+
+# If the MACRO_EXPANSION and EXPAND_PREDEF_ONLY tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all function-like macros that are alone
+# on a line, have an all uppercase name, and do not end with a semicolon. Such
+# function macros are typically used for boiler-plate code, and will confuse the
+# parser if not removed.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration::addtions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tagfiles.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in Html, RTF and LaTeX) for classes with base or
+# super classes. Setting the tag to NO turns the diagrams off. Note that this
+# option is superceded by the HAVE_DOT option below. This is only a fallback. It is
+# recommended to install and use dot, since it yield more powerful graphs.
+
+CLASS_DIAGRAMS = YES
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT = NO
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH = YES
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found on the path.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS =
+
+# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than
+# this value, doxygen will try to truncate the graph, so that it fits within
+# the specified constraint. Beware that most browsers cannot cope with very
+# large images.
+
+MAX_DOT_GRAPH_WIDTH = 1024
+
+# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than
+# this value, doxygen will try to truncate the graph, so that it fits within
+# the specified constraint. Beware that most browsers cannot cope with very
+# large images.
+
+MAX_DOT_GRAPH_HEIGHT = 1024
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermedate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP = YES
+
+#---------------------------------------------------------------------------
+# Configuration::addtions related to the search engine
+#---------------------------------------------------------------------------
+
+# The SEARCHENGINE tag specifies whether or not a search engine should be
+# used. If set to NO the values of all tags below this one will be ignored.
+
+SEARCHENGINE = NO
+
+# The CGI_NAME tag should be the name of the CGI script that
+# starts the search engine (doxysearch) with the correct parameters.
+# A script with this name will be generated by doxygen.
+
+CGI_NAME = search.cgi
+
+# The CGI_URL tag should be the absolute URL to the directory where the
+# cgi binaries are located. See the documentation of your http daemon for
+# details.
+
+CGI_URL =
+
+# The DOC_URL tag should be the absolute URL to the directory where the
+# documentation is located. If left blank the absolute path to the
+# documentation, with file:// prepended to it, will be used.
+
+DOC_URL =
+
+# The DOC_ABSPATH tag should be the absolute path to the directory where the
+# documentation is located. If left blank the directory on the local machine
+# will be used.
+
+DOC_ABSPATH =
+
+# The BIN_ABSPATH tag must point to the directory where the doxysearch binary
+# is installed.
+
+BIN_ABSPATH = /usr/local/bin/
+
+# The EXT_DOC_PATHS tag can be used to specify one or more paths to
+# documentation generated for other projects. This allows doxysearch to search
+# the documentation for these projects as well.
+
+EXT_DOC_PATHS =
diff --git a/doc/style.css b/doc/style.css
new file mode 100644
index 0000000..a19b017
--- /dev/null
+++ b/doc/style.css
@@ -0,0 +1,29 @@
+/* $Id: style.css 41 2003-10-20 21:53:46Z lennart $ */
+
+/***
+ * This file is part of libnewmail.
+ *
+ * libnewmail 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.
+ *
+ * libnewmail 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 libnewmail; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ ***/
+
+body { color: black; background-color: white; margin: 0.5cm; }
+a:link, a:visited { color: #900000; }
+p { margin-left: 0.5cm; margin-right: 0.5cm; }
+div.news-date { margin-left: 0.5cm; font-size: 80%; color: #4f0000; }
+p.news-text { margin-left: 1cm; }
+ul { margin-left: 0.5cm; }
+h1 { color: #00009F; }
+h2 { color: #00009F; }
+h3 { color: #00004F; margin-left: 0.5cm; }
diff --git a/examples/Makefile.am b/examples/Makefile.am
new file mode 100644
index 0000000..1efae10
--- /dev/null
+++ b/examples/Makefile.am
@@ -0,0 +1,19 @@
+# $Id: Makefile.am 26 2003-07-19 09:44:50Z lennart $
+#
+# This file is part of libnewmail.
+#
+# libnewmail 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.
+#
+# libnewmail 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 libnewmail; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+
+EXTRA_DIST = foobar.imap local.maildir local.unix waldo.pop3
diff --git a/examples/foobar.imap b/examples/foobar.imap
new file mode 100644
index 0000000..088ad42
--- /dev/null
+++ b/examples/foobar.imap
@@ -0,0 +1,6 @@
+Hostname imap.foobar.bogus
+Username quux
+Password gurke
+UseSSL Yes
+Debug 0
+#Folder megaman
diff --git a/examples/local.maildir b/examples/local.maildir
new file mode 100644
index 0000000..f0fc5ab
--- /dev/null
+++ b/examples/local.maildir
@@ -0,0 +1,2 @@
+Path %h/Maildir
+PollIntervall 20
diff --git a/examples/local.unix b/examples/local.unix
new file mode 100644
index 0000000..e5588ff
--- /dev/null
+++ b/examples/local.unix
@@ -0,0 +1,2 @@
+Path /var/mail/%u
+PollIntervall 10
diff --git a/examples/waldo.pop3 b/examples/waldo.pop3
new file mode 100644
index 0000000..897a600
--- /dev/null
+++ b/examples/waldo.pop3
@@ -0,0 +1,4 @@
+Hostname pop.waldo.bogus
+Username kunibert
+Password ottokar
+#Debug 1
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..bf98692
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,58 @@
+# $Id$
+#
+# This file is part of libnewmail.
+#
+# libnewmail 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.
+#
+# libnewmail 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 libnewmail; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+
+lib_LTLIBRARIES = libnewmail.la
+pkglib_LTLIBRARIES = libunix.la libmaildir.la libpop3.la libimap.la
+pkginclude_HEADERS=newmail.h module.h config.h util.h
+
+bin_PROGRAMS = nmail nmail-async nm-spoolhack
+noinst_PROGRAMS = easy
+
+libnewmail_la_SOURCES = config.c util.c newmail.c newmail.h util.h config.h module.h
+libnewmail_la_LDFLAGS = -version-info 0:0:0 -export-dynamic
+libnewmail_la_INCLUDES = $(INCLTDL)
+libnewmail_la_CFLAGS = -DNM_LIBRARY_PATH="\"$(pkglibdir)\""
+libnewmail_la_LIBADD = $(LIBLTDL)
+
+libunix_la_SOURCES = unix.c newmail.h config.h util.h module.h
+libunix_la_LDFLAGS = -module
+
+libmaildir_la_SOURCES = maildir.c newmail.h config.h util.h module.h
+libmaildir_la_LDFLAGS = -module
+
+libpop3_la_SOURCES = pop3.c sockwrap.c md5.c md5.h sockwrap.h newmail.h config.h util.h module.h
+libpop3_la_LDFLAGS = -module
+libpop3_la_CFLAGS = $(LIBGNUTLS_CFLAGS)
+libpop3_la_LIBADD = $(LIBGNUTLS_LIBS)
+
+libimap_la_SOURCES = imap.c sockwrap.c md5.c md5.h sockwrap.h newmail.h config.h util.h module.h
+libimap_la_LDFLAGS = -module
+libimap_la_CFLAGS = $(LIBGNUTLS_CFLAGS)
+libimap_la_LIBADD = $(LIBGNUTLS_LIBS)
+
+nmail_SOURCES = nmail.c newmail.h
+nmail_LDADD = libnewmail.la
+
+nmail_async_SOURCES = nmail-async.c newmail.h
+nmail_async_LDADD = libnewmail.la
+
+nm_spoolhack_SOURCES = nm-spoolhack.c newmail.h
+nm_spoolhack_LDADD = libnewmail.la
+
+easy_SOURCES = easy.c newmail.h
+easy_LDADD = libnewmail.la
diff --git a/src/config.c b/src/config.c
new file mode 100644
index 0000000..2c45de8
--- /dev/null
+++ b/src/config.c
@@ -0,0 +1,123 @@
+/* $Id$ */
+
+/***
+ This file is part of libnewmail
+
+ libnewmail 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.
+
+ libnewmail 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 libnewmail; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ USA
+***/
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "config.h"
+#include "newmail.h"
+#include "util.h"
+
+config_t* nm_config_open(const char *fn) {
+ config_t* c = NULL;
+ FILE* f = NULL;
+
+ if (!(c = nm_malloc(sizeof(config_t)))) {
+ nm_error(NM_ERROR_MEMORY, NULL);
+ goto fail;
+ }
+
+ if (!fn) {
+ c->file = NULL;
+ return c;
+ }
+
+ if (!(f = fopen(fn, "r"))) {
+ nm_error(NM_ERROR_NOFILE|NM_ERROR_SYSTEM, "Configuration file not found\n");
+ goto fail;
+ }
+
+ c->file = f;
+ return c;
+
+fail:
+ if (c)
+ nm_free(c);
+
+ if (f)
+ fclose(f);
+
+ return NULL;
+}
+
+void nm_config_close(config_t *c) {
+ if (c) {
+ if (c->file)
+ fclose(c->file);
+
+ nm_free(c);
+ }
+}
+
+
+const char *nm_config_get(config_t *c, const char*entry, const char*def) {
+ if (!c || !entry || !c->file)
+ return def;
+
+ rewind(c->file);
+
+ while (!feof(c->file)) {
+ static char ln[128];
+ char *n, *t;
+
+ if (!fgets(ln, sizeof(ln), c->file))
+ return def;
+
+ nm_chomp(ln);
+
+ n = &ln[strspn(ln, " \t")];
+
+ if (*n == '#' || *n == 0)
+ continue;
+
+ if (!(t = strpbrk(n, " \t")))
+ t = strchr(n, 0);
+
+ if (strncmp(n, entry, t-n) == 0) {
+ t += strspn(t, " \t");
+
+ return t;
+ }
+ }
+
+ return def;
+}
+
+
+int nm_config_get_int(config_t *c, const char*entry, int def) {
+ const char *r;
+
+ if ((r = nm_config_get(c, entry, NULL)))
+ return atoi(r);
+
+ return def;
+}
+
+
+int nm_config_get_bool(config_t *c, const char*entry, int def) {
+ const char *r;
+
+ if ((r = nm_config_get(c, entry, NULL)))
+ return tolower(*r) == 'y' || atoi(r) || *r == '+' || !strcasecmp(r, "on");
+
+ return def;
+}
diff --git a/src/config.h b/src/config.h
new file mode 100644
index 0000000..0a93918
--- /dev/null
+++ b/src/config.h
@@ -0,0 +1,75 @@
+#ifndef fooconfighfoo
+#define fooconfighfoo
+
+/* $Id$ */
+
+/***
+ This file is part of libnewmail
+
+ libnewmail 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.
+
+ libnewmail 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 libnewmail; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ USA
+***/
+
+/** \file
+ *
+ * Some routines to ease the configuration file access. This is only
+ * used by the plugins, not by applications linking to libnewmail.
+ */
+
+
+#include <stdio.h>
+
+/** A configuration file handle
+ */
+typedef struct {
+ FILE *file; /**< A FILE pointer to the configuraiton file */
+} config_t;
+
+/** Open the specified configuration file
+ * @param fn Path to configuration file
+ * @return A handle to the configuration file object
+ */
+config_t* nm_config_open(const char *fn);
+
+/** Close a configuration file oject
+ * @param c The configuration file object to be freed
+ */
+void nm_config_close(config_t *c);
+
+/** Request a specific configuration key from the configuration file.
+ * @param c The configuration file object
+ * @param entry The configuration file key
+ * @param def The default value, when the key is not found. May be NULL
+ * @return A pointer to a statically allocated string containing the value read or def.
+ */
+const char *nm_config_get(config_t *c, const char*entry, const char* def);
+
+/** Same as nm_config_get() but requests an integer
+ * @param c The configuration file object
+ * @param entry The configuration file key
+ * @param def The default value, when the key is not found.
+ * @return The value read or def
+ */
+int nm_config_get_int(config_t *c, const char*entry, int def);
+
+/** Same as nm_config_get() but requests a boolean
+ * @param c The configuration file object
+ * @param entry The configuration file key
+ * @param def The default value, when the key is not found.
+ * @return The value read or def
+ */
+int nm_config_get_bool(config_t *c, const char*entry, int def);
+
+#endif
diff --git a/src/easy.c b/src/easy.c
new file mode 100644
index 0000000..f1dae36
--- /dev/null
+++ b/src/easy.c
@@ -0,0 +1,61 @@
+/* $Id: nmail.c 23 2003-06-04 17:16:43Z lennart $ */
+
+/***
+ This file is part of libnewmail
+
+ libnewmail 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.
+
+ libnewmail 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 libnewmail; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ USA
+***/
+
+#include <stdio.h>
+#include <errno.h>
+
+#include <newmail.h>
+
+int main(int argc, char *argv[]) {
+ struct nm_spool* s = NULL;
+ struct nm_status st;
+ int r = 1;
+
+ /* Open mail spool */
+ if (!(s = nm_open(argc > 1 ? argv[1] : NULL))) {
+ fprintf(stderr, "nm_open(): %s\n", nm_strerror(nm_errno, errno, nm_explanation));
+ goto finish;
+ }
+
+ /* Query for status */
+ if (nm_query(s, NM_QUERY_CUR|NM_QUERY_NEW, &st) < 0) {
+ fprintf(stderr, "nm_check(): %s\n", nm_strerror(nm_errno, errno, nm_explanation));
+ goto finish;
+ }
+
+ /* Print results */
+ if (st.new > 0)
+ printf("You have new mail\n");
+ else if (st.cur > 0)
+ printf("You have mail\n");
+ else
+ printf("No mail\n");
+
+ r = 0;
+
+finish:
+
+ /* Close mail spool */
+ if (s)
+ nm_close(s);
+
+ return r;
+}
diff --git a/src/imap.c b/src/imap.c
new file mode 100644
index 0000000..ac492c2
--- /dev/null
+++ b/src/imap.c
@@ -0,0 +1,370 @@
+/* $Id$ */
+
+/***
+ This file is part of libnewmail
+
+ libnewmail 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.
+
+ libnewmail 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 libnewmail; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ USA
+***/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <signal.h>
+#include <wait.h>
+
+#include "module.h"
+#include "newmail.h"
+#include "util.h"
+#include "md5.h"
+#include "sockwrap.h"
+
+struct forkresp {
+ struct nm_status status;
+ int ret;
+ int nm_errno;
+ int system_errno;
+ char nm_explanation[128];
+};
+
+struct data {
+ char *username;
+ char *password;
+
+ char *hostname;
+ int port;
+ int tls;
+
+ char *folder;
+
+ oop_source *oop;
+ int fdpipe;
+ struct forkresp forkresp;
+ int nread;
+
+ int debug;
+
+ nm_query_cb_t cb;
+ void *user;
+
+ pid_t child;
+};
+
+static int _imap_process(struct nm_spool *s, enum nm_query query, struct nm_status *status) {
+ struct sockwrap *sw = NULL;
+ struct data *data = (struct data*) s->data;
+ enum { HELLO, LOGIN, STATUS, LOGOUT } state = HELLO;
+ char *tag = "* ";
+ int r = -1;
+ static char star[256] = "";
+
+ status->cur = status->new = -1;
+
+ if (!(sw = sockwrap(data->hostname, data->port, data->tls)))
+ goto finish;
+
+ for (;;) {
+ int finished = 0;
+
+ static char response[256];
+ static char request[256];
+ char *p;
+
+ if (sockwrap_readln(sw, response, sizeof(response)) < 0) {
+ nm_error(NM_ERROR_SERVFAIL, NULL);
+ goto finish;
+ }
+
+ nm_chomp(response);
+
+ if (data->debug)
+ fprintf(stderr, "RECV: %s\n", response);
+
+ if (strncmp(response, tag, strlen(tag))) {
+
+ if (!strncmp(response, "* ", 2))
+ strcpy(star, response);
+
+ continue;
+ }
+
+ p = response + strlen(tag);
+
+ if (strncmp(p, "OK ", 3)) {
+ char *e;
+ if ((e = strchr(p, ' ')))
+ e++;
+ else
+ e = p;
+
+ nm_error(NM_ERROR_SERVFAIL|NM_ERROR_EXPLANATION, e);
+ goto finish;
+ }
+
+ switch (state) {
+ case HELLO:
+ state = LOGIN;
+ break;
+
+ case LOGIN:
+ state = STATUS;
+ star[0] = 0;
+ break;
+
+ case STATUS:
+
+ if (sscanf(star, "%*s %*s %*s %*s %d %*s %d", &status->cur, &status->new) != 2) {
+ status->cur = status->new = -1;
+ nm_error(NM_ERROR_SERVFAIL, NULL);
+ goto finish;
+ }
+
+ state = LOGOUT;
+ break;
+
+ case LOGOUT:
+ finished = 1;
+ break;
+ }
+
+ if (finished)
+ break;
+
+
+ switch (state) {
+ case LOGIN:
+ snprintf(request, sizeof(request), "%sLOGIN \"%s\" \"%s\"\n", tag = "A ", data->username, data->password);
+ break;
+
+ case STATUS:
+ snprintf(request, sizeof(request), "%sSTATUS \"%s\" (MESSAGES UNSEEN)\n", tag = "B ", data->folder);
+ break;
+
+ case LOGOUT:
+ snprintf(request, sizeof(request), "%sLOGOUT\n", tag = "C ");
+ break;
+
+ case HELLO: // Completely useless, however, this will remove GCC's warning
+ break;
+ }
+
+ if (data->debug)
+ fprintf(stderr, "SEND: %s", request);
+
+ if (sockwrap_writeln(sw, request) < 0) {
+ nm_error(NM_ERROR_SERVFAIL, NULL);
+ goto finish;
+ }
+ }
+
+
+ r = 0;
+
+finish:
+
+ if (sw)
+ sockwrap_close(sw);
+
+ return r;
+}
+
+static void* _callback(oop_source *source, int fd, oop_event event, void *user) {
+ struct data *data = (struct data*) ((struct nm_spool*) user)->data;
+ ssize_t r;
+
+ if ((r = read(data->fdpipe, ((char*) &data->forkresp) + data->nread, sizeof(struct forkresp)-data->nread)) < 0) {
+ nm_error(NM_ERROR_INTERNAL|NM_ERROR_SYSTEM, NULL);
+ goto fail;
+ }
+
+ data->nread += r;
+
+ if (data->nread >= sizeof(struct forkresp)) {
+
+ if (data->forkresp.nm_errno == NM_ERROR_SUCCESS) {
+ data->cb((struct nm_spool*) user, &data->forkresp.status, data->user);
+ goto finish;
+ } else {
+ nm_error(nm_errno, data->forkresp.nm_explanation[0] ? data->forkresp.nm_explanation : NULL);
+ errno = data->forkresp.system_errno;
+ goto fail;
+ }
+ }
+
+ return OOP_CONTINUE;
+
+fail:
+ data->cb((struct nm_spool*) user, NULL, data->user);
+
+finish:
+
+ if (data->oop)
+ data->oop->cancel_fd(data->oop, data->fdpipe, OOP_READ);
+
+ close(data->fdpipe);
+ data->fdpipe = -1;
+
+ waitpid(data->child, 0, 0);
+ data->child = (pid_t) -1;
+
+ return OOP_CONTINUE;
+}
+
+static int _check_submit(struct nm_spool *s, enum nm_query query, oop_source* oop, nm_query_cb_t cb, void *user) {
+ struct data *data = (struct data*) s->data;
+ int pf[2] = { -1, -1};
+ pid_t pid;
+
+ if (data->fdpipe >= 0) {
+ nm_error(NM_ERROR_ALREADY, NULL);
+ goto fail;
+ }
+
+ if (pipe(pf) < 0) {
+ nm_error(NM_ERROR_FORK|NM_ERROR_SYSTEM, NULL);
+ goto fail;
+ }
+
+ if ((pid = fork()) < 0) {
+ nm_error(NM_ERROR_FORK|NM_ERROR_SYSTEM, NULL);
+ goto fail;
+ } else if (!pid) {
+ struct forkresp forkresp = { { -1, -1 }, -1, 0, 0, "" };
+ FILE *f;
+
+ signal(SIGPIPE, SIG_IGN);
+ close(pf[0]);
+
+ nm_error(NM_ERROR_SUCCESS, NULL);
+
+ if ((forkresp.ret = _imap_process(s, query, &forkresp.status)) < 0) {
+ forkresp.system_errno = errno;
+ forkresp.nm_errno = nm_errno;
+ if (nm_explanation[0])
+ snprintf(forkresp.nm_explanation, sizeof(forkresp.nm_explanation), "%s", nm_explanation);
+ else
+ forkresp.nm_explanation[0] = 0;
+ }
+
+ f = fdopen(pf[1], "w");
+ fwrite(&forkresp, sizeof(forkresp), 1, f);
+ fclose(f);
+ close(pf[1]);
+
+ exit(0);
+ } else {
+ close(pf[1]);
+ data->fdpipe = pf[0];
+ data->nread = 0;
+
+ data->cb = cb;
+ data->user = user;
+ data->oop = oop;
+
+ data->child = pid;
+
+ oop->on_fd(oop, data->fdpipe, OOP_READ, _callback, s);
+ return 0;
+ }
+
+fail:
+
+ if (pf[0] >= 0)
+ close(pf[0]);
+ if (pf[1] >= 1)
+ close(pf[1]);
+
+ return -1;
+}
+
+static int _check(struct nm_spool *s, enum nm_query query, struct nm_status *status) {
+ struct data *data = (struct data*) s->data;
+
+ if (!s || !status) {
+ nm_error(NM_ERROR_INVPAR, NULL);
+ return -1;
+ }
+
+ if (data->fdpipe >= 0) {
+ nm_error(NM_ERROR_ALREADY, NULL);
+ return -1;
+ }
+
+ return _imap_process(s, query, status);
+}
+
+static int _configure(struct nm_spool *s) {
+ return -1;
+}
+
+static int _info(struct nm_spool *s, struct nm_info *i) {
+ struct data *data = (struct data*) s->data;
+ if (data->port == 143)
+ snprintf(i->text, sizeof(i->text), "IMAP mailbox %s@%s/%s", data->username, data->hostname, data->folder);
+ else
+ snprintf(i->text, sizeof(i->text), "IMAP mailbox %s@%s:%i/%s", data->username, data->hostname, data->port, data->folder);
+
+ i->flags = NM_FLAG_ASYNCHRONOUS;
+
+ return 0;
+}
+
+static void _done(struct nm_spool *s) {
+ struct data *data = (struct data*) s->data;
+
+ if (data) {
+ if (data->fdpipe >= 0) {
+ if (data->oop)
+ data->oop->cancel_fd(data->oop, data->fdpipe, OOP_READ);
+ close(data->fdpipe);
+ }
+
+ nm_free(data->hostname);
+ nm_free(data->username);
+ nm_free(data->password);
+ nm_free(data);
+ s->data = NULL;
+ }
+}
+
+int nm_init(struct nm_spool *s) {
+ struct data *data;
+ s->query = _check;
+ s->query_submit = _check_submit;
+ s->configure = _configure;
+ s->info = _info;
+ s->done = _done;
+
+ data = nm_malloc(sizeof(struct data));
+ memset(data, 0, sizeof(struct data));
+
+ data->hostname = nm_strdup(nm_specials(nm_config_get(s->config, "Hostname", "localhost")));
+ data->username = nm_strdup(nm_specials(nm_config_get(s->config, "Username", "%u")));
+ data->password = nm_strdup(nm_config_get(s->config, "Password", "secret"));
+ data->folder = nm_strdup(nm_specials(nm_config_get(s->config, "Folder", "INBOX")));
+
+ data->tls = nm_config_get_bool(s->config, "UseSSL", 0) || nm_config_get_bool(s->config, "UseTLS", 0);
+ data->port = nm_config_get_int(s->config, "Port", data->tls ? 993 : 143);
+ data->debug = nm_config_get_bool(s->config, "Debug", 0);
+ data->fdpipe = -1;
+ data->child = (pid_t) -1;
+ s->data = (void*) data;
+
+ return 0;
+}
+
+
diff --git a/src/maildir.c b/src/maildir.c
new file mode 100644
index 0000000..8d379cc
--- /dev/null
+++ b/src/maildir.c
@@ -0,0 +1,210 @@
+/* $Id$ */
+
+/***
+ This file is part of libnewmail
+
+ libnewmail 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.
+
+ libnewmail 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 libnewmail; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ USA
+***/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <dirent.h>
+
+#include "module.h"
+#include "newmail.h"
+#include "util.h"
+
+struct data {
+ char *path;
+ enum nm_query query;
+ nm_query_cb_t cb;
+ void *user;
+ oop_source *oop;
+};
+
+static int _is_maildir(char *p) {
+ static char fn[PATH_MAX];
+ static struct stat st;
+
+
+ if (stat(p, &st) == 0 && S_ISDIR(st.st_mode)) {
+ snprintf(fn, sizeof(fn), "%s/cur", p);
+
+ if (stat(fn, &st) == 0 && S_ISDIR(st.st_mode))
+ return 0;
+ }
+
+ return -1;
+}
+
+static int _query(struct nm_spool *s, enum nm_query query, struct nm_status *status) {
+ struct data *data = (struct data*) s->data;
+ DIR* d;
+ static char c[PATH_MAX];
+ status->new = status->cur = -1;
+
+ if (_is_maildir(data->path)) {
+ nm_error(NM_ERROR_NOFILE, "Mailbox not maildir");
+ return -1;
+ }
+
+
+ snprintf(c, sizeof(c), "%s/new", data->path);
+ if ((d = opendir(c))) {
+ int n = 0;
+ struct dirent *de;
+
+ while ((de = readdir(d))) {
+ if (de->d_name[0] == '.')
+ continue;
+ n++;
+ if (!(query & NM_QUERY_NNEW))
+ break;
+ }
+
+ closedir(d);
+
+ snprintf(c, sizeof(c), "%s/cur", data->path);
+ if ((d = opendir(c))) {
+ int n2 = 0;
+
+ while ((de = readdir(d))) {
+ if (de->d_name[0] == '.')
+ continue;
+ n2++;
+ if (!(query & NM_QUERY_NCUR))
+ break;
+ }
+
+ closedir(d);
+
+ status->new = n;
+ status->cur = query & NM_QUERY_NCUR ? (n+n2) : (n||n2 ? 1 : 0);
+
+ return 0;
+ } else
+ nm_error(NM_ERROR_SYSTEM|NM_ERROR_NOFILE, NULL);
+
+ } else
+ nm_error(NM_ERROR_SYSTEM|NM_ERROR_NOFILE, NULL);
+
+ return -1;
+}
+
+static void * _cb(oop_source *source, struct timeval tv, void *user) {
+ struct nm_status status;
+ struct nm_spool *s = (struct nm_spool *) user;
+ struct data *data = (struct data*) s->data;
+
+ if (_query(s, data->query, &status) < 0)
+ data->cb(s, NULL, data->user);
+ else
+ data->cb(s, &status, data->user);
+
+ data->cb = NULL;
+ data->query = 0;
+ data->user = NULL;
+ data->oop = NULL;
+
+ return OOP_CONTINUE;
+}
+
+static int _query_submit(struct nm_spool *s, enum nm_query query, oop_source *oop, nm_query_cb_t cb, void *user) {
+ struct data *data = (struct data*) s->data;
+
+ if (data->cb) {
+ nm_error(NM_ERROR_ALREADY, NULL);
+ return -1;
+ }
+
+ data->cb = cb;
+ data->query = query;
+ data->user = user;
+ data->oop = oop;
+
+ data->oop->on_time(data->oop, OOP_TIME_NOW, _cb, s);
+
+ return 0;
+}
+
+static int _configure(struct nm_spool *s) {
+ return -1;
+}
+
+static int _info(struct nm_spool *s, struct nm_info *i) {
+ struct data *data = (struct data*) s->data;
+
+ snprintf(i->text, sizeof(i->text), "qmail Maildir %s", data->path);
+ i->flags = NM_FLAG_SYNCHRONOUS;
+
+ return 0;
+}
+
+static void _done(struct nm_spool *s) {
+ struct data *data = (struct data*) s->data;
+ if (data) {
+ if (data->cb && data->oop)
+ data->oop->cancel_time(data->oop, OOP_TIME_NOW, _cb, s);
+
+ nm_free(data->path);
+ nm_free(data);
+ }
+}
+
+
+int nm_init(struct nm_spool *s) {
+ struct data *data;
+ char *def;
+
+ def = NULL;
+ if (!(def = getenv("MAILDIR")))
+ if ((def = getenv("MAIL")))
+ if (_is_maildir(def) != 0) {
+ if (!s->config)
+ return -1;
+
+ def = NULL;
+ }
+
+ if (!def) {
+ static char fn[PATH_MAX];
+ snprintf(fn, sizeof(fn), "%s/Maildir", getenv("HOME"));
+ if (s->config || _is_maildir(fn) == 0)
+ def = fn;
+ else
+ return -1;
+ }
+
+
+ s->query = _query;
+ s->query_submit = _query_submit;
+ s->configure = _configure;
+ s->info = _info;
+ s->done = _done;
+
+ if (!s->path)
+ s->path = nm_strdup("@AUTOMATIC@.maildir");
+
+ data = nm_malloc(sizeof(struct data));
+ memset(data, 0, sizeof(struct data));
+
+ data->path = nm_strdup(nm_specials(nm_config_get(s->config, "Path", def)));
+ s->data = (void*) data;
+ return 0;
+}
diff --git a/src/md5.c b/src/md5.c
new file mode 100644
index 0000000..2c9c2fc
--- /dev/null
+++ b/src/md5.c
@@ -0,0 +1,381 @@
+/*
+ Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved.
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ L. Peter Deutsch
+ ghost@aladdin.com
+
+ */
+/* $Id$ */
+/*
+ Independent implementation of MD5 (RFC 1321).
+
+ This code implements the MD5 Algorithm defined in RFC 1321, whose
+ text is available at
+ http://www.ietf.org/rfc/rfc1321.txt
+ The code is derived from the text of the RFC, including the test suite
+ (section A.5) but excluding the rest of Appendix A. It does not include
+ any code or documentation that is identified in the RFC as being
+ copyrighted.
+
+ The original and principal author of md5.c is L. Peter Deutsch
+ <ghost@aladdin.com>. Other authors are noted in the change history
+ that follows (in reverse chronological order):
+
+ 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order
+ either statically or dynamically; added missing #include <string.h>
+ in library.
+ 2002-03-11 lpd Corrected argument list for main(), and added int return
+ type, in test program and T value program.
+ 2002-02-21 lpd Added missing #include <stdio.h> in test program.
+ 2000-07-03 lpd Patched to eliminate warnings about "constant is
+ unsigned in ANSI C, signed in traditional"; made test program
+ self-checking.
+ 1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
+ 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5).
+ 1999-05-03 lpd Original version.
+ */
+
+#include "md5.h"
+#include <string.h>
+
+#undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */
+#ifdef ARCH_IS_BIG_ENDIAN
+# define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1)
+#else
+# define BYTE_ORDER 0
+#endif
+
+#define T_MASK ((md5_word_t)~0)
+#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87)
+#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9)
+#define T3 0x242070db
+#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111)
+#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050)
+#define T6 0x4787c62a
+#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec)
+#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe)
+#define T9 0x698098d8
+#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850)
+#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e)
+#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841)
+#define T13 0x6b901122
+#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c)
+#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71)
+#define T16 0x49b40821
+#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d)
+#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf)
+#define T19 0x265e5a51
+#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855)
+#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2)
+#define T22 0x02441453
+#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e)
+#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437)
+#define T25 0x21e1cde6
+#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829)
+#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278)
+#define T28 0x455a14ed
+#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa)
+#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07)
+#define T31 0x676f02d9
+#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375)
+#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd)
+#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e)
+#define T35 0x6d9d6122
+#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3)
+#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb)
+#define T38 0x4bdecfa9
+#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f)
+#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f)
+#define T41 0x289b7ec6
+#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805)
+#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a)
+#define T44 0x04881d05
+#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6)
+#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a)
+#define T47 0x1fa27cf8
+#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a)
+#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb)
+#define T50 0x432aff97
+#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58)
+#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6)
+#define T53 0x655b59c3
+#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d)
+#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82)
+#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e)
+#define T57 0x6fa87e4f
+#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f)
+#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb)
+#define T60 0x4e0811a1
+#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d)
+#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca)
+#define T63 0x2ad7d2bb
+#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e)
+
+
+static void
+md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/)
+{
+ md5_word_t
+ a = pms->abcd[0], b = pms->abcd[1],
+ c = pms->abcd[2], d = pms->abcd[3];
+ md5_word_t t;
+#if BYTE_ORDER > 0
+ /* Define storage only for big-endian CPUs. */
+ md5_word_t X[16];
+#else
+ /* Define storage for little-endian or both types of CPUs. */
+ md5_word_t xbuf[16];
+ const md5_word_t *X;
+#endif
+
+ {
+#if BYTE_ORDER == 0
+ /*
+ * Determine dynamically whether this is a big-endian or
+ * little-endian machine, since we can use a more efficient
+ * algorithm on the latter.
+ */
+ static const int w = 1;
+
+ if (*((const md5_byte_t *)&w)) /* dynamic little-endian */
+#endif
+#if BYTE_ORDER <= 0 /* little-endian */
+ {
+ /*
+ * On little-endian machines, we can process properly aligned
+ * data without copying it.
+ */
+ if (!((data - (const md5_byte_t *)0) & 3)) {
+ /* data are properly aligned */
+ X = (const md5_word_t *)data;
+ } else {
+ /* not aligned */
+ memcpy(xbuf, data, 64);
+ X = xbuf;
+ }
+ }
+#endif
+#if BYTE_ORDER == 0
+ else /* dynamic big-endian */
+#endif
+#if BYTE_ORDER >= 0 /* big-endian */
+ {
+ /*
+ * On big-endian machines, we must arrange the bytes in the
+ * right order.
+ */
+ const md5_byte_t *xp = data;
+ int i;
+
+# if BYTE_ORDER == 0
+ X = xbuf; /* (dynamic only) */
+# else
+# define xbuf X /* (static only) */
+# endif
+ for (i = 0; i < 16; ++i, xp += 4)
+ xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);
+ }
+#endif
+ }
+
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
+
+ /* Round 1. */
+ /* Let [abcd k s i] denote the operation
+ a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
+#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
+#define SET(a, b, c, d, k, s, Ti)\
+ t = a + F(b,c,d) + X[k] + Ti;\
+ a = ROTATE_LEFT(t, s) + b
+ /* Do the following 16 operations. */
+ SET(a, b, c, d, 0, 7, T1);
+ SET(d, a, b, c, 1, 12, T2);
+ SET(c, d, a, b, 2, 17, T3);
+ SET(b, c, d, a, 3, 22, T4);
+ SET(a, b, c, d, 4, 7, T5);
+ SET(d, a, b, c, 5, 12, T6);
+ SET(c, d, a, b, 6, 17, T7);
+ SET(b, c, d, a, 7, 22, T8);
+ SET(a, b, c, d, 8, 7, T9);
+ SET(d, a, b, c, 9, 12, T10);
+ SET(c, d, a, b, 10, 17, T11);
+ SET(b, c, d, a, 11, 22, T12);
+ SET(a, b, c, d, 12, 7, T13);
+ SET(d, a, b, c, 13, 12, T14);
+ SET(c, d, a, b, 14, 17, T15);
+ SET(b, c, d, a, 15, 22, T16);
+#undef SET
+
+ /* Round 2. */
+ /* Let [abcd k s i] denote the operation
+ a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
+#define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
+#define SET(a, b, c, d, k, s, Ti)\
+ t = a + G(b,c,d) + X[k] + Ti;\
+ a = ROTATE_LEFT(t, s) + b
+ /* Do the following 16 operations. */
+ SET(a, b, c, d, 1, 5, T17);
+ SET(d, a, b, c, 6, 9, T18);
+ SET(c, d, a, b, 11, 14, T19);
+ SET(b, c, d, a, 0, 20, T20);
+ SET(a, b, c, d, 5, 5, T21);
+ SET(d, a, b, c, 10, 9, T22);
+ SET(c, d, a, b, 15, 14, T23);
+ SET(b, c, d, a, 4, 20, T24);
+ SET(a, b, c, d, 9, 5, T25);
+ SET(d, a, b, c, 14, 9, T26);
+ SET(c, d, a, b, 3, 14, T27);
+ SET(b, c, d, a, 8, 20, T28);
+ SET(a, b, c, d, 13, 5, T29);
+ SET(d, a, b, c, 2, 9, T30);
+ SET(c, d, a, b, 7, 14, T31);
+ SET(b, c, d, a, 12, 20, T32);
+#undef SET
+
+ /* Round 3. */
+ /* Let [abcd k s t] denote the operation
+ a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define SET(a, b, c, d, k, s, Ti)\
+ t = a + H(b,c,d) + X[k] + Ti;\
+ a = ROTATE_LEFT(t, s) + b
+ /* Do the following 16 operations. */
+ SET(a, b, c, d, 5, 4, T33);
+ SET(d, a, b, c, 8, 11, T34);
+ SET(c, d, a, b, 11, 16, T35);
+ SET(b, c, d, a, 14, 23, T36);
+ SET(a, b, c, d, 1, 4, T37);
+ SET(d, a, b, c, 4, 11, T38);
+ SET(c, d, a, b, 7, 16, T39);
+ SET(b, c, d, a, 10, 23, T40);
+ SET(a, b, c, d, 13, 4, T41);
+ SET(d, a, b, c, 0, 11, T42);
+ SET(c, d, a, b, 3, 16, T43);
+ SET(b, c, d, a, 6, 23, T44);
+ SET(a, b, c, d, 9, 4, T45);
+ SET(d, a, b, c, 12, 11, T46);
+ SET(c, d, a, b, 15, 16, T47);
+ SET(b, c, d, a, 2, 23, T48);
+#undef SET
+
+ /* Round 4. */
+ /* Let [abcd k s t] denote the operation
+ a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
+#define I(x, y, z) ((y) ^ ((x) | ~(z)))
+#define SET(a, b, c, d, k, s, Ti)\
+ t = a + I(b,c,d) + X[k] + Ti;\
+ a = ROTATE_LEFT(t, s) + b
+ /* Do the following 16 operations. */
+ SET(a, b, c, d, 0, 6, T49);
+ SET(d, a, b, c, 7, 10, T50);
+ SET(c, d, a, b, 14, 15, T51);
+ SET(b, c, d, a, 5, 21, T52);
+ SET(a, b, c, d, 12, 6, T53);
+ SET(d, a, b, c, 3, 10, T54);
+ SET(c, d, a, b, 10, 15, T55);
+ SET(b, c, d, a, 1, 21, T56);
+ SET(a, b, c, d, 8, 6, T57);
+ SET(d, a, b, c, 15, 10, T58);
+ SET(c, d, a, b, 6, 15, T59);
+ SET(b, c, d, a, 13, 21, T60);
+ SET(a, b, c, d, 4, 6, T61);
+ SET(d, a, b, c, 11, 10, T62);
+ SET(c, d, a, b, 2, 15, T63);
+ SET(b, c, d, a, 9, 21, T64);
+#undef SET
+
+ /* Then perform the following additions. (That is increment each
+ of the four registers by the value it had before this block
+ was started.) */
+ pms->abcd[0] += a;
+ pms->abcd[1] += b;
+ pms->abcd[2] += c;
+ pms->abcd[3] += d;
+}
+
+void
+md5_init(md5_state_t *pms)
+{
+ pms->count[0] = pms->count[1] = 0;
+ pms->abcd[0] = 0x67452301;
+ pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476;
+ pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301;
+ pms->abcd[3] = 0x10325476;
+}
+
+void
+md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes)
+{
+ const md5_byte_t *p = data;
+ int left = nbytes;
+ int offset = (pms->count[0] >> 3) & 63;
+ md5_word_t nbits = (md5_word_t)(nbytes << 3);
+
+ if (nbytes <= 0)
+ return;
+
+ /* Update the message length. */
+ pms->count[1] += nbytes >> 29;
+ pms->count[0] += nbits;
+ if (pms->count[0] < nbits)
+ pms->count[1]++;
+
+ /* Process an initial partial block. */
+ if (offset) {
+ int copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
+
+ memcpy(pms->buf + offset, p, copy);
+ if (offset + copy < 64)
+ return;
+ p += copy;
+ left -= copy;
+ md5_process(pms, pms->buf);
+ }
+
+ /* Process full blocks. */
+ for (; left >= 64; p += 64, left -= 64)
+ md5_process(pms, p);
+
+ /* Process a final partial block. */
+ if (left)
+ memcpy(pms->buf, p, left);
+}
+
+void
+md5_finish(md5_state_t *pms, md5_byte_t digest[16])
+{
+ static const md5_byte_t pad[64] = {
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+ md5_byte_t data[8];
+ int i;
+
+ /* Save the length before padding. */
+ for (i = 0; i < 8; ++i)
+ data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3));
+ /* Pad to 56 bytes mod 64. */
+ md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);
+ /* Append the length. */
+ md5_append(pms, data, 8);
+ for (i = 0; i < 16; ++i)
+ digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
+}
diff --git a/src/md5.h b/src/md5.h
new file mode 100644
index 0000000..5eb6d6c
--- /dev/null
+++ b/src/md5.h
@@ -0,0 +1,91 @@
+/*
+ Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved.
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ L. Peter Deutsch
+ ghost@aladdin.com
+
+ */
+/* $Id$ */
+/*
+ Independent implementation of MD5 (RFC 1321).
+
+ This code implements the MD5 Algorithm defined in RFC 1321, whose
+ text is available at
+ http://www.ietf.org/rfc/rfc1321.txt
+ The code is derived from the text of the RFC, including the test suite
+ (section A.5) but excluding the rest of Appendix A. It does not include
+ any code or documentation that is identified in the RFC as being
+ copyrighted.
+
+ The original and principal author of md5.h is L. Peter Deutsch
+ <ghost@aladdin.com>. Other authors are noted in the change history
+ that follows (in reverse chronological order):
+
+ 2002-04-13 lpd Removed support for non-ANSI compilers; removed
+ references to Ghostscript; clarified derivation from RFC 1321;
+ now handles byte order either statically or dynamically.
+ 1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
+ 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5);
+ added conditionalization for C++ compilation from Martin
+ Purschke <purschke@bnl.gov>.
+ 1999-05-03 lpd Original version.
+ */
+
+#ifndef md5_INCLUDED
+# define md5_INCLUDED
+
+/*
+ * This package supports both compile-time and run-time determination of CPU
+ * byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be
+ * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is
+ * defined as non-zero, the code will be compiled to run only on big-endian
+ * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to
+ * run on either big- or little-endian CPUs, but will run slightly less
+ * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined.
+ */
+
+typedef unsigned char md5_byte_t; /* 8-bit byte */
+typedef unsigned int md5_word_t; /* 32-bit word */
+
+/* Define the state of the MD5 Algorithm. */
+typedef struct md5_state_s {
+ md5_word_t count[2]; /* message length in bits, lsw first */
+ md5_word_t abcd[4]; /* digest buffer */
+ md5_byte_t buf[64]; /* accumulate block */
+} md5_state_t;
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/* Initialize the algorithm. */
+void md5_init(md5_state_t *pms);
+
+/* Append a string to the message. */
+void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes);
+
+/* Finish the message and return the digest. */
+void md5_finish(md5_state_t *pms, md5_byte_t digest[16]);
+
+#ifdef __cplusplus
+} /* end extern "C" */
+#endif
+
+#endif /* md5_INCLUDED */
diff --git a/src/module.h b/src/module.h
new file mode 100644
index 0000000..7e8eb98
--- /dev/null
+++ b/src/module.h
@@ -0,0 +1,70 @@
+#ifndef foomodulehfoo
+#define foomodulehfoo
+
+/* $Id$ */
+
+/***
+ This file is part of libnewmail
+
+ libnewmail 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.
+
+ libnewmail 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 libnewmail; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ USA
+***/
+
+/** \file
+ *
+ * The plugin interface of libnewmail. Mail checking modules should
+ * use these functions and those declared in config.h and util.h
+ */
+
+#include <ltdl.h>
+#include "newmail.h"
+#include "config.h"
+
+/** A structure encapsulating information about a mail spool handle. It is opaque to the application
+ */
+struct nm_spool {
+ lt_dlhandle dl; /**< A libltdl handle to the plugin so */
+ char *data; /**< Some plugin specific data */
+ config_t *config; /**< A configuration context for the mail spool */
+ char *path; /**< The path to the associated configuration file */
+
+ int (*query) (struct nm_spool *s, enum nm_query query, struct nm_status *status);
+ /**< A pointer to the real query() function wrapped by nm_query() */
+
+ int (*query_submit) (struct nm_spool *s, enum nm_query query, oop_source* oop, nm_query_cb_t cb, void *user);
+ /**< A pointer to the real query_submit() function wrapped by nm_query_submit() */
+
+ int (*configure) (struct nm_spool *s);
+ /**< A pointer to the real configure() function wrapped by nm_configuret() */
+
+ int (*info) (struct nm_spool *s, struct nm_info *i);
+ /**< A pointer to the real query_info() function wrapped by nm_info() */
+
+ void (*done) (struct nm_spool *s);
+ /**< A pointer to a function which will be called before this nm_spool is freed. */
+};
+
+/** The prototype of the only function which needs to be exported by a
+ * plugin. It is called when new nm_spool of the plugin is
+ * instantiated.
+ * @param s The virgin nm_spool structure. The plugin should fill in
+ * the pointers to functions contained in the structure.\c dl, \c config and \c path are
+ * already filled in, \c data may be used for arbitrary spool handle
+ * specific data,
+ * @return zero on success, nonzero on failure.
+ */
+typedef int (*nm_init_t) (struct nm_spool *s);
+
+#endif
diff --git a/src/newmail.c b/src/newmail.c
new file mode 100644
index 0000000..7d513c9
--- /dev/null
+++ b/src/newmail.c
@@ -0,0 +1,339 @@
+/* $Id$ */
+
+/***
+ This file is part of libnewmail
+
+ libnewmail 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.
+
+ libnewmail 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 libnewmail; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ USA
+***/
+
+#include <limits.h>
+#include <dirent.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <ltdl.h>
+
+#include "newmail.h"
+#include "module.h"
+#include "config.h"
+#include "util.h"
+
+#ifndef NM_LIBRARY_PATH
+#define NM_LIBRARY_PATH "/home/lennart/projects/libnewmail/src"
+#endif
+
+#define NM_PRIVATE_CONFIG_PATH ".newmail"
+#define NM_GLOBAL_CONFIG_PATH "/etc/newmail"
+
+void* (*nm_malloc)(size_t) = malloc;
+void* (*nm_realloc)(void *,size_t) = realloc;
+void (*nm_free)(void *) = free;
+
+enum nm_error nm_errno = 0;
+char *nm_explanation = 0;
+
+static void _ltdl_init(int b) {
+ static int n = 0;
+
+ if (b) {
+ if (n++ == 0) {
+ lt_dlinit();
+ lt_dladdsearchdir(NM_LIBRARY_PATH);
+ }
+ } else {
+ if (--n == 0)
+ lt_dlexit();
+ }
+}
+
+
+int nm_list(nm_enum_cb_t cb, const void*user) {
+ static char p[PATH_MAX];
+ DIR *d;
+ struct dirent *de;
+ int n = 0;
+
+ if (!cb) {
+ nm_error(NM_ERROR_INVPAR, NULL);
+ return -1;
+ }
+
+ snprintf(p, sizeof(p), "%s/"NM_PRIVATE_CONFIG_PATH, getenv("HOME"));
+ if (!(d = opendir(p)))
+ if (!(d = opendir(NM_GLOBAL_CONFIG_PATH)))
+ return 0;
+
+ while ((de = readdir(d))) {
+ static char fn[PATH_MAX];
+
+ if (de->d_name[0] == '.')
+ continue;
+
+ snprintf(fn, sizeof(fn), "%s/%s", p, de->d_name);
+ cb(fn, user);
+ n++;
+ }
+
+ closedir(d);
+
+ return n;
+}
+
+const char *nm_strerror(enum nm_error n, int e, const char *explanation) {
+ char *p = NULL;
+ static char t[256];
+
+ switch (n & ~(NM_ERROR_SYSTEM|NM_ERROR_EXPLANATION)) {
+ case NM_ERROR_SUCCESS: p = "Success"; break;
+ case NM_ERROR_NOCONFIG: p = "No configuration available"; break;
+ case NM_ERROR_INVPAR: p = "Invalid parameters"; break;
+ case NM_ERROR_MEMORY: p = "Not enough memory"; break;
+ case NM_ERROR_INVNAME: p = "Invalid name"; break;
+ case NM_ERROR_DLFAIL: p = "Module not found"; break;
+ case NM_ERROR_NOTIMPL: p = "Not implemented"; break;
+ case NM_ERROR_NOFILE: p = "Could not open file"; break;
+ case NM_ERROR_FORK: p = "fork() failure"; break;
+ case NM_ERROR_ALREADY: p = "Asynchronous check already scheduled"; break;
+ case NM_ERROR_CONTEXT: p = "Function call in wrong context"; break;
+ case NM_ERROR_INTERNAL: p = "Internal error"; break;
+ case NM_ERROR_SERVFAIL: p = "Server failure"; break;
+ case NM_ERROR_SERVNOTFOUND: p = "Server not found"; break;
+ default: p = "Unknown error"; break;
+ }
+
+ if (n & NM_ERROR_SYSTEM) {
+ snprintf(t, sizeof(t), "%s (%s)", p, strerror(e));
+ p = t;
+ } else if (n & NM_ERROR_EXPLANATION) {
+ snprintf(t, sizeof(t), "%s (Explanation: %s)", p, explanation);
+ p = t;
+ }
+
+ return p;
+}
+
+void nm_perror(const char *s) {
+ fprintf(stderr, "%s: %s\n", s, nm_strerror(nm_errno, errno, nm_explanation));
+}
+
+int nm_info(struct nm_spool *s, struct nm_info *i) {
+ char *p;
+
+ if (!s || !i) {
+ nm_error(NM_ERROR_INVPAR, NULL);
+ goto fail;
+ }
+
+ if (!s->info) {
+ nm_error(NM_ERROR_NOTIMPL, NULL);
+ goto fail;
+ }
+
+ memset(i, 0, sizeof(struct nm_info));
+
+ strncpy(i->path, s->path ? s->path : "n/a", sizeof(i->path));
+ i->path[sizeof(i->path)-1] = 0;
+
+ if (!(p = strrchr(i->path, '/')))
+ p = i->path;
+ else
+ p++;
+
+ strncpy(i->name, p, sizeof(i->name));
+ i->name[sizeof(i->name)-1] = 0;
+
+ if ((p = strrchr(i->name, '.'))) {
+ *p = 0;
+ p++;
+
+ strncpy(i->type, p, sizeof(i->type));
+ i->type[sizeof(i->type)-1] = 0;
+ }
+
+ return s->info(s, i);
+
+fail:
+
+ return -1;
+}
+
+int nm_query(struct nm_spool *s, enum nm_query query, struct nm_status *st) {
+
+ if (!s || !st) {
+ nm_error(NM_ERROR_INVPAR, NULL);
+ goto fail;
+ }
+
+ if (!s->query) {
+ nm_error(NM_ERROR_NOTIMPL, NULL);
+ goto fail;
+ }
+
+ return s->query(s, query, st);
+
+fail:
+ return -1;
+}
+
+
+int nm_query_submit(struct nm_spool *s, enum nm_query query, oop_source *oop, nm_query_cb_t cb, const void *user) {
+
+ if (!s || !cb || !oop) {
+ nm_error(NM_ERROR_INVPAR, NULL);
+ goto fail;
+ }
+
+ if (!s->query_submit) {
+ nm_error(NM_ERROR_NOTIMPL, NULL);
+ goto fail;
+ }
+
+ return s->query_submit(s, query, oop, cb, (void*) user);
+
+fail:
+ return -1;
+}
+
+static int _nm_load(struct nm_spool *s, char *p) {
+ char t[PATH_MAX];
+ nm_init_t init;
+
+ _ltdl_init(1);
+
+
+ snprintf(t, sizeof(t), "lib%s", p);
+ if (!(s->dl = lt_dlopenext(t))) {
+ nm_error(NM_ERROR_DLFAIL|NM_ERROR_EXPLANATION, lt_dlerror());
+ goto fail;
+ }
+
+ if (!(init = lt_dlsym(s->dl, "nm_init"))) {
+ nm_error(NM_ERROR_DLFAIL|NM_ERROR_EXPLANATION, lt_dlerror());
+ goto fail;
+ }
+
+ if (init(s) < 0)
+ goto fail;
+
+ return 0;
+
+fail:
+
+ if (s->dl)
+ lt_dlclose(s->dl);
+
+ _ltdl_init(0);
+
+ return -1;
+}
+
+struct nm_spool* nm_open(const char *spool) {
+ struct nm_spool* s = NULL;
+ static char p[PATH_MAX];
+
+ if (!spool) {
+ char *r;
+ snprintf(p, sizeof(p), "%s/"NM_PRIVATE_CONFIG_PATH"/.default", getenv("HOME"));
+
+ if ((r = realpath(p, NULL)))
+ if ((s = nm_open(r))) {
+ free(r);
+ return s;
+ }
+
+ snprintf(p, sizeof(p), NM_GLOBAL_CONFIG_PATH"/.default");
+
+ if ((r = realpath(p, NULL)))
+ if ((s = nm_open(r))) {
+ free(r);
+ return s;
+ }
+ }
+
+ if (!(s = nm_malloc(sizeof(struct nm_spool)))) {
+ nm_error(NM_ERROR_MEMORY, NULL);
+ goto fail;
+ }
+ memset(s, 0, sizeof(struct nm_spool));
+
+ if (spool) {
+ char *d;
+
+ if (!(s->config = nm_config_open(spool)))
+ goto fail;
+
+ if (!(s->path = nm_strdup(spool))) {
+ nm_error(NM_ERROR_MEMORY, NULL);
+ goto fail;
+ }
+
+ if (!(d = strrchr(spool, '.'))) {
+ nm_error(NM_ERROR_INVNAME, NULL);
+ goto fail;
+ }
+ d++;
+
+ if (_nm_load(s, d) < 0)
+ goto fail;
+
+ } else {
+ if (_nm_load(s, "maildir") < 0)
+ if (_nm_load(s, "unix") < 0)
+ goto fail;
+ }
+
+ return s;
+
+fail:
+ if (s) {
+ if (s->config)
+ nm_config_close(s->config);
+
+
+ if (s->path)
+ nm_free(s->path);
+
+ nm_free(s);
+ }
+
+ return NULL;
+}
+
+void nm_close(struct nm_spool *s) {
+
+ if (!s) {
+ nm_error(NM_ERROR_INVPAR, NULL);
+ return;
+ }
+
+ if (s->done)
+ s->done(s);
+
+ if (s->config)
+ nm_config_close(s->config);
+
+ if (s->path)
+ nm_free(s->path);
+
+ if (s->dl)
+ lt_dlclose(s->dl);
+
+ nm_free(s);
+
+ _ltdl_init(0);
+}
+
diff --git a/src/newmail.h b/src/newmail.h
new file mode 100644
index 0000000..109a87d
--- /dev/null
+++ b/src/newmail.h
@@ -0,0 +1,254 @@
+#ifndef foonewmailhfoo
+#define foonewmailhfoo
+
+/* $Id$ */
+
+/***
+ This file is part of libnewmail
+
+ libnewmail 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.
+
+ libnewmail 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 libnewmail; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ USA
+***/
+
+/** \mainpage
+ *
+ * For a brief explanation of libnewmail's purpose, have a look on <a href="../../README.html">the README file</a>. Thank you!
+ *
+ */
+
+/** \example easy.c
+ * A minimal example
+ */
+
+/** \example nmail.c
+ * This is an usage example for the simple, synchronous API of libnewmail
+ */
+
+/** \example nmail-async.c
+ * This is an usage example for the asynchronous API of libnewmail
+ */
+
+/** \example nm-spoolhack.c This is an example implementing a tool to
+ * emulate Unix mail spool stat() behaviour for a flag file to
+ * multiplex mail status information of libnewmail plugins.
+ */
+
+
+/** \file
+ *
+ * The public application interface of libnewmail. Applications
+ * linking to libnewmail should use only functions defined in this
+ * header file.
+ */
+
+#include <limits.h>
+#include <oop.h>
+
+/**
+ * Flags for a mail spool; specifies if a query on this spool will be
+ * executed synchronously or asynchronously. Local mailbox queries
+ * are probably executed synchronously, while networked queries are
+ * exectued asynchronously.
+ */
+enum nm_flags {
+ NM_FLAG_SYNCHRONOUS= 1, /**< The spool query won't block */
+ NM_FLAG_ASYNCHRONOUS = 2 /**< The spool query may block when not issued asynchronously */
+};
+
+/**
+ * An enumeration specifying a certain error
+ * condition. NM_ERROR_SYSTEM and NM_ERROR_EXPLANATION may be ORed
+ * logically with one of the other constants, to specifiy that system
+ * errno and/or the nm_explanation variable is in context with the
+ * error occured.
+ */
+enum nm_error {
+ NM_ERROR_SYSTEM = 256, /**< When this bit is set, errno is also set */
+ NM_ERROR_EXPLANATION = 512, /**< When this bit is set, nm_explanation is set */
+ NM_ERROR_SUCCESS = 0, /**< The query succeeded */
+ NM_ERROR_NOCONFIG = 1, /**< No configuration file was found for this spool */
+ NM_ERROR_INVPAR = 2, /**< An API function was called with corrupt parameters */
+ NM_ERROR_MEMORY = 3, /**< Failure while allocating memory */
+ NM_ERROR_INVNAME = 4, /**< Invalid name */
+ NM_ERROR_DLFAIL = 5, /**< Plugin could not be loaded (failure of dynamic loader) */
+ NM_ERROR_NOTIMPL = 6, /**< Function not implemented */
+ NM_ERROR_NOFILE = 7, /**< File not found */
+ NM_ERROR_FORK = 8, /**< Failure on fork() */
+ NM_ERROR_ALREADY = 9, /**< A query was submitted while the previous hasn't been terminated yet */
+ NM_ERROR_CONTEXT = 10, /**< Function called in wrong context */
+ NM_ERROR_INTERNAL = 11, /**< Internal error */
+ NM_ERROR_SERVFAIL = 12, /**< Server failed */
+ NM_ERROR_SERVNOTFOUND = 13, /**< Server not found */
+};
+
+/**
+ * Types of mail spool queries; A combination of these flags should be
+ * specified on a call to nm_query()
+ */
+enum nm_query {
+ NM_QUERY_CUR = 1, /**< Query the boolean availability of total (current) mails */
+ NM_QUERY_NEW = 2, /**< Query the boolean availabillty of unread mails */
+ NM_QUERY_NCUR = 4, /**< Query the numeric count of total (current) mails */
+ NM_QUERY_NNEW = 8 /**< Query the numeric count of unread mails */
+};
+
+/** Opaque structure encapsulating a handle on a mail spool A pointer
+ * to a structure of this type is returned by nm_open(). It should be
+ * freed with nm_close().
+ */
+struct nm_spool;
+
+/** A structure describing a mail spool status.
+ *
+ */
+struct nm_status {
+ int cur; /**< The number of total mails available if the query was issued with NM_QUERY_NCUR or a boolean value if NM_QUERY_CUR was set. */
+ int new; /**< The number of unread mails available if the query was issued with NM_QUERY_NNEW or a boolean value if NM_QUERY_NEW was set. */
+};
+
+/** A structure for storing information about a mail spool. For usage with nm_info().
+ */
+struct nm_info {
+ char name[NAME_MAX]; /**< Name of the mailspool */
+ char path[PATH_MAX]; /**< Path to the configuration file */
+ char type[32]; /**< Textual representation of the mail spool type */
+ char text[128]; /**< Description of the mail spool */
+ enum nm_flags flags; /**< Flags describing the the mail spool */
+};
+
+
+/** A prototype for callback functions for enumerating configured
+ * mail spools with nm_list().
+ * @param spool A path to a configuration file
+ * @param user The user pointer specified on nm_list() invocation
+ */
+typedef void (*nm_enum_cb_t) (const char *spool, const void*user);
+
+/** A prototype for callback functions for asynchronous mail spool queries.
+ * @param s The mail spool belonging to this response
+ * @param status A pointer to a structure describing the mail spool status or NULL, if an error occured. In this case, nm_errno is set.
+ * @param user The user pointer specified on nm_query_submit() invocation
+ */
+typedef void (*nm_query_cb_t) (struct nm_spool *s, struct nm_status *status, const void *user);
+
+/** A pointer to a malloc() compatible function which is used by
+ * libnewmail for allocating memory. Initially set to libc's malloc().
+ */
+extern void* (*nm_malloc)(size_t);
+
+/** A pointer to a realloc() compatible function which is used by
+ * libnewmail for reallocating memory. Initially set to libc's
+ * realloc().
+ */
+extern void* (*nm_realloc)(void *,size_t);
+
+/** A pointer to a free() compatible function which is used by
+ * libnewmail for freeing memory. Initially set to libc's
+ * free().
+ */
+extern void (*nm_free)(void *);
+
+/** A pointer to a textual string giving a terse explanation for the
+ * last failure. This is only valid when NM_ERROR_EXPLANATION is set
+ * in nm_errno.
+ */
+extern char *nm_explanation;
+
+/** A variable describing the last error occured. Only valid when the
+ * last API function call returned a failure.
+ */
+extern enum nm_error nm_errno;
+
+
+/** Open the given mail spool configuration file and return a pointer
+ * to an opaque stracture used as handle to access the mail spool. The
+ * returned pointer should be freed with nm_close() when it is no
+ * longer needed.
+ * @param spool A path to a mail spool configuration file. If NULL an
+ * automatic detection of the mail spool location is tried.
+ * @return A pointer to a newly allocated spool handle or NULL on failure. In this case nm_errno is set.
+ */
+struct nm_spool* nm_open(const char *spool);
+
+/** Free the given mail spool handle.
+ * @param s The spool handle to be freed
+ */
+void nm_close(struct nm_spool *s);
+
+/** Issue a synchronous query for the specified mail spool. The
+ * function will block until the query succeeded or a failure is
+ * returned. Be aware that every query may use fork() to spawn a
+ * background process to execute the query.
+ * @param s The spool to be queried
+ * @param query The desired query type
+ * @param status A pointer to a structure which will be filled with the query response
+ * @return zero on success, negative on failure. In the latter case nm_errno is set.
+ */
+int nm_query(struct nm_spool *s, enum nm_query query, struct nm_status *status);
+
+/** Issue an asynchronous query for the specified mail spool. The
+ * function will return immediately, however the callback cb is called
+ * when the query is finished. Be aware that every query may use fork() to spawn a
+ * background process to execute the query.
+ * @param s The spool to be queried
+ * @param query The desired query type
+ * @param oop The liboop oop_source which shall be used for asynchronous handling
+ * @param cb The callback function to be called when the query is finished.
+ * @param user An arbitrary pointer to be passed to cb
+ * @return zero on success, negative on failure. In the latter case nm_errno is set.
+ */
+int nm_query_submit(struct nm_spool *s, enum nm_query query, oop_source *oop, nm_query_cb_t cb, const void *user);
+
+/** Show an X11 configuration dialog for the specified mail spool -- Currently an NOOP
+ * This function will run an external configuration program for the specific mail spool eventually.
+ * @param s The spool the dialog should be shown for. NULL if a
+ * complete configuration dialog should be shown, with the possibility
+ * for the user to create new mail spool profiles.
+ * @return zero on success, negative on failure. In the latter case nm_errno is set.
+ */
+int nm_configure(struct nm_spool *s);
+
+/** Fill a structure containing some information about the specified mail spool
+ * @param s The spool to be queried
+ * @param info A pointer to the information structure to be filled
+ * @return zero on success, negative on failure. In the latter case nm_errno is set.
+ */
+int nm_info(struct nm_spool *s, struct nm_info *info);
+
+/** Enumerate all configured mail spools.
+ * @param cb A callback function called for every configured mail spool.
+ * @param user An arbitrary pointer to be passed to cb
+ * @return negative on failure, number of calls to cb invoked. If this
+ * is zero, no mail spool is configured, you probably should try a
+ * nm_open(NULL) next.
+ */
+int nm_list(nm_enum_cb_t cb, const void*user);
+
+/** Return a textual representation of the given error triplet.
+ * @param n A libnewmail error condition (e.g. nm_errno)
+ * @param e A libc error condition (e.g. errno)
+ * @param explanation A libnewmail error explanation (e.g. nm_explanation)
+ * @return A pointer to a string in static memory. The contents is
+ * overwritten on subsequent calls to nm_strerror() or nm_perror().
+ */
+const char *nm_strerror(enum nm_error n, int e, const char *explanation);
+
+/** A similar function to libc's perror(). This function will show
+ * libnewmail error conditions however.
+ * @param s A string which will be concatenated with the error string
+ */
+void nm_perror(const char *s);
+
+#endif
diff --git a/src/nm-spoolhack.c b/src/nm-spoolhack.c
new file mode 100644
index 0000000..59630ab
--- /dev/null
+++ b/src/nm-spoolhack.c
@@ -0,0 +1,196 @@
+/* $Id: nmail-async.c 23 2003-06-04 22:04:34Z lennart $ */
+
+/***
+ This file is part of libnewmail
+
+ libnewmail 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.
+
+ libnewmail 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 libnewmail; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ USA
+***/
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <newmail.h>
+
+/* The default Unix mail spool emulation file to use */
+#define HACKFILE ".newmail.hack"
+
+/* Create a mail spool file with a size > 0, mtime > atime. */
+int create_new(const char *fname) {
+ int fd = -1, r = 1;
+ char c = 'X';
+
+ if ((fd = open(fname, O_WRONLY|O_CREAT, 0666)) < 0) {
+ fprintf(stderr, "open(\"%s\", ...): %s\n", fname, strerror(errno));
+ goto finish;
+ }
+
+ if (write(fd, &c, sizeof(c)) != sizeof(c)) {
+ fprintf(stderr, "write(): %s\n", strerror(errno));
+ goto finish;
+ }
+
+ ftruncate(fd, 1);
+
+ r = 0;
+
+finish:
+ if (fd >= 0)
+ close(fd);
+
+ return r;
+
+}
+
+/* Create a mail spool file with a size > 0, mtime < atime. */
+int create_old(const char *fname) {
+ int r = 1, fd = -1;
+ char c = 'X';
+ ssize_t n;
+
+ if ((fd = open(fname, O_RDWR|O_CREAT, 0666)) < 0) {
+ fprintf(stderr, "open(\"%s\", ...): %s\n", fname, strerror(errno));
+ goto finish;
+ }
+
+ do {
+ if (lseek(fd, 0, SEEK_SET) != 0) {
+ fprintf(stderr, "lseek(): %s\n", strerror(errno));
+ goto finish;
+ }
+
+ if ((n = read(fd, &c, sizeof(c))) < 0) {
+ fprintf(stderr, "read(): %s\n", strerror(errno));
+ goto finish;
+ }
+
+ if (!n) {
+ if (write(fd, &c, sizeof(c)) != sizeof(c)) {
+ fprintf(stderr, "write(): %s\n", strerror(errno));
+ goto finish;
+ }
+ }
+ } while (!n);
+
+ r = 0;
+
+finish:
+ if (fd >= 0)
+ close(fd);
+
+ return r;
+}
+
+/* Create a mail spool file with size == 0. */
+int create_empty(const char *fname) {
+ int fd = -1, r = 1;
+ if ((fd = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0) {
+ fprintf(stderr, "open(\"%s\", ...): %s\n", fname, strerror(errno));
+ goto finish;
+ }
+
+ r = 0;
+
+finish:
+ if (fd >= 0)
+ close(fd);
+
+ return r;
+
+}
+
+/* Show usage information */
+void usage(const char *argv0) {
+ const char *r;
+ if ((r = strrchr(argv0, '/')))
+ r++;
+ else
+ r = argv0;
+
+ printf("%s [-s SPOOLNAME ] [-f HACKFILE]\n\n"
+ " SPOOLNAME: The libnewmail spool name to check\n"
+ " HACKFILE: The emulated Unix mail spool file to use, defaults to $HOME/"HACKFILE"\n\n"
+ "%s multiplexes the Unix mail spool stat() behaviour for remote mail spools.\n"
+ "This may be used to teach simple mail check applets new mail spool techniques without patching.\n", r, r);
+
+ exit(1);
+}
+
+int main(int argc, char *argv[]) {
+ struct nm_spool *s = NULL;
+ struct nm_status st;
+ int r = 1;
+ char *n = NULL,
+ *fname = NULL;
+ char t[PATH_MAX];
+
+ /* Iterate through the arguments passed to the process */
+ for (;;) {
+ int c;
+
+ if ((c = getopt(argc, argv, "s:f:h")) == -1)
+ break;
+
+ switch (c) {
+ case 's':
+ n = optarg;
+ break;
+
+ case 'f':
+ fname = optarg;
+ break;
+
+ default:
+ usage(argv[0]);
+ }
+ }
+
+ if (!fname)
+ snprintf(fname = t, sizeof(t), "%s/"HACKFILE, getenv("HOME"));
+
+ /* Open the mail spool */
+ if (!(s = nm_open(n))) {
+ fprintf(stderr, "nm_open(\"%s\"): %s\n", n, nm_strerror(nm_errno, errno, nm_explanation));
+ goto finish;
+ }
+
+ /* Issue the query */
+ if (nm_query(s, NM_QUERY_CUR|NM_QUERY_NEW, &st) < 0) {
+ fprintf(stderr, "nm_check(\"%s\"): %s\n", n, nm_strerror(nm_errno, errno, nm_explanation));
+ goto finish;
+ }
+
+ /* Create the mail spool file accordingly */
+ if (st.cur && st.new)
+ r = create_new(fname);
+ else if (st.cur)
+ r = create_old(fname);
+ else
+ r = create_empty(fname);
+
+finish:
+
+ /* Close the mail spool */
+ if (s)
+ nm_close(s);
+
+ return r;
+
+}
diff --git a/src/nmail-async.c b/src/nmail-async.c
new file mode 100644
index 0000000..06f4d09
--- /dev/null
+++ b/src/nmail-async.c
@@ -0,0 +1,183 @@
+/* $Id$ */
+
+/***
+ This file is part of libnewmail
+
+ libnewmail 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.
+
+ libnewmail 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 libnewmail; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ USA
+***/
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#include <newmail.h>
+
+/* The query to issue */
+int query = NM_QUERY_NCUR|NM_QUERY_NNEW;
+
+/* A counter for the queries running */
+int count = 0;
+
+/* The liboop main loop object */
+oop_source *oop = NULL;
+
+/* A linked list structure for the spools */
+struct spool_ll{
+ struct nm_spool *spool;
+ struct spool_ll *next;
+} *spools = NULL;
+
+/* A function which converts binary mail spool status flags into human readable strings */
+char *b2s(int b) {
+ if (b < 0) return "fail";
+ if (b > 0) return "yes";
+ return "no";
+}
+
+/* A callback function for oop which terminates the main loop */
+void* _finish(oop_source *source, struct timeval tv, void *user) {
+ return OOP_HALT;
+}
+
+/* A utility function which issues the callback defined above */
+void finish(void) {
+ oop->on_time(oop, OOP_TIME_NOW, _finish, NULL);
+}
+
+/* A callback function which is called whenever a mail spool query finished */
+void cb_check(struct nm_spool *s, struct nm_status *status, const void *user) {
+ struct nm_info i;
+ static char txt[256];
+
+ /* Check the status flag */
+ if (!status)
+ snprintf(txt, sizeof(txt), "%s", nm_strerror(nm_errno, errno, nm_explanation));
+
+ /* Get some information about the mail spool */
+ if (nm_info(s, &i) < 0) {
+ fprintf(stderr, "nm_open(): %s\n", nm_strerror(nm_errno, errno, nm_explanation));
+ goto finish;
+ }
+
+ /* Print that information */
+ printf("\n%s:\n\tName: %s\n\tType: %s\n\tText: %s\n\tFlags: ", i.path, i.name, i.type, i.text);
+ if (i.flags & NM_FLAG_SYNCHRONOUS) printf("SYNCHRONOUS ");
+ if (i.flags & NM_FLAG_ASYNCHRONOUS) printf("ASYNCHRONOUS ");
+ printf("\n");
+
+ /* Show status information */
+ if (status) {
+ if (query & NM_QUERY_NCUR)
+ printf("\tCurrent: %i\n", status->cur);
+ else if (query & NM_QUERY_CUR)
+ printf("\tCurrent: %s\n", b2s(status->cur));
+
+ if (query & NM_QUERY_NNEW)
+ printf("\tNew: %i\n", status->new);
+ else if (query & NM_QUERY_NEW)
+ printf("\tNew: %s\n", b2s(status->new));
+
+ } else
+ fprintf(stderr, "\n\tFAILURE: %s\n", txt);
+
+finish:
+
+ count--;
+ if (count <= 0)
+ finish();
+}
+
+/* The callback function for iterating through the mail spools available */
+void cb_list(const char *spool, const void *user) {
+ struct nm_spool* s = NULL;
+ struct spool_ll* l = 0;
+
+ /* Open the mail spool */
+ if (!(s = nm_open(spool))) {
+ fprintf(stderr, "nm_open(\"%s\"): %s\n", spool, nm_strerror(nm_errno, errno, nm_explanation));
+ goto finish;
+ }
+
+ /* Allocate a linked list entry */
+ if (!(l = malloc(sizeof(struct spool_ll)))) {
+ fprintf(stderr, "Memory\n");
+ goto finish;
+ }
+
+ /* Start the spool query */
+ if (nm_query_submit(s, query, oop, cb_check, NULL) < 0) {
+ fprintf(stderr, "nm_check_submit(\"%s\"): %s\n", spool, nm_strerror(nm_errno, errno, nm_explanation));
+ goto finish;
+ }
+
+ /* Fill in the linked list entry */
+ l->spool = s;
+ l->next = spools;
+ spools = l;
+
+ count++;
+
+ return;
+
+finish:
+
+ free(l);
+
+ if (s)
+ nm_close(s);
+}
+
+int main(int argc, char *argv[]) {
+ oop_source_sys *sys;
+ count = 1; /* This variable is initialized to 1 because otherwise
+ * the main loop is terminated too early when
+ * synchronous mail spools are queried */
+
+ /* Create a generic liboop main loop object */
+ if (!(sys = oop_sys_new())) {
+ fprintf(stderr, "Could not reate OOP system source.\n");
+ return 1;
+ }
+
+ if (!(oop = oop_sys_source(sys))) {
+ fprintf(stderr, "Could not reate OOP system source.\n");
+ oop_sys_delete(sys);
+ return 1;
+ }
+
+ /* Iterate through the mail spools avilable */
+ if (nm_list(cb_list, NULL) < 0)
+ nm_perror("nm_list()");
+
+ count--;
+
+ /* Wait until all queries finished */
+ while (count > 0)
+ oop_sys_run(sys);
+
+ /* Shutdown the main loop */
+ oop_sys_delete(sys);
+
+ /* Free the linked list */
+ while (spools) {
+ struct spool_ll *l = spools;
+ spools = spools->next;
+ nm_close(l->spool);
+ free(l);
+ }
+
+ return 0;
+}
diff --git a/src/nmail.c b/src/nmail.c
new file mode 100644
index 0000000..e9fbdb8
--- /dev/null
+++ b/src/nmail.c
@@ -0,0 +1,93 @@
+/* $Id$ */
+
+/***
+ This file is part of libnewmail
+
+ libnewmail 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.
+
+ libnewmail 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 libnewmail; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ USA
+***/
+
+#include <stdio.h>
+#include <errno.h>
+
+#include <newmail.h>
+
+/* This type of query is issued */
+int query = NM_QUERY_NCUR|NM_QUERY_NNEW;
+
+/* A simple function formatting mail status codes */
+char *b2s(int b) {
+ if (b < 0) return "fail";
+ if (b > 0) return "yes";
+ return "no";
+}
+
+/* A callback function called once for each defined libnewmail mailbox */
+void cb(const char *spool, const void*user) {
+ struct nm_spool* s = NULL;
+ struct nm_info i;
+ struct nm_status st;
+
+ /* Open this mail spool */
+ if (!(s = nm_open(spool))) {
+ fprintf(stderr, "nm_open(\"%s\"): %s\n", spool, nm_strerror(nm_errno, errno, nm_explanation));
+ goto finish;
+ }
+
+ /* Get spool information */
+ if (nm_info(s, &i) < 0) {
+ fprintf(stderr, "nm_info(\"%s\"): %s\n", spool, nm_strerror(nm_errno, errno, nm_explanation));
+ goto finish;
+ }
+
+ /* Show some information about the spool */
+ printf("\n%s:\n\tName: %s\n\tType: %s\n\tText: %s\n\tFlags: ", i.path, i.name, i.type, i.text);
+ if (i.flags & NM_FLAG_SYNCHRONOUS) printf("SYNCHRONOUS ");
+ if (i.flags & NM_FLAG_ASYNCHRONOUS) printf("ASYNCHRONOUS ");
+ printf("\n");
+
+ /* Do a status query */
+ if (nm_query(s, query, &st) < 0) {
+ fprintf(stderr, "nm_check(\"%s\"): %s\n", spool, nm_strerror(nm_errno, errno, nm_explanation));
+ goto finish;
+ }
+
+ /* Print the status query results: total number of mails */
+ if (query & NM_QUERY_NCUR)
+ printf("\tCurrent: %i\n", st.cur);
+ else if (query & NM_QUERY_CUR)
+ printf("\tCurrent: %s\n", b2s(st.cur));
+
+ /* Print the status query results: new mails */
+ if (query & NM_QUERY_NNEW)
+ printf("\tNew: %i\n", st.new);
+ else if (query & NM_QUERY_NEW)
+ printf("\tNew: %s\n", b2s(st.new));
+
+finish:
+
+ /* Close the mail spool */
+ if (s)
+ nm_close(s);
+}
+
+int main(int argc, char *argv[]) {
+
+ /* Iterate through the mail spools */
+ if (nm_list(cb, NULL) < 0)
+ nm_perror("nm_list()");
+
+ return 0;
+}
diff --git a/src/pop3.c b/src/pop3.c
new file mode 100644
index 0000000..692a427
--- /dev/null
+++ b/src/pop3.c
@@ -0,0 +1,417 @@
+/* $Id$ */
+
+/***
+ This file is part of libnewmail
+
+ libnewmail 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.
+
+ libnewmail 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 libnewmail; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ USA
+***/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include "module.h"
+#include "newmail.h"
+#include "util.h"
+#include "md5.h"
+#include "sockwrap.h"
+
+struct forkresp {
+ struct nm_status status;
+ int ret;
+ int nm_errno;
+ int system_errno;
+ char nm_explanation[128];
+};
+
+struct data {
+ char *username;
+ char *password;
+
+ char *hostname;
+ int port;
+ int tls;
+
+ oop_source *oop;
+ int fdpipe;
+ struct forkresp forkresp;
+ int nread;
+
+ int debug;
+
+ nm_query_cb_t cb;
+ void *user;
+
+ pid_t child;
+};
+
+static int _pop3_process(struct nm_spool *s, enum nm_query query, struct nm_status *status) {
+ struct sockwrap *sw = NULL;
+ struct data *data = (struct data*) s->data;
+ enum { HELLO, APOP, USER, PASS, STAT, LAST, QUIT } state = HELLO;
+ int r = -1;
+
+ status->cur = status->new = -1;
+
+ if (!(sw = sockwrap(data->hostname, data->port, data->tls)))
+ goto finish;
+
+ for (;;) {
+ int finished = 0;
+
+ static char response[128];
+ static char request[128];
+ char *apop_token = 0;
+
+ if (sockwrap_readln(sw, response, sizeof(response)) < 0) {
+ nm_error(NM_ERROR_SERVFAIL, NULL);
+ goto finish;
+ }
+
+ nm_chomp(response);
+
+ if (data->debug)
+ fprintf(stderr, "RECV: %s\n", response);
+
+ if (state != LAST && response[0] != '+') {
+ char *e;
+ if (strlen(response) >= 5)
+ e = response+5;
+ else
+ e = response;
+
+ nm_error(NM_ERROR_SERVFAIL|NM_ERROR_EXPLANATION, e);
+ goto finish;
+ }
+
+ switch (state) {
+ case HELLO:
+ if ((apop_token = strchr(response, '<'))) {
+ char *e;
+ if ((e = strchr(apop_token, '>'))) {
+ *(e+1) = 0;
+ state = APOP;
+ break;
+ }
+ }
+
+ state = USER;
+ break;
+
+ case USER:
+ state = PASS;
+ break;
+
+ case PASS:
+ case APOP:
+ state = STAT;
+ break;
+
+ case STAT:
+ if (strlen(response) < 5) {
+ nm_error(NM_ERROR_SERVFAIL, response);
+ goto finish;
+ }
+
+ status->cur = atoi(&response[4]);
+
+ state = LAST;
+ break;
+
+ case LAST:
+
+ if (response[0] == '+') {
+ int i;
+
+ if (strlen(response) < 5) {
+ nm_error(NM_ERROR_SERVFAIL, response);
+ goto finish;
+ }
+
+ i = atoi(&response[4]);
+
+ if (status->cur <= i)
+ status->new = 0;
+ else
+ status->new = status->cur - i;
+ }
+
+ state = QUIT;
+ break;
+
+ case QUIT:
+ finished = 1;
+ break;
+ }
+
+ if (finished)
+ break;
+
+
+ switch (state) {
+ case USER:
+ snprintf(request, sizeof(request), "USER %s\n", data->username);
+ break;
+
+ case PASS:
+ snprintf(request, sizeof(request), "PASS %s\n", data->password);
+ break;
+
+ case APOP: {
+ static char m[256];
+ md5_state_t st;
+ unsigned char sum[16];
+
+ md5_init(&st);
+ snprintf(m, sizeof(m), "%s%s", apop_token, data->password);
+ md5_append(&st, m, strlen(m));
+ md5_finish(&st, sum);
+
+ snprintf(request, sizeof(request),
+ "APOP %s %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", data->username,
+ sum[0], sum[1], sum[2], sum[3],
+ sum[4], sum[5], sum[6], sum[7],
+ sum[8], sum[9], sum[10], sum[11],
+ sum[12], sum[13], sum[14], sum[15]);
+ break;
+ }
+ case STAT:
+ snprintf(request, sizeof(request), "STAT\n");
+ break;
+
+ case LAST:
+ snprintf(request, sizeof(request), "LAST\n");
+ break;
+
+ case QUIT:
+ snprintf(request, sizeof(request), "QUIT\n");
+ break;
+
+ case HELLO: // Completely useless, however, this will remove GCC's warning
+ break;
+ }
+
+ if (data->debug)
+ fprintf(stderr, "SEND: %s", request);
+
+ if (sockwrap_writeln(sw, request) < 0) {
+ nm_error(NM_ERROR_SERVFAIL, NULL);
+ goto finish;
+ }
+
+ }
+
+
+ r = 0;
+
+finish:
+
+ if (sw)
+ sockwrap_close(sw);
+
+ return r;
+}
+
+static void* _callback(oop_source *source, int fd, oop_event event, void *user) {
+ struct data *data = (struct data*) ((struct nm_spool*) user)->data;
+ ssize_t r;
+
+ if ((r = read(data->fdpipe, ((char*) &data->forkresp) + data->nread, sizeof(struct forkresp)-data->nread)) < 0) {
+ nm_error(NM_ERROR_INTERNAL|NM_ERROR_SYSTEM, NULL);
+ goto fail;
+ }
+
+ data->nread += r;
+
+ if (data->nread >= sizeof(struct forkresp)) {
+
+ if (data->forkresp.nm_errno == NM_ERROR_SUCCESS) {
+ data->cb((struct nm_spool*) user, &data->forkresp.status, data->user);
+ goto finish;
+ } else {
+ nm_error(data->forkresp.nm_errno, data->forkresp.nm_explanation[0] ? data->forkresp.nm_explanation : NULL);
+ errno = data->forkresp.system_errno;
+ goto fail;
+ }
+ }
+
+ return OOP_CONTINUE;
+
+fail:
+ data->cb((struct nm_spool*) user, NULL, data->user);
+
+finish:
+
+ if (data->oop)
+ data->oop->cancel_fd(data->oop, data->fdpipe, OOP_READ);
+
+ close(data->fdpipe);
+ data->fdpipe = -1;
+
+ waitpid(data->child, 0, 0);
+ data->child = (pid_t) -1;
+
+ return OOP_CONTINUE;
+}
+
+static int _query_submit(struct nm_spool *s, enum nm_query query, oop_source* oop, nm_query_cb_t cb, void *user) {
+ struct data *data = (struct data*) s->data;
+ int pf[2] = { -1, -1};
+ pid_t pid;
+
+ if (data->fdpipe >= 0) {
+ nm_error(NM_ERROR_ALREADY, NULL);
+ goto fail;
+ }
+
+ if (pipe(pf) < 0) {
+ nm_error(NM_ERROR_FORK|NM_ERROR_SYSTEM, NULL);
+ goto fail;
+ }
+
+ if ((pid = fork()) < 0) {
+ nm_error(NM_ERROR_FORK|NM_ERROR_SYSTEM, NULL);
+ goto fail;
+ } else if (!pid) {
+ struct forkresp forkresp = { { -1, -1 }, -1, 0, 0, "" };
+ FILE *f;
+
+ signal(SIGPIPE, SIG_IGN);
+ close(pf[0]);
+
+ nm_error(NM_ERROR_SUCCESS, NULL);
+
+ if ((forkresp.ret = _pop3_process(s, query, &forkresp.status)) < 0) {
+ forkresp.system_errno = errno;
+ forkresp.nm_errno = nm_errno;
+ if (nm_explanation[0])
+ snprintf(forkresp.nm_explanation, sizeof(forkresp.nm_explanation), "%s", nm_explanation);
+ else
+ forkresp.nm_explanation[0] = 0;
+ }
+
+ f = fdopen(pf[1], "w");
+ fwrite(&forkresp, sizeof(forkresp), 1, f);
+ fclose(f);
+ close(pf[1]);
+
+ exit(0);
+ } else {
+ close(pf[1]);
+ data->fdpipe = pf[0];
+ data->nread = 0;
+
+ data->cb = cb;
+ data->user = user;
+ data->oop = oop;
+
+ data->child = pid;
+
+ oop->on_fd(oop, data->fdpipe, OOP_READ, _callback, s);
+ return 0;
+ }
+
+fail:
+
+ if (pf[0] >= 0)
+ close(pf[0]);
+ if (pf[1] >= 1)
+ close(pf[1]);
+
+ return -1;
+}
+
+static int _query(struct nm_spool *s, enum nm_query query, struct nm_status *status) {
+ struct data *data = (struct data*) s->data;
+
+ if (!s || !status) {
+ nm_error(NM_ERROR_INVPAR, NULL);
+ return -1;
+ }
+
+ if (data->fdpipe >= 0) {
+ nm_error(NM_ERROR_ALREADY, NULL);
+ return -1;
+ }
+
+ return _pop3_process(s, query, status);
+}
+
+static int _configure(struct nm_spool *s) {
+ return -1;
+}
+
+static int _info(struct nm_spool *s, struct nm_info *i) {
+ struct data *data = (struct data*) s->data;
+
+ if (data->port == 110)
+ snprintf(i->text, sizeof(i->text), "POP3 mailbox %s@%s", data->username, data->hostname);
+ else
+ snprintf(i->text, sizeof(i->text), "POP3 mailbox %s@%s:%i", data->username, data->hostname, data->port);
+
+ i->flags = NM_FLAG_ASYNCHRONOUS;
+
+ return 0;
+}
+
+static void _done(struct nm_spool *s) {
+ struct data *data = (struct data*) s->data;
+
+ if (data) {
+ if (data->fdpipe >= 0) {
+ if (data->oop)
+ data->oop->cancel_fd(data->oop, data->fdpipe, OOP_READ);
+ close(data->fdpipe);
+ }
+
+ nm_free(data->hostname);
+ nm_free(data->username);
+ nm_free(data->password);
+ nm_free(data);
+ s->data = NULL;
+ }
+}
+
+int nm_init(struct nm_spool *s) {
+ struct data *data;
+ s->query = _query;
+ s->query_submit = _query_submit;
+ s->configure = _configure;
+ s->info = _info;
+ s->done = _done;
+
+ data = nm_malloc(sizeof(struct data));
+ memset(data, 0, sizeof(struct data));
+
+ data->hostname = nm_strdup(nm_specials(nm_config_get(s->config, "Hostname", "localhost")));
+ data->username = nm_strdup(nm_specials(nm_config_get(s->config, "Username", "%u")));
+ data->password = nm_strdup(nm_config_get(s->config, "Password", "secret"));
+ data->tls = nm_config_get_bool(s->config, "UseSSL", 0) || nm_config_get_bool(s->config, "UseTLS", 0);
+ data->port = nm_config_get_int(s->config, "Port", data->tls ? 995 : 110);
+ data->debug = nm_config_get_bool(s->config, "Debug", 0);
+ data->fdpipe = -1;
+ data->child = (pid_t) -1;
+ s->data = (void*) data;
+
+ return 0;
+}
+
+
diff --git a/src/sockwrap.c b/src/sockwrap.c
new file mode 100644
index 0000000..0d18fed
--- /dev/null
+++ b/src/sockwrap.c
@@ -0,0 +1,224 @@
+/* $Id$ */
+
+/***
+ This file is part of libnewmail
+
+ libnewmail 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.
+
+ libnewmail 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 libnewmail; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ USA
+***/
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <gnutls/gnutls.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "sockwrap.h"
+#include "util.h"
+
+struct sockwrap {
+ int fd;
+ gnutls_session tls;
+ gnutls_certificate_credentials tls_cred;
+ int use_tls;
+};
+
+int _global_tls = 0;
+
+static void _atexit(void) {
+ if (_global_tls)
+ gnutls_global_deinit();
+
+ _global_tls = 0;
+}
+
+int sockwrap_readln(struct sockwrap *s, char *ln, int max) {
+ char *p = ln;
+
+ while (max > 1) {
+ ssize_t r;
+
+ if (!s->use_tls) {
+ if ((r = read(s->fd, p, 1)) <= 0)
+ return -1;
+ } else {
+ if ((r = gnutls_record_recv(s->tls, p, 1)) < 0)
+ return -1;
+ }
+
+ max -= r;
+
+ if (*p == '\n') {
+ p += r;
+ break;
+ }
+
+ p +=r;
+ }
+
+ *p = 0;
+
+ //ßfprintf(stderr, "Read %i bytes\n", p-ln);
+
+ return 0;
+}
+
+int sockwrap_writeln(struct sockwrap *s, char *ln) {
+ char *p;
+ ssize_t n;
+
+ p = ln;
+ n = strlen(p);
+ while(n > 0) {
+ ssize_t r;
+ if (!s->use_tls) {
+ if ((r = write(s->fd, p, n)) <= 0)
+ return -1;
+ } else {
+ if ((r = gnutls_record_send(s->tls, ln, n)) <= 0)
+ return -1;
+ }
+
+ n -= r;
+ p += r;
+ }
+
+ return 0;
+}
+
+struct sockwrap* sockwrap(char *host, int port, int use_tls) {
+ struct sockwrap* s = NULL;
+ struct hostent *he;
+ struct sockaddr_in sa;
+
+ if (!(s = malloc(sizeof(struct sockwrap)))) {
+ nm_error(NM_ERROR_MEMORY, NULL);
+ goto finish;
+ }
+
+ s->fd = -1;
+ s->tls = 0;
+ s->tls_cred = 0;
+ s->use_tls = use_tls;
+
+ if ((s->fd = socket(PF_INET, SOCK_STREAM, 0)) < 0)
+ goto finish;
+
+ if (!(he = gethostbyname(host))) {
+ nm_error(NM_ERROR_SERVNOTFOUND|NM_ERROR_SYSTEM, NULL);
+ goto finish;
+ }
+
+ sa.sin_family = AF_INET;
+ sa.sin_port = htons(port);
+ sa.sin_addr = *((struct in_addr *) he->h_addr);
+
+ if (connect(s->fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
+ nm_error(NM_ERROR_SERVFAIL|NM_ERROR_SYSTEM, NULL);
+ goto finish;
+ }
+
+ if (use_tls) {
+ int ret;
+
+ if (!_global_tls) {
+ if ((ret = gnutls_global_init()) != 0) {
+ nm_error(NM_ERROR_INTERNAL, gnutls_strerror(ret));
+ goto finish;
+ }
+
+ _global_tls = 1;
+ atexit(_atexit);
+ }
+
+ if ((ret = gnutls_init(&s->tls, GNUTLS_CLIENT)) != 0) {
+ nm_error(NM_ERROR_INTERNAL, gnutls_strerror(ret));
+ goto finish;
+ }
+
+ if ((ret = gnutls_set_default_priority(s->tls)) != 0) {
+ nm_error(NM_ERROR_INTERNAL, gnutls_strerror(ret));
+ goto finish;
+ }
+
+ if ((ret = gnutls_certificate_allocate_sc(&s->tls_cred)) < 0) {
+ nm_error(NM_ERROR_INTERNAL, gnutls_strerror(ret));
+ goto finish;
+ }
+
+ if ((ret = gnutls_cred_set(s->tls, GNUTLS_CRD_CERTIFICATE, s->tls_cred)) < 0) {
+ nm_error(NM_ERROR_INTERNAL, gnutls_strerror(ret));
+ goto finish;
+ }
+
+ gnutls_transport_set_ptr(s->tls, (gnutls_transport_ptr) s->fd);
+
+ if ((ret = gnutls_handshake(s->tls)) != 0) {
+ nm_error(NM_ERROR_INTERNAL, gnutls_strerror(ret));
+ goto finish;
+ }
+ }
+
+ return s;
+
+finish:
+
+ if (s && s->use_tls) {
+ if (s->tls && s->tls_cred)
+ gnutls_bye(s->tls, GNUTLS_SHUT_RDWR);
+ if (s->tls_cred)
+ gnutls_certificate_free_credentials(s->tls_cred);
+ if (s->tls)
+ gnutls_deinit(s->tls);
+
+ gnutls_global_deinit();
+ }
+
+ if (s && s->fd >= 0) {
+ shutdown(s->fd, SHUT_RDWR);
+ close(s->fd);
+ }
+
+ free(s);
+
+
+ return NULL;
+}
+
+
+void sockwrap_close(struct sockwrap *s) {
+ if (!s)
+ return;
+
+ if (s->use_tls) {
+ if (s->tls && s->tls_cred)
+ gnutls_bye(s->tls, GNUTLS_SHUT_RDWR);
+ if (s->tls_cred)
+ gnutls_certificate_free_credentials(s->tls_cred);
+ if (s->tls)
+ gnutls_deinit(s->tls);
+
+ }
+
+ if (s->fd >= 0) {
+ shutdown(s->fd, SHUT_RDWR);
+ close(s->fd);
+ }
+
+ free(s);
+}
diff --git a/src/sockwrap.h b/src/sockwrap.h
new file mode 100644
index 0000000..ad25abf
--- /dev/null
+++ b/src/sockwrap.h
@@ -0,0 +1,32 @@
+#ifndef foosockwraphfoo
+#define foosockwraphfoo
+
+/* $Id$ */
+
+/***
+ This file is part of libnewmail
+
+ libnewmail 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.
+
+ libnewmail 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 libnewmail; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ USA
+***/
+
+struct sockwrap;
+
+struct sockwrap* sockwrap(char *host, int port, int tls);
+void sockwrap_close(struct sockwrap *s);
+int sockwrap_writeln(struct sockwrap *s, char *ln);
+int sockwrap_readln(struct sockwrap *s, char *ln, int max);
+
+#endif
diff --git a/src/unix.c b/src/unix.c
new file mode 100644
index 0000000..181ff7a
--- /dev/null
+++ b/src/unix.c
@@ -0,0 +1,218 @@
+/* $Id$ */
+
+/***
+ This file is part of libnewmail
+
+ libnewmail 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.
+
+ libnewmail 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 libnewmail; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ USA
+***/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <errno.h>
+
+#include "module.h"
+#include "newmail.h"
+#include "util.h"
+
+struct data {
+ char *path;
+ enum nm_query query;
+ nm_query_cb_t cb;
+ void *user;
+ oop_source *oop;
+};
+
+static int _query(struct nm_spool *s, enum nm_query query, struct nm_status *status) {
+ struct data *data = (struct data*) s->data;
+ status->new = status->cur = -1;
+
+
+ if (query & (NM_QUERY_NCUR|NM_QUERY_NNEW)) {
+ FILE *f;
+ struct stat st;
+ int hdr=1, old=0;
+
+ if (!(f = fopen(data->path, "r"))) {
+
+ if (errno == ENOENT) {
+ status->new = status->cur = 0;
+ return 0;
+ } else {
+ nm_error(NM_ERROR_NOFILE|NM_ERROR_SYSTEM, NULL);
+ return -1;
+ }
+
+ }
+
+ if (fstat(fileno(f), &st) < 0) {
+ nm_error(NM_ERROR_NOFILE|NM_ERROR_SYSTEM, "fstat() failed");
+ fclose(f);
+ return -1;
+ }
+
+ if (!S_ISREG(st.st_mode)) {
+ nm_error(NM_ERROR_NOFILE, "Mailbox not a regular file");
+ fclose(f);
+ return -1;
+ }
+
+ status->cur = 0;
+
+ while (!feof(f)) {
+ static char ln[128];
+
+ if (!fgets(ln, sizeof(ln), f))
+ break;
+
+ if (strncmp(ln, "From ", 5) == 0) {
+ hdr = 1;
+ status->cur++;
+ } else if (hdr && strcmp(ln, "\n") == 0)
+ hdr = 0;
+ else if (hdr && strncmp(ln, "Status: ", 8) == 0) {
+ old++;
+ hdr = 0;
+ }
+ }
+
+ fclose(f);
+
+ status->new = status->cur-old;
+
+ return 0;
+
+ } else if (query & (NM_QUERY_CUR|NM_QUERY_NEW)) {
+ struct stat st;
+
+ if (stat(data->path, &st) < 0) {
+ if (errno == ENOENT) {
+ status->cur = status->new = 0;
+ return 0;
+ }
+
+ nm_error(NM_ERROR_NOFILE|NM_ERROR_SYSTEM, NULL);
+ return -1;
+ }
+
+ if (!S_ISREG(st.st_mode)) {
+ nm_error(NM_ERROR_NOFILE, "Mailbox not a regular file");
+ return -1;
+ }
+
+ status->cur = st.st_size != 0 ? 1 : 0;
+ status->new = status->cur && (st.st_atime < st.st_mtime) ? 1 : 0;
+ return 0;
+ }
+
+ return -1;
+}
+
+static void * _cb(oop_source *source, struct timeval tv, void *user) {
+ struct nm_status status;
+ struct nm_spool *s = (struct nm_spool *) user;
+ struct data *data = (struct data*) s->data;
+
+ if (_query(s, data->query, &status) < 0)
+ data->cb(s, NULL, data->user);
+ else
+ data->cb(s, &status, data->user);
+
+ data->cb = NULL;
+ data->user = NULL;
+ data->query = 0;
+ data->oop = NULL;
+
+ return OOP_CONTINUE;
+}
+
+
+static int _query_submit(struct nm_spool *s, enum nm_query query, oop_source *oop, nm_query_cb_t cb, void *user) {
+ struct data *data = (struct data*) s->data;
+
+ if (data->cb) {
+ nm_error(NM_ERROR_ALREADY, NULL);
+ return -1;
+ }
+
+ data->cb = cb;
+ data->user = user;
+ data->query = query;
+ data->oop = oop;
+
+ data->oop->on_time(data->oop, OOP_TIME_NOW, _cb, s);
+
+ return 0;
+}
+
+static int _configure(struct nm_spool *s) {
+ return -1;
+}
+
+static int _info(struct nm_spool *s, struct nm_info *i) {
+ struct data *data = (struct data*) s->data;
+
+ snprintf(i->text, sizeof(i->text), "Unix mail spool %s", data->path);
+ i->flags = NM_FLAG_SYNCHRONOUS;
+
+ return 0;
+}
+
+static void _done(struct nm_spool *s) {
+ struct data *data = (struct data*) s->data;
+
+ if (data) {
+ if (data->cb && data->oop)
+ data->oop->cancel_time(data->oop, OOP_TIME_NOW, _cb, s);
+
+ nm_free(data->path);
+ nm_free(data);
+ }
+}
+
+int nm_init(struct nm_spool *s) {
+ struct data *data;
+ char *def;
+
+ if (!(def = getenv("MAIL"))) {
+ static char fn[PATH_MAX];
+ static struct stat st;
+
+ def = fn;
+
+ snprintf(fn, sizeof(fn), "/var/mail/%s", getenv("USER"));
+ if (stat(fn, &st) < 0 || !S_ISREG(st.st_mode))
+ snprintf(fn, sizeof(fn), "/var/spool/mail/%s", getenv("USER"));
+ }
+
+ s->query = _query;
+ s->query_submit = _query_submit;
+ s->configure = _configure;
+ s->info = _info;
+ s->done = _done;
+
+ if (!s->path)
+ s->path = nm_strdup("@AUTOMATIC@.unix");
+
+ data = nm_malloc(sizeof(struct data));
+ memset(data, 0, sizeof(struct data));
+ data->path = nm_strdup(nm_specials(nm_config_get(s->config, "Path", def)));
+ s->data = (void*) data;
+ return 0;
+}
+
+
diff --git a/src/util.c b/src/util.c
new file mode 100644
index 0000000..f3eeae1
--- /dev/null
+++ b/src/util.c
@@ -0,0 +1,102 @@
+/* $Id$ */
+
+/***
+ This file is part of libnewmail
+
+ libnewmail 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.
+
+ libnewmail 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 libnewmail; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ USA
+***/
+
+#include <string.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <stdio.h>
+
+#include "util.h"
+#include "newmail.h"
+
+char* nm_chomp(char *ln) {
+ if (!ln)
+ return NULL;
+ ln[strcspn(ln, "\n\r\0")] = 0;
+ return ln;
+}
+
+char* nm_specials(const char *format) {
+ int i;
+ static char ret[PATH_MAX];
+ const char *p;
+ char *d;
+ int special=0, max;
+
+ if (!format)
+ return NULL;
+
+ max = PATH_MAX-1;
+ ret[max] = 0;
+
+ memset(ret, 0, max);
+
+ for (p = format, d = ret, i=0; *p && i < max; p++) {
+ //fprintf(stderr, "CHAR: %c [%s] %s\n", *p, ret, special ? "SPEC" : "");
+ if (special) {
+ char *a = NULL;
+ if (*p == 'u')
+ a = getenv("USER");
+ else if (*p == 'h')
+ a = getenv("HOME");
+ else if (*p == 'H') {
+ static char hn[256];
+ gethostname(a = hn, sizeof(hn));
+ }
+
+ if (a) {
+ int x;
+ special = 0;
+ strncpy(d, a, max-i);
+ x = strlen(d);
+ d += x; i += x;
+ continue;
+ }
+ } else if (*p == '%') {
+ special = 1;
+ continue;
+ }
+
+ special = 0;
+ *d = *p;
+ d++; i++;
+ }
+
+ return ret;
+}
+
+
+char *nm_strdup(const char *s) {
+ char *p;
+ if (!s)
+ return 0;
+ p = nm_malloc(strlen(s)+1);
+ return p ? strcpy(p, s) : 0;
+}
+
+void nm_error(enum nm_error en, const char* exp) {
+ nm_errno = en | (exp ? NM_ERROR_EXPLANATION : 0);
+ if (nm_explanation)
+ nm_free(nm_explanation);
+ nm_explanation = nm_strdup(exp);
+}
+
+
diff --git a/src/util.h b/src/util.h
new file mode 100644
index 0000000..155e763
--- /dev/null
+++ b/src/util.h
@@ -0,0 +1,59 @@
+#ifndef fooutilhfoo
+#define fooutilhfoo
+
+/* $Id$ */
+
+/***
+ This file is part of libnewmail
+
+ libnewmail 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.
+
+ libnewmail 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 libnewmail; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ USA
+***/
+
+/** \file
+ *
+ * Some utility functions which may be used by plugins
+ */
+
+#include "newmail.h"
+
+/** Remove all newline and carriage return characters from the end of
+ * the string
+ * @param ln The string to chomp
+ * @return The same string, chomped
+ */
+char* nm_chomp(char *ln);
+
+/** Replace all special characters like "%%h" by their respective
+ * meanings.
+ * @param format The format string to expand
+ * @return A pointer to a static memory region containing the expanded string
+ */
+char* nm_specials(const char *format);
+
+/** Like libc's strdup() but uses nm_malloc() for memory allocation
+ * @param s The string to duplicate
+ * @return A pointer to a newly allocated memory block containing the copied string */
+char *nm_strdup(const char *s);
+
+/** Set the current error condition to the given values
+ * @param en Specifies the error condition to set
+ *
+ * @param exp Specifies an explanation for the error, if sensible. May
+ * be NULL. NM_ERROR_EXPLANATION is set iff exp is not NULL.
+ */
+void nm_error(enum nm_error en, const char* exp);
+
+#endif