notmuch-deliver: Initial import

This commit is contained in:
Ali Polatel 2010-05-26 10:09:47 +03:00
parent 6a280088e6
commit af863f8c7f
32 changed files with 2431 additions and 0 deletions

41
contrib/notmuch-deliver/.gitignore vendored Normal file
View file

@ -0,0 +1,41 @@
# gitignore for notmuch-deliver
.*.swp
*~
*.[oa]
*.py[co]
tags
*.lo
*.la
.deps
.libs
Makefile.in
Makefile
gmon.out
gprof*
/INSTALL
/aclocal.m4
/autom4te.cache
/config.guess
/config.h
/config.h.in
/config.log
/config.sub
/config.status
/configure
/compile
/depcomp
/install-sh
/missing
/stamp-h1
/libtool
/ltmain.sh
m4/libtool.m4
m4/lt*.m4
src/notmuch-deliver

View file

@ -0,0 +1,340 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 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.

View file

@ -0,0 +1,8 @@
CLEANFILES= *~
MAINTAINERCLEANFILES= Makefile.in configure aclocal.m4 \
config.h config.h.in INSTALL
ACLOCAL_AMFLAGS= -I m4
AUTOMAKE_OPTIONS= dist-bzip2 no-dist-gzip std-options foreign
SUBDIRS= numlib src .
doc_DATA= README.mkd

View file

@ -0,0 +1,49 @@
## About
`notmuch-deliver` is a [maildir](http://cr.yp.to/proto/maildir.html) delivery
tool.
## Overview
`notmuch-deliver` is a [maildir](http://cr.yp.to/proto/maildir.html) delivery
tool for [notmuch](http://notmuchmail.org) mail indexer. It reads from standard
input, delivers the mail to the specified maildir and adds it to the notmuch
database. This is meant as a convenient alternative to running `notmuch new`
after mail delivery.
## Usage
Here's a simple example for [maildrop](http://www.courier-mta.org/maildrop/):
# Deliver local mail to $MAILDIR/.Local and add local tag.
if (/^From: root/:h)
{
to "|notmuch-deliver -f -t local Local"
}
# Deliver lkml mail to $MAILDIR/.Lkml, add lkml tag and remove inbox tag.
if (/^List-Id: linux-kernel@vger.kernel.org/:h)
{
to "|notmuch-deliver -f -t lkml -r inbox Lkml"
}
# Deliver the rest to $MAILDIR, adding personal tag
to "|deliver-notmuch.rb -t personal"
## Requirements
- [notmuch](http://notmuchmail.org) shared library
- [GLib](http://library.gnome.org/devel/glib/)-2.16 or newer
## Contribute
Clone [git://github.com/alip/notmuch-deliver.git](git://github.com/alip/notmuch-deliver.git).
Format patches are preferred. Either send a mail to me or poke me on IRC.
My personal e-mail address is [alip@exherbo.org](mailto:alip@exherbo.org).
I'm available on IRC as `alip` on [Freenode](http://freenode.net) and [OFTC](http://www.oftc.net).
## License
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, version 2 of the License.
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.
<!-- vim: set ft=mkd spell spelllang=en sw=4 sts=4 et : -->

View file

@ -0,0 +1,20 @@
#!/bin/sh
# vim: set sw=4 et sts=4 tw=80 :
die() {
echo "$@" >&2
exit 1
}
echo ">>> libtoolize --copy --force --automake"
libtoolize --copy --force --automake || die "libtoolize failed"
echo ">>> rm -f config.cache"
rm -f config.cache
echo ">>> aclocal -I m4"
aclocal -I m4 || die "aclocal failed"
echo ">>> autoheader"
autoheader || die "autoheader failed"
echo ">>> autoconf"
autoconf || die "autoconf failed"
echo ">>> automake --foreign --add-missing --copy"
automake --foreign --add-missing --copy || die "automake failed"

View file

@ -0,0 +1,126 @@
dnl vim: set sw=4 sts=4 ts=4 noet ft=config foldmethod=marker foldmarker={{{,}}} :
dnl {{{ Program, version
AC_PREREQ(2.59)
AC_INIT([src/main.c])
AC_CANONICAL_SYSTEM
VERSION_MAJOR=0
VERSION_MINOR=1
VERSION_FULL="$VERSION_MAJOR.$VERSION_MINOR"
VERSION="$VERSION_FULL"
AC_SUBST([VERSION_MAJOR])
AC_SUBST([VERSION_MINOR])
AC_SUBST([VERSION_FULL])
AM_INIT_AUTOMAKE(notmuch-deliver, [$VERSION_FULL])
m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])])
dnl {{{ Git revision
AC_MSG_CHECKING([for git head])
if test -d "${GIT_DIR:-${ac_top_srcdir:-./}/.git}" ; then
GITHEAD=`git describe 2>/dev/null`
if test -z ${GITHEAD} ; then
GITHEAD=`git rev-parse HEAD`
fi
if test -n "`git diff-index -m --name-only HEAD`" ; then
GITHEAD=${GITHEAD}-dirty
fi
if test -n "${GITHEAD}" ; then
GITHEAD="-${GITHEAD}"
fi
fi
AC_MSG_RESULT([$GITHEAD])
AC_SUBST([GITHEAD])
dnl }}}
dnl }}}
dnl {{{ Toolchain checks
AC_USE_SYSTEM_EXTENSIONS
AC_PROG_CC
AC_PROG_CC_C99
if test x"$ac_cv_prog_cc_c99" = x"no"; then
AC_MSG_ERROR([notmuch-deliver requires a C compiler that supports ISO C99!])
fi
AC_PROG_LIBTOOL
AC_PROG_LN_S
AC_PROG_INSTALL
AC_PROG_MAKE_SET
dnl }}}
dnl {{{ Check for headers
AC_HEADER_DIRENT
AC_HEADER_STDC
AC_HEADER_TIME
AC_HEADER_SYS_WAIT
AC_CHECK_HEADERS([sys/stat.h unistd.h sysexits.h utime.h])
dnl }}}
dnl {{{ Check for typedefs, structures and compiler characteristics
AC_C_CONST
AC_TYPE_OFF_T
AC_TYPE_SIZE_T
AC_TYPE_UID_T
AC_TYPE_PID_T
AC_STRUCT_TM
dnl }}}
dnl {{{ Check for library functions
AC_CHECK_FUNCS([setgroups initgroups symlink readlink strcasecmp utime utimes])
dnl }}}
dnl {{{ gethostname()
AC_CACHE_CHECK([for missing gethostname prototype],
maildir_cv_SYS_GETHOSTNAME,
AC_TRY_COMPILE([
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
int gethostname(int,int);
],,[maildir_cv_SYS_GETHOSTNAME=yes], [maildir_cv_SYS_GETHOSTNAME=no]))
if test x"$maildir_cv_SYS_GETHOSTNAME" = x"no" ; then
AC_DEFINE_UNQUOTED(HAS_GETHOSTNAME, 1, [Whether gethostname() is prototyped])
fi
dnl }}}
dnl {{{ Check for maildir target separator
if test "$target_os" = "cygwin" ; then
AC_DEFINE_UNQUOTED(MDIRSEP, "!", [Maildir target separator])
else
AC_DEFINE_UNQUOTED(MDIRSEP, ":", [Maildir target separator])
fi
dnl }}}
dnl {{{ Make pkg-config work
PKG_PROG_PKG_CONFIG([0.9.0])
dnl }}}
dnl {{{ Check for libraries
GLIB_REQUIRED=2.16
PKG_CHECK_MODULES([glib], [glib-2.0 >= $GLIB_REQUIRED],,
[AC_MSG_ERROR([notmuch-deliver requires glib-$GLIB_REQUIRED or newer])])
AC_CHECK_LIB(notmuch, notmuch_database_create,,
[AC_MSG_ERROR([notmuch-deliver requires notmuch mail indexing library])])
dnl }}}
dnl {{{ Extra CFLAGS
NOTMUCH_DELIVER_CFLAGS=
WANTED_CFLAGS="-Wall -W -Wextra -Wvla -Wformat=2 -Wformat-security -Wformat-nonliteral -Winit-self -Wfloat-equal -Wno-deprecated-declarations -Wmissing-declarations -Wmissing-noreturn -Wmissing-prototypes -Wredundant-decls -Wshadow -Wpointer-arith -Wstrict-prototypes -Wcast-qual -Wwrite-strings -pedantic"
for flag in $WANTED_CFLAGS ; do
AX_CHECK_COMPILER_FLAGS([$flag], [NOTMUCH_DELIVER_CFLAGS="$NOTMUCH_DELIVER_CFLAGS $flag"],)
done
AC_SUBST([NOTMUCH_DELIVER_CFLAGS])
dnl }}}
dnl {{{ Output
AM_CONFIG_HEADER(config.h)
AC_OUTPUT(
Makefile
numlib/Makefile
src/Makefile
)
dnl }}}

View file

@ -0,0 +1,74 @@
# ===========================================================================
# http://www.nongnu.org/autoconf-archive/ax_check_compiler_flags.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_CHECK_COMPILER_FLAGS(FLAGS, [ACTION-SUCCESS], [ACTION-FAILURE])
#
# DESCRIPTION
#
# Check whether the given compiler FLAGS work with the current language's
# compiler, or whether they give an error. (Warnings, however, are
# ignored.)
#
# ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on
# success/failure.
#
# LICENSE
#
# Copyright (c) 2009 Steven G. Johnson <stevenj@alum.mit.edu>
# Copyright (c) 2009 Matteo Frigo
#
# 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 3 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, see <http://www.gnu.org/licenses/>.
#
# As a special exception, the respective Autoconf Macro's copyright owner
# gives unlimited permission to copy, distribute and modify the configure
# scripts that are the output of Autoconf when processing the Macro. You
# need not follow the terms of the GNU General Public License when using
# or distributing such scripts, even though portions of the text of the
# Macro appear in them. The GNU General Public License (GPL) does govern
# all other use of the material that constitutes the Autoconf Macro.
#
# This special exception to the GPL applies to versions of the Autoconf
# Macro released by the Autoconf Archive. When you make and distribute a
# modified version of the Autoconf Macro, you may extend this special
# exception to the GPL to apply to your modified version as well.
AC_DEFUN([AX_CHECK_COMPILER_FLAGS],
[AC_PREREQ(2.59) dnl for _AC_LANG_PREFIX
AC_MSG_CHECKING([whether _AC_LANG compiler accepts $1])
dnl Some hackery here since AC_CACHE_VAL can't handle a non-literal varname:
AS_LITERAL_IF([$1],
[AC_CACHE_VAL(AS_TR_SH(ax_cv_[]_AC_LANG_ABBREV[]_flags_[$1]), [
ax_save_FLAGS=$[]_AC_LANG_PREFIX[]FLAGS
_AC_LANG_PREFIX[]FLAGS="$1"
AC_COMPILE_IFELSE([AC_LANG_PROGRAM()],
AS_TR_SH(ax_cv_[]_AC_LANG_ABBREV[]_flags_[$1])=yes,
AS_TR_SH(ax_cv_[]_AC_LANG_ABBREV[]_flags_[$1])=no)
_AC_LANG_PREFIX[]FLAGS=$ax_save_FLAGS])],
[ax_save_FLAGS=$[]_AC_LANG_PREFIX[]FLAGS
_AC_LANG_PREFIX[]FLAGS="$1"
AC_COMPILE_IFELSE([AC_LANG_PROGRAM()],
eval AS_TR_SH(ax_cv_[]_AC_LANG_ABBREV[]_flags_[$1])=yes,
eval AS_TR_SH(ax_cv_[]_AC_LANG_ABBREV[]_flags_[$1])=no)
_AC_LANG_PREFIX[]FLAGS=$ax_save_FLAGS])
eval ax_check_compiler_flags=$AS_TR_SH(ax_cv_[]_AC_LANG_ABBREV[]_flags_[$1])
AC_MSG_RESULT($ax_check_compiler_flags)
if test "x$ax_check_compiler_flags" = xyes; then
m4_default([$2], :)
else
m4_default([$3], :)
fi
])dnl AX_CHECK_COMPILER_FLAGS

View file

@ -0,0 +1,29 @@
# $Id: Makefile.am,v 1.12 2007/06/30 15:40:53 mrsam Exp $
#
# Copyright 1998 - 2004 Double Precision, Inc. See COPYING for
# distribution information.
CLEANFILES=$(noinst_DATA)
noinst_LTLIBRARIES=\
libnumlib.la
noinst_HEADERS=\
numlib.h
libnumlib_la_SOURCES=\
atotimet.c \
atouidt.c \
changeuidgid.c \
strdevt.c \
strgidt.c \
strhdevt.c \
strhinot.c \
strhpidt.c \
strhtimet.c \
strinot.c \
strofft.c \
strpidt.c \
strsize.c \
strsizet.c \
strtimet.c \
struidt.c

View file

@ -0,0 +1,14 @@
/*
** Copyright 2003 Double Precision, Inc.
** See COPYING for distribution information.
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include "numlib.h"
#include <string.h>
static const char rcsid[]="$Id: atotimet.c,v 1.1 2003/08/03 03:09:19 mrsam Exp $";
LIBMAIL_STRIMPL(time_t, libmail_strtotime_t, libmail_atotime_t)

View file

@ -0,0 +1,15 @@
/*
** Copyright 2003 Double Precision, Inc.
** See COPYING for distribution information.
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include "numlib.h"
#include <string.h>
static const char rcsid[]="$Id: atouidt.c,v 1.1 2004/01/11 02:47:33 mrsam Exp $";
LIBMAIL_STRIMPL(uid_t, libmail_strtouid_t, libmail_atouid_t)
LIBMAIL_STRIMPL(gid_t, libmail_strtogid_t, libmail_atogid_t)

View file

@ -0,0 +1,111 @@
/*
** Copyright 1998 - 2002 Double Precision, Inc. See COPYING for
** distribution information.
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include <sys/types.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <grp.h>
#include <pwd.h>
#include <errno.h>
#include "numlib.h"
static const char rcsid[]="$Id: changeuidgid.c,v 1.2 2003/01/05 04:01:17 mrsam Exp $";
void libmail_changegroup(gid_t gid)
{
if ( setgid(gid))
{
perror("setgid");
exit(1);
}
#if HAVE_SETGROUPS
if ( getuid() == 0 && setgroups(1, &gid) )
{
perror("setgroups");
exit(1);
}
#endif
}
void libmail_changeuidgid(uid_t uid, gid_t gid)
{
libmail_changegroup(gid);
if ( setuid(uid))
{
perror("setuid");
exit(1);
}
}
void libmail_changeusername(const char *uname, const gid_t *forcegrp)
{
struct passwd *pw;
uid_t changeuid;
gid_t changegid;
/* uname might be a pointer returned from a previous called to getpw(),
** and libc has a problem getting it back.
*/
char *p=malloc(strlen(uname)+1);
if (!p)
{
perror("malloc");
exit(1);
}
strcpy(p, uname);
errno=ENOENT;
if ((pw=getpwnam(p)) == 0)
{
free(p);
perror("getpwnam");
exit(1);
}
free(p);
changeuid=pw->pw_uid;
if ( !forcegrp ) forcegrp= &pw->pw_gid;
changegid= *forcegrp;
if ( setgid( changegid ))
{
perror("setgid");
exit(1);
}
#if HAVE_INITGROUPS
if ( getuid() == 0 && initgroups(pw->pw_name, changegid) )
{
perror("initgroups");
exit(1);
}
#else
#if HAVE_SETGROUPS
if ( getuid() == 0 && setgroups(1, &changegid) )
{
perror("setgroups");
exit(1);
}
#endif
#endif
if (setuid(changeuid))
{
perror("setuid");
exit(1);
}
}

View file

@ -0,0 +1,97 @@
#ifndef numlib_h
#define numlib_h
/*
** Copyright 1998 - 2003 Double Precision, Inc.
** See COPYING for distribution information.
*/
#ifdef __cplusplus
extern "C" {
#endif
static const char numlib_h_rcsid[]="$Id: numlib.h,v 1.10 2004/01/11 02:47:33 mrsam Exp $";
#ifdef HAVE_CONFIG_H
#include "config.h" /* VPATH build */
#endif
#include <sys/types.h>
#include <time.h>
#define NUMBUFSIZE 60
/* Convert various system types to decimal */
char *libmail_str_time_t(time_t, char *);
char *libmail_str_off_t(off_t, char *);
char *libmail_str_pid_t(pid_t, char *);
char *libmail_str_dev_t(dev_t, char *);
char *libmail_str_ino_t(ino_t, char *);
char *libmail_str_uid_t(uid_t, char *);
char *libmail_str_gid_t(gid_t, char *);
char *libmail_str_size_t(size_t, char *);
char *libmail_str_sizekb(unsigned long, char *); /* X Kb or X Mb */
/* Convert selected system types to hex */
char *libmail_strh_time_t(time_t, char *);
char *libmail_strh_pid_t(pid_t, char *);
char *libmail_strh_ino_t(ino_t, char *);
char *libmail_strh_dev_t(dev_t, char *);
/* And, now let's do the reverse */
time_t libmail_strtotime_t(const char **);
time_t libmail_atotime_t(const char *);
uid_t libmail_strtouid_t(const char **);
uid_t libmail_atouid_t(const char *);
gid_t libmail_strtogid_t(const char **);
gid_t libmail_atogid_t(const char *);
/* Common macros: */
#define LIBMAIL_STRIMPL(type, f1, f2) \
\
type f1(const char **p)\
{\
type n=0;\
while ( **p >= '0' && **p <= '9') n=n*10 + (char)(*(*p)++ - '0');\
return n;\
}\
\
type f2(const char *p)\
{\
return f1(&p);\
}
/*
** The following functions are used by root to reset its user and group id
** to the authenticated user's. Various functions are provided to handle
** various situations.
*/
void libmail_changegroup(gid_t); /* Set the group id only. Also clear any
** auxiliary group ids */
void libmail_changeuidgid(uid_t, gid_t);
/* Set both user id and group id. Also clear
** aux group ids */
void libmail_changeusername(const char *, const gid_t *);
/*
** Set the userid to the indicate user's. If second argument is
** not null, it points to the groupid to set. If it's null, the
** group id is taken from the passwd file. Auxiliary IDs are set
** to any aux IDs set for the user in the group file. If there are
** no aux group IDs for the user, any AUX ids are cleared.
*/
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,26 @@
/*
** Copyright 2003 Double Precision, Inc.
** See COPYING for distribution information.
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include "numlib.h"
#include <string.h>
static const char rcsid[]="$Id: strdevt.c,v 1.1 2003/01/26 03:22:40 mrsam Exp $";
char *libmail_str_dev_t(dev_t t, char *arg)
{
char buf[NUMBUFSIZE];
char *p=buf+sizeof(buf)-1;
*p=0;
do
{
*--p= '0' + (t % 10);
t=t / 10;
} while(t);
return (strcpy(arg, p));
}

View file

@ -0,0 +1,26 @@
/*
** Copyright 1998 - 2000 Double Precision, Inc.
** See COPYING for distribution information.
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include "numlib.h"
#include <string.h>
static const char rcsid[]="$Id: strgidt.c,v 1.4 2003/01/05 04:01:17 mrsam Exp $";
char *libmail_str_gid_t(gid_t t, char *arg)
{
char buf[NUMBUFSIZE];
char *p=buf+sizeof(buf)-1;
*p=0;
do
{
*--p= '0' + (t % 10);
t=t / 10;
} while(t);
return (strcpy(arg, p));
}

View file

@ -0,0 +1,29 @@
/*
** Copyright 1998 - 2003 Double Precision, Inc.
** See COPYING for distribution information.
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include "numlib.h"
#include <string.h>
static const char rcsid[]="$Id: strhdevt.c,v 1.2 2003/03/12 02:45:56 mrsam Exp $";
static const char xdigit[]="0123456789ABCDEF";
char *libmail_strh_dev_t(dev_t t, char *arg)
{
char buf[sizeof(t)*2+1];
char *p=buf+sizeof(buf)-1;
unsigned i;
*p=0;
for (i=0; i<sizeof(t)*2; i++)
{
*--p= xdigit[t & 15];
t=t / 16;
}
return (strcpy(arg, p));
}

View file

@ -0,0 +1,29 @@
/*
** Copyright 1998 - 2000 Double Precision, Inc.
** See COPYING for distribution information.
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include "numlib.h"
#include <string.h>
static const char rcsid[]="$Id: strhinot.c,v 1.5 2003/03/12 02:45:56 mrsam Exp $";
static const char xdigit[]="0123456789ABCDEF";
char *libmail_strh_ino_t(ino_t t, char *arg)
{
char buf[sizeof(t)*2+1];
char *p=buf+sizeof(buf)-1;
unsigned i;
*p=0;
for (i=0; i<sizeof(t)*2; i++)
{
*--p= xdigit[t & 15];
t=t / 16;
}
return (strcpy(arg, p));
}

View file

@ -0,0 +1,29 @@
/*
** Copyright 1998 - 2000 Double Precision, Inc.
** See COPYING for distribution information.
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include "numlib.h"
#include <string.h>
static const char rcsid[]="$Id: strhpidt.c,v 1.5 2003/03/12 02:45:56 mrsam Exp $";
static const char xdigit[]="0123456789ABCDEF";
char *libmail_strh_pid_t(pid_t t, char *arg)
{
char buf[sizeof(t)*2+1];
char *p=buf+sizeof(buf)-1;
unsigned i;
*p=0;
for (i=0; i<sizeof(t)*2; i++)
{
*--p= xdigit[t & 15];
t=t / 16;
}
return (strcpy(arg, p));
}

View file

@ -0,0 +1,29 @@
/*
** Copyright 1998 - 2000 Double Precision, Inc.
** See COPYING for distribution information.
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include "numlib.h"
#include <string.h>
static const char rcsid[]="$Id: strhtimet.c,v 1.5 2003/03/12 02:45:56 mrsam Exp $";
static const char xdigit[]="0123456789ABCDEF";
char *libmail_strh_time_t(time_t t, char *arg)
{
char buf[sizeof(t)*2+1];
char *p=buf+sizeof(buf)-1;
unsigned i;
*p=0;
for (i=0; i<sizeof(t)*2; i++)
{
*--p= xdigit[t & 15];
t=t / 16;
}
return (strcpy(arg, p));
}

View file

@ -0,0 +1,26 @@
/*
** Copyright 1998 - 2000 Double Precision, Inc.
** See COPYING for distribution information.
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include "numlib.h"
#include <string.h>
static const char rcsid[]="$Id: strinot.c,v 1.4 2003/01/05 04:01:17 mrsam Exp $";
char *libmail_str_ino_t(ino_t t, char *arg)
{
char buf[NUMBUFSIZE];
char *p=buf+sizeof(buf)-1;
*p=0;
do
{
*--p= '0' + (t % 10);
t=t / 10;
} while(t);
return (strcpy(arg, p));
}

View file

@ -0,0 +1,37 @@
/*
** Copyright 1998 - 2002 Double Precision, Inc.
** See COPYING for distribution information.
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include "numlib.h"
#include <string.h>
static const char rcsid[]="$Id: strofft.c,v 1.5 2003/01/05 04:01:17 mrsam Exp $";
char *libmail_str_off_t(off_t t, char *arg)
{
char buf[NUMBUFSIZE];
char *p=buf+sizeof(buf)-1;
int isneg=0;
if (t < 0)
{
t= -t;
isneg=1;
}
*p=0;
do
{
*--p= '0' + (t % 10);
t=t / 10;
} while(t);
if (isneg)
*--p='-';
return (strcpy(arg, p));
}

View file

@ -0,0 +1,26 @@
/*
** Copyright 1998 - 2000 Double Precision, Inc.
** See COPYING for distribution information.
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include "numlib.h"
#include <string.h>
static const char rcsid[]="$Id: strpidt.c,v 1.4 2003/01/05 04:01:17 mrsam Exp $";
char *libmail_str_pid_t(pid_t t, char *arg)
{
char buf[NUMBUFSIZE];
char *p=buf+sizeof(buf)-1;
*p=0;
do
{
*--p= '0' + (t % 10);
t=t / 10;
} while(t);
return (strcpy(arg, p));
}

View file

@ -0,0 +1,62 @@
/*
** Copyright 2001 Double Precision, Inc.
** See COPYING for distribution information.
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include "numlib.h"
#include <string.h>
static const char rcsid[]="$Id: strsize.c,v 1.2 2003/01/05 04:01:17 mrsam Exp $";
static void cat_n(char *buf, unsigned long n)
{
char bb[NUMBUFSIZE+1];
char *p=bb+sizeof(bb)-1;
*p=0;
do
{
*--p = "0123456789"[n % 10];
n=n/10;
} while (n);
strcat(buf, p);
}
char *libmail_str_sizekb(unsigned long n, char *sizebuf)
{
/* If size is less than 1K bytes, display it as 0.xK */
if (n < 1024)
{
strcpy(sizebuf, "0.");
cat_n(sizebuf, (int)(10 * n / 1024 ));
strcat(sizebuf, "K");
}
/* If size is less than 1 meg, display is as xK */
else if (n < 1024 * 1024)
{
*sizebuf=0;
cat_n(sizebuf, (unsigned long)(n+512)/1024);
strcat(sizebuf, "K");
}
/* Otherwise, display in megabytes */
else
{
unsigned long nm=(double)n / (1024.0 * 1024.0) * 10;
*sizebuf=0;
cat_n( sizebuf, nm / 10);
strcat(sizebuf, ".");
cat_n( sizebuf, nm % 10);
strcat(sizebuf, "M");
}
return (sizebuf);
}

View file

@ -0,0 +1,26 @@
/*
** Copyright 1998 - 2000 Double Precision, Inc.
** See COPYING for distribution information.
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include "numlib.h"
#include <string.h>
static const char rcsid[]="$Id: strsizet.c,v 1.4 2003/01/05 04:01:18 mrsam Exp $";
char *libmail_str_size_t(size_t t, char *arg)
{
char buf[NUMBUFSIZE];
char *p=buf+sizeof(buf)-1;
*p=0;
do
{
*--p= '0' + (t % 10);
t=t / 10;
} while(t);
return (strcpy(arg, p));
}

View file

@ -0,0 +1,26 @@
/*
** Copyright 1998 - 2000 Double Precision, Inc.
** See COPYING for distribution information.
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include "numlib.h"
#include <string.h>
static const char rcsid[]="$Id: strtimet.c,v 1.4 2003/01/05 04:01:18 mrsam Exp $";
char *libmail_str_time_t(time_t t, char *arg)
{
char buf[NUMBUFSIZE];
char *p=buf+sizeof(buf)-1;
*p=0;
do
{
*--p= '0' + (t % 10);
t=t / 10;
} while(t);
return (strcpy(arg, p));
}

View file

@ -0,0 +1,26 @@
/*
** Copyright 1998 - 2000 Double Precision, Inc.
** See COPYING for distribution information.
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include "numlib.h"
#include <string.h>
static const char rcsid[]="$Id: struidt.c,v 1.4 2003/01/05 04:01:18 mrsam Exp $";
char *libmail_str_uid_t(uid_t t, char *arg)
{
char buf[NUMBUFSIZE];
char *p=buf+sizeof(buf)-1;
*p=0;
do
{
*--p= '0' + (t % 10);
t=t / 10;
} while(t);
return (strcpy(arg, p));
}

View file

@ -0,0 +1,18 @@
DEFS+= -DGITHEAD=\"$(GITHEAD)\"
AM_CFLAGS= @NOTMUCH_DELIVER_CFLAGS@ $(glib_CFLAGS)
noinst_HEADERS=\
maildircreate.h \
maildirmisc.h
bin_PROGRAMS=\
notmuch-deliver
notmuch_deliver_SOURCES=\
maildircreate.c \
maildiropen.c \
maildirmkdir.c \
main.c
notmuch_deliver_LDADD=\
$(top_builddir)/numlib/libnumlib.la \
$(glib_LIBS)

View file

@ -0,0 +1,241 @@
/*
** Copyright 1998 - 2003 Double Precision, Inc.
** See COPYING for distribution information.
*/
#include "maildircreate.h"
#include "maildirmisc.h"
#include <sys/types.h>
#if HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#if TIME_WITH_SYS_TIME
#include <sys/time.h>
#include <time.h>
#else
#if HAVE_SYS_TIME_H
#include <sys/time.h>
#else
#include <time.h>
#endif
#endif
#if HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include "numlib/numlib.h"
static const char rcsid[]="$Id: maildircreate.c,v 1.6 2003/01/26 04:07:03 mrsam Exp $";
FILE *maildir_tmpcreate_fp(struct maildir_tmpcreate_info *info)
{
int fd=maildir_tmpcreate_fd(info);
FILE *fp;
if (fd < 0)
return NULL;
fp=fdopen(fd, "w+");
if (fp == NULL)
{
close(fd);
return NULL;
}
return fp;
}
static int maildir_tmpcreate_fd_do(struct maildir_tmpcreate_info *info);
#define KEEPTRYING (60 * 60)
#define SLEEPFOR 3
int maildir_tmpcreate_fd(struct maildir_tmpcreate_info *info)
{
int i;
if (!info->doordie)
return (maildir_tmpcreate_fd_do(info));
for (i=0; i<KEEPTRYING / SLEEPFOR; i++)
{
int fd=maildir_tmpcreate_fd_do(info);
if (fd >= 0 || errno != EAGAIN)
return fd;
sleep(SLEEPFOR);
}
return -1;
}
static int maildir_tmpcreate_fd_do(struct maildir_tmpcreate_info *info)
{
const char *maildir=info->maildir;
const char *uniq=info->uniq;
const char *hostname=info->hostname;
char hostname_buf[256];
char time_buf[NUMBUFSIZE];
char usec_buf[NUMBUFSIZE];
char pid_buf[NUMBUFSIZE];
char len_buf[NUMBUFSIZE+3];
char dev_buf[NUMBUFSIZE];
char ino_buf[NUMBUFSIZE];
struct timeval tv;
struct stat stat_buf;
int fd;
if (!maildir)
maildir=".";
if (!uniq)
uniq="";
if (!hostname || !*hostname)
{
hostname_buf[sizeof(hostname_buf)-1]=0;
if (gethostname(hostname_buf, sizeof(hostname_buf)-1) < 0)
strcpy(hostname_buf, "localhost");
hostname=hostname_buf;
}
gettimeofday(&tv, NULL);
libmail_str_time_t(tv.tv_sec, time_buf);
libmail_str_time_t(tv.tv_usec, usec_buf);
libmail_str_pid_t(getpid(), pid_buf);
len_buf[0]=0;
if (info->msgsize > 0)
{
strcpy(len_buf, ",S=");
libmail_str_size_t(info->msgsize, len_buf+3);
}
if (info->tmpname)
free(info->tmpname);
info->tmpname=malloc(strlen(maildir)+strlen(uniq)+
strlen(hostname)+strlen(time_buf)+
strlen(usec_buf)+
strlen(pid_buf)+strlen(len_buf)+100);
if (!info->tmpname)
{
maildir_tmpcreate_free(info);
return -1;
}
strcpy(info->tmpname, maildir);
strcat(info->tmpname, "/tmp/");
strcat(info->tmpname, time_buf);
strcat(info->tmpname, ".M");
strcat(info->tmpname, usec_buf);
strcat(info->tmpname, "P");
strcat(info->tmpname, pid_buf);
if (*uniq)
strcat(strcat(info->tmpname, "_"), uniq);
strcat(info->tmpname, ".");
strcat(info->tmpname, hostname);
strcat(info->tmpname, len_buf);
if (stat( info->tmpname, &stat_buf) == 0)
{
maildir_tmpcreate_free(info);
errno=EAGAIN;
return -1;
}
if (errno != ENOENT)
{
maildir_tmpcreate_free(info);
if (errno == EAGAIN)
errno=EIO;
return -1;
}
if ((fd=maildir_safeopen_stat(info->tmpname, O_CREAT|O_RDWR|O_TRUNC,
info->openmode, &stat_buf)) < 0)
{
maildir_tmpcreate_free(info);
return -1;
}
libmail_strh_dev_t(stat_buf.st_dev, dev_buf);
libmail_strh_ino_t(stat_buf.st_ino, ino_buf);
if (info->newname)
free(info->newname);
info->newname=malloc(strlen(info->tmpname)+strlen(ino_buf)+
strlen(dev_buf)+3);
if (!info->newname)
{
maildir_tmpcreate_free(info);
unlink(info->tmpname);
close(fd);
if (errno == EAGAIN)
errno=EIO;
return -1;
}
strcpy(info->newname, maildir);
strcat(info->newname, "/new/");
strcat(info->newname, time_buf);
strcat(info->newname, ".M");
strcat(info->newname, usec_buf);
strcat(info->newname, "P");
strcat(info->newname, pid_buf);
strcat(info->newname, "V");
strcat(info->newname, dev_buf);
strcat(info->newname, "I");
strcat(info->newname, ino_buf);
if (*uniq)
strcat(strcat(info->newname, "_"), uniq);
strcat(info->newname, ".");
strcat(info->newname, hostname);
strcat(info->newname, len_buf);
return fd;
}
void maildir_tmpcreate_free(struct maildir_tmpcreate_info *info)
{
if (info->tmpname)
free(info->tmpname);
info->tmpname=NULL;
if (info->newname)
free(info->newname);
info->newname=NULL;
}
int maildir_movetmpnew(const char *tmpname, const char *newname)
{
if (link(tmpname, newname) == 0)
{
unlink(tmpname);
return 0;
}
if (errno != EXDEV)
return -1;
/* AFS? */
return rename(tmpname, newname);
}

View file

@ -0,0 +1,52 @@
#ifndef maildircreate_h
#define maildircreate_h
/*
** Copyright 1998 - 2003 Double Precision, Inc.
** See COPYING for distribution information.
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#ifdef __cplusplus
extern "C" {
#endif
static const char maildircreate_h_rcsid[]="$Id: maildircreate.h,v 1.10 2006/10/29 00:03:53 mrsam Exp $";
/* Create messages in maildirs */
struct maildir_tmpcreate_info {
const char *maildir;
unsigned long msgsize; /* If known, 0 otherwise (must use requota later)*/
const char *uniq; /* You need when creating multiple msgs */
const char *hostname; /* If known, NULL otherwise */
int openmode; /* Default open mode */
int doordie; /* Loop until we get it right. */
char *tmpname; /* On exit, filename in tmp */
char *newname; /* On exit, filename in new */
};
#define maildir_tmpcreate_init(i) \
do \
{ \
memset( (i), 0, sizeof(*(i))); \
(i)->openmode=0644; \
} while(0)
int maildir_tmpcreate_fd(struct maildir_tmpcreate_info *);
FILE *maildir_tmpcreate_fp(struct maildir_tmpcreate_info *);
void maildir_tmpcreate_free(struct maildir_tmpcreate_info *);
/* Move created message from tmp to new */
int maildir_movetmpnew(const char *tmpname, const char *newname);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,202 @@
#ifndef maildirmisc_h
#define maildirmisc_h
/*
** Copyright 2000-2003 Double Precision, Inc.
** See COPYING for distribution information.
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#if HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif
static const char maildirmisc_h_rcsid[]="$Id: maildirmisc.h,v 1.18 2006/07/22 02:48:15 mrsam Exp $";
/*
**
** Miscellaneous maildir-related code
**
*/
/* Some special folders */
#define INBOX "INBOX"
#define DRAFTS "Drafts"
#define SENT "Sent"
#define TRASH "Trash"
#define SHARED "shared"
#define SHAREDSUBDIR "shared-folders"
#define NEWSHAREDSP "#shared"
#define NEWSHARED "#shared."
#define PUBLIC "public" /* SMAP */
int maildir_make(const char *maildir, int perm, int subdirperm,
int folder);
int maildir_del(const char *maildir);
int maildir_del_content(const char *maildir);
char *maildir_name2dir(const char *maildir, /* DIR location */
const char *foldername); /* INBOX.name */
char *maildir_location(const char *homedir,
const char *maildir);
/*
** Homedir is the account's home directory, "maildir" is where the account's
** default Maildir is configured to be (usually "./Maildir"). Combine the
** two to produce an absolute pathname.
*/
char *maildir_folderdir(const char *, /* maildir */
const char *); /* folder name */
/* Returns the directory corresponding to foldername (foldername is
** checked to make sure that it's a valid name, else we set errno
** to EINVAL, and return (0).
*/
char *maildir_filename(const char *, /* maildir */
const char *, /* folder */
const char *); /* filename */
/*
** Builds the filename to this message, suitable for opening.
** If the file doesn't appear to be there, search the maildir to
** see if someone changed the flags, and return the current filename.
*/
int maildir_safeopen(const char *, /* filename */
int, /* mode */
int); /* perm */
/*
** Same arguments as open(). When we're accessing a shared maildir,
** prevent someone from playing cute and dumping a bunch of symlinks
** in there. This function will open the indicate file only if the
** last component is not a symlink.
** This is implemented by opening the file with O_NONBLOCK (to prevent
** a DOS attack of someone pointing the symlink to a pipe, causing
** the open to hang), clearing O_NONBLOCK, then stat-int the file
** descriptor, lstating the filename, and making sure that dev/ino
** match.
*/
int maildir_semisafeopen(const char *, /* filename */
int, /* mode */
int); /* perm */
/*
** Same thing, except that we allow ONE level of soft link indirection,
** because we're reading from our own maildir, which points to the
** message in the sharable maildir.
*/
int maildir_safeopen_stat(const char *path, int mode, int perm,
struct stat *stat1);
/* Sane as maildir_safeopen(), except that we also initialize a
** struct stat, saving an extra syscall to the caller.
*/
int maildir_mkdir(const char *); /* directory */
/*
** Create maildir including all subdirectories in the path (like mkdir -p)
*/
void maildir_purgetmp(const char *); /* maildir */
/* purges old stuff out of tmp */
void maildir_purge(const char *, /* directory */
unsigned); /* time_t to purge */
void maildir_getnew(const char *, /* maildir */
const char *, /* folder */
void (*)(const char *, void *), /* Callback function for
** every moved msg.
*/
void *arg); /* Passthrough callback arg */
/* move messages from new to cur */
int maildir_deletefolder(const char *, /* maildir */
const char *); /* folder */
/* deletes a folder */
void maildir_list(const char *maildir,
void (*func)(const char *, void *),
void *voidp);
void maildir_list_sharable(const char *, /* maildir */
void (*)(const char *, void *), /* callback function */
void *); /* 2nd arg to callback func */
/* list sharable folders */
int maildir_shared_subscribe(const char *, /* maildir */
const char *); /* folder */
/* subscribe to a shared folder */
void maildir_list_shared(const char *, /* maildir */
void (*)(const char *, void *), /* callback function */
void *); /* 2nd arg to the callback func */
/* list subscribed folders */
int maildir_shared_unsubscribe(const char *, /* maildir */
const char *); /* folder */
/* unsubscribe from a shared folder */
char *maildir_shareddir(const char *, /* maildir */
const char *); /* folder */
/*
** Validate and return a path to a shared folder. folderdir must be
** a name of a valid shared folder.
*/
void maildir_shared_sync(const char *); /* maildir */
/* "sync" the shared folder */
int maildir_sharedisro(const char *); /* maildir */
/* maildir is a shared read-only folder */
int maildir_unlinksharedmsg(const char *); /* filename */
/* Remove a message from a shared folder */
/* Internal function that reads a symlink */
char *maildir_getlink(const char *);
/* Determine whether the maildir filename has a certain flag */
int maildir_hasflag(const char *filename, char);
#define MAILDIR_DELETED(f) maildir_hasflag((f), 'T')
/*
** Hierarchical maildir rename.
*/
#define MAILDIR_RENAME_FOLDER 1
#define MAILDIR_RENAME_SUBFOLDERS 2
int maildir_rename(const char *maildir, /* Path to the maildir */
const char *oldname, /* .foldername */
const char *newname, /* .foldername */
int flags, /* See above */
void (*callback_func)(const char *old_path,
const char *new_path)
);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,78 @@
/*
** Copyright 2000 Double Precision, Inc.
** See COPYING for distribution information.
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <stdlib.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <errno.h>
#include "maildirmisc.h"
static const char rcsid[]="$Id: maildirmkdir.c,v 1.2 2002/03/15 03:09:21 mrsam Exp $";
int maildir_mkdir(const char *dir)
{
char *buf, *p;
size_t l;
if (dir == 0 || dir[0] == 0)
{
errno = EINVAL;
return (-1);
}
l = strlen(dir);
if ((buf = malloc(l + sizeof("/tmp"))) == 0)
{
errno = ENOMEM;
return (-1);
}
strcpy(buf, dir);
strcpy(buf+l, "/cur");
/* We do mkdir -p here */
p = buf+1;
while ((p = strchr(p, '/')) != 0)
{
*p = '\0';
if (mkdir(buf, 0700) < 0 && errno != EEXIST)
{
free(buf);
return (-1);
}
*p++ = '/';
}
if (mkdir(buf, 0700) < 0 && errno != EEXIST) {
free(buf);
return (-1);
}
strcpy(buf+l, "/new");
if (mkdir(buf, 0700) < 0 && errno != EEXIST) {
free(buf);
return (-1);
}
/*
* make /tmp last because this is the one we open first -
* the existence of this directory implies the whole
* Maildir structure is complete
*/
strcpy(buf+l, "/tmp");
if (mkdir(buf, 0700) < 0 && errno != EEXIST) {
free(buf);
return (-1);
}
free(buf);
return (0);
}

View file

@ -0,0 +1,141 @@
/*
** Copyright 2000 Double Precision, Inc.
** See COPYING for distribution information.
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <stdio.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include "maildirmisc.h"
static const char rcsid[]="$Id: maildiropen.c,v 1.8 2003/01/19 16:39:52 mrsam Exp $";
char *maildir_getlink(const char *filename)
{
#if HAVE_READLINK
size_t bufsiz;
char *buf;
bufsiz=0;
buf=0;
for (;;)
{
int n;
if (buf) free(buf);
bufsiz += 256;
if ((buf=malloc(bufsiz)) == 0)
{
perror("malloc");
return (0);
}
if ((n=readlink(filename, buf, bufsiz)) < 0)
{
free(buf);
return (0);
}
if (n < bufsiz)
{
buf[n]=0;
break;
}
}
return (buf);
#else
return (0);
#endif
}
int maildir_semisafeopen(const char *path, int mode, int perm)
{
#if HAVE_READLINK
char *l=maildir_getlink(path);
if (l)
{
int f;
if (*l != '/')
{
char *q=malloc(strlen(path)+strlen(l)+2);
char *s;
if (!q)
{
free(l);
return (-1);
}
strcpy(q, path);
if ((s=strchr(q, '/')) != 0)
s[1]=0;
else *q=0;
strcat(q, l);
free(l);
l=q;
}
f=maildir_safeopen(l, mode, perm);
free(l);
return (f);
}
#endif
return (maildir_safeopen(path, mode, perm));
}
int maildir_safeopen(const char *path, int mode, int perm)
{
struct stat stat1;
return maildir_safeopen_stat(path, mode, perm, &stat1);
}
int maildir_safeopen_stat(const char *path, int mode, int perm,
struct stat *stat1)
{
struct stat stat2;
int fd=open(path, mode
#ifdef O_NONBLOCK
| O_NONBLOCK
#else
| O_NDELAY
#endif
, perm);
if (fd < 0) return (fd);
if (fcntl(fd, F_SETFL, (mode & O_APPEND)) || fstat(fd, stat1)
|| lstat(path, &stat2))
{
close(fd);
return (-1);
}
if (stat1->st_dev != stat2.st_dev || stat1->st_ino != stat2.st_ino)
{
close(fd);
errno=ENOENT;
return (-1);
}
return (fd);
}

View file

@ -0,0 +1,378 @@
/* vim: set cino= fo=croql sw=8 ts=8 sts=0 noet cin fdm=syntax : */
/*
* Copyright (c) 2010 Ali Polatel <alip@exherbo.org>
* Based in part upon deliverquota of maildrop which is:
* Copyright 1998 - 2009 Double Precision, Inc.
*
* This file is part of the notmuch-deliver. notmuch-deliver is free software;
* you can redistribute it and/or modify it under the terms of the GNU General
* Public License version 2, as published by the Free Software Foundation.
*
* notmuch-deliver 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
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#ifdef HAVE_SYSEXITS_H
#include <sysexits.h>
#endif
#include <glib.h>
#include <notmuch.h>
#include "maildircreate.h"
#include "maildirmisc.h"
#ifndef EX_USAGE
#define EX_USAGE 64
#endif
#ifndef EX_SOFTWARE
#define EX_SOFTWARE 70
#endif
#ifndef EX_OSERR
#define EX_OSERR 71
#endif
#ifndef EX_IOERR
#define EX_IOERR 74
#endif
#ifndef EX_TEMPFAIL
#define EX_TEMPFAIL 75
#endif
#ifndef EX_NOPERM
#define EX_NOPERM 77
#endif
#ifndef EX_CONFIG
#define EX_CONFIG 78
#endif
static gboolean opt_create, opt_fatal, opt_folder, opt_version;
static gboolean opt_verbose = FALSE;
static gchar **opt_tags = NULL;
static gchar **opt_rtags = NULL;
static GOptionEntry options[] = {
{"version", 'V', 0, G_OPTION_ARG_NONE, &opt_version,
"Display version", NULL},
{"verbose", 'v', 0, G_OPTION_ARG_NONE, &opt_verbose,
"Be verbose (useful for debugging)", NULL},
{"create", 'c', 0, G_OPTION_ARG_NONE, &opt_create,
"Create the maildir if it doesn't exist", NULL},
{"folder", 'f', 0, G_OPTION_ARG_NONE, &opt_folder,
"Add a dot before FOLDER, e.g: Local => $MAILDIR/.Local", NULL},
{"tag", 't', 0, G_OPTION_ARG_STRING_ARRAY, &opt_tags,
"Add a tag to the message, may be specified multiple times", "TAG"},
{"remove-tag", 'r', 0, G_OPTION_ARG_STRING_ARRAY, &opt_rtags,
"Remove a tag from the message, may be specified multiple times", "TAG"},
{"fatal-add", 0, 0, G_OPTION_ARG_NONE, &opt_fatal,
"If adding the mail to the database fails, unlink it and return non-zero", NULL},
{NULL, 0, 0, 0, NULL, NULL, NULL},
};
static void
about(void)
{
printf(PACKAGE"-"VERSION GITHEAD "\n");
}
static void
log_handler(G_GNUC_UNUSED const gchar *domain, GLogLevelFlags level,
const gchar *message, G_GNUC_UNUSED gpointer user_data)
{
g_return_if_fail(message != NULL && message[0] != '\0');
if (!opt_verbose && (level & G_LOG_LEVEL_DEBUG))
return;
g_printerr(PACKAGE": %s\n", message);
}
static gboolean
load_keyfile(const gchar *path, gchar **db_path, gchar ***tags)
{
GKeyFile *fd;
GError *error;
fd = g_key_file_new();
error = NULL;
if (!g_key_file_load_from_file(fd, path, G_KEY_FILE_NONE, &error)) {
g_printerr("Failed to parse `%s': %s", path, error->message);
g_error_free(error);
g_key_file_free(fd);
return FALSE;
}
*db_path = g_key_file_get_string(fd, "database", "path", &error);
if (*db_path == NULL) {
g_critical("Failed to parse database.path from `%s': %s", path, error->message);
g_error_free(error);
g_key_file_free(fd);
return FALSE;
}
*tags = g_key_file_get_string_list(fd, "new", "tags", NULL, NULL);
g_key_file_free(fd);
return TRUE;
}
static int
save_maildir(int fdin, const char *dir, int auto_create, char **path)
{
int fd, ret, written;
char buf[4096], *p;
struct maildir_tmpcreate_info info;
maildir_tmpcreate_init(&info);
info.openmode = 0666;
info.maildir = dir;
info.doordie = 1;
while ((fd = maildir_tmpcreate_fd(&info)) < 0)
{
if (errno == ENOENT && auto_create && maildir_mkdir(dir) == 0)
{
auto_create = 0;
continue;
}
g_critical("Failed to create temporary file `%s': %s",
info.tmpname, g_strerror(errno));
return EX_TEMPFAIL;
}
g_debug("Reading from standard input and writing to `%s'", info.tmpname);
for (;;) {
ret = read(fdin, buf, 4096);
if (!ret)
break;
if (ret < 0) {
if (errno == EINTR)
continue;
g_critical("Reading from standard input failed: %s", g_strerror(errno));
goto fail;
}
p = buf;
do {
written = write(fd, p, ret);
if (!written)
goto fail;
if (written < 0) {
if (errno == EINTR)
continue;
g_critical("Writing to temporary file `%s' failed: %s",
info.tmpname, g_strerror(errno));
goto fail;
}
p += written;
ret -= written;
} while (ret);
}
close(fd);
g_debug("Moving `%s' to `%s'", info.tmpname, info.newname);
if (maildir_movetmpnew(info.tmpname, info.newname)) {
g_critical("Moving `%s' to `%s' failed: %s",
info.tmpname, info.newname, g_strerror(errno));
unlink(info.tmpname);
return EX_IOERR;
}
if (path)
*path = g_strdup(info.newname);
maildir_tmpcreate_free(&info);
return 0;
fail:
g_debug("Unlinking `%s'", info.tmpname);
unlink(info.tmpname);
return EX_IOERR;
}
static int
add_tags(notmuch_message_t *message, char **tags)
{
unsigned i;
notmuch_status_t ret;
if (!tags)
return 0;
for (i = 0; tags[i]; i++) {
ret = notmuch_message_add_tag(message, tags[i]);
if (ret != NOTMUCH_STATUS_SUCCESS)
g_warning("Failed to add tag `%s': %s",
tags[i], notmuch_status_to_string(ret));
}
return i;
}
static int
rm_tags(notmuch_message_t *message, char **tags)
{
unsigned i;
notmuch_status_t ret;
if (!tags)
return 0;
for (i = 0; tags[i]; i++) {
ret = notmuch_message_remove_tag(message, tags[i]);
if (ret != NOTMUCH_STATUS_SUCCESS)
g_warning("Failed to remove tag `%s': %s",
tags[i], notmuch_status_to_string(ret));
}
return i;
}
static int
save_database(notmuch_database_t *db, const char *path, char **default_tags)
{
notmuch_status_t ret;
notmuch_message_t *message;
g_debug("Adding `%s' to notmuch database", path);
ret = notmuch_database_add_message(db, path, &message);
switch (ret) {
case NOTMUCH_STATUS_SUCCESS:
break;
case NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID:
return 0;
default:
g_warning("Failed to add `%s' to notmuch database: %s",
path, notmuch_status_to_string(ret));
return EX_SOFTWARE;
}
g_debug("Message isn't a duplicate, adding tags");
add_tags(message, default_tags);
add_tags(message, opt_tags);
rm_tags(message, opt_rtags);
return 0;
}
int
main(int argc, char **argv)
{
int ret;
gchar *conf_path, *db_path, *folder, *maildir, *mail;
gchar **conf_tags;
GOptionContext *ctx;
GError *error = NULL;
notmuch_database_t *db;
ctx = g_option_context_new("[FOLDER]");
g_option_context_add_main_entries(ctx, options, PACKAGE);
g_option_context_set_summary(ctx, PACKAGE"-"VERSION GITHEAD" - notmuch delivery tool");
g_option_context_set_description(ctx,
"\nConfiguration:\n"
" "PACKAGE" uses notmuch's configuration file to determine database path and\n"
"initial tags to add to new messages. You may set NOTMUCH_CONFIG environment\n"
"variable to specify an alternative configuration file.\n"
"\nExit codes:\n"
" 0 => Successful run\n"
" 64 => Usage error\n"
" 70 => Failed to open the database\n"
" (or to add to the database if --fatal-add is specified)\n"
" 71 => Input output errors\n"
" (failed to read from standard input)\n"
" (failed to write to temporary file)\n"
" 76 => Failed to open/create maildir\n"
" 78 => Configuration error (wrt .notmuch-config\n");
g_log_set_default_handler(log_handler, NULL);
if (!g_option_context_parse(ctx, &argc, &argv, &error)) {
g_critical("Option parsing failed: %s", error->message);
g_option_context_free(ctx);
g_error_free(error);
return EX_USAGE;
}
g_option_context_free(ctx);
if (opt_version) {
about();
return 0;
}
if (g_getenv("NOTMUCH_CONFIG"))
conf_path = g_strdup(g_getenv("NOTMUCH_CONFIG"));
else if (g_getenv("HOME"))
conf_path = g_build_filename(g_getenv("HOME"), ".notmuch-config", NULL);
else {
g_critical("Neither NOTMUCH_CONFIG nor HOME set");
return EX_USAGE;
}
db_path = NULL;
conf_tags = NULL;
g_debug("Parsing configuration from `%s'", conf_path);
if (!load_keyfile(conf_path, &db_path, &conf_tags)) {
g_free(conf_path);
return EX_CONFIG;
}
g_free(conf_path);
if (argc > 1) {
folder = g_strdup_printf("%s%s", opt_folder ? "." : "", argv[1]);
maildir = g_build_filename(db_path, folder, NULL);
g_free(folder);
}
else
maildir = g_strdup(db_path);
g_debug("Opening notmuch database `%s'", db_path);
db = notmuch_database_open(db_path, NOTMUCH_DATABASE_MODE_READ_WRITE);
g_free(db_path);
if (db == NULL)
return EX_SOFTWARE;
if (notmuch_database_needs_upgrade(db)) {
g_message("Upgrading database");
notmuch_database_upgrade(db, NULL, NULL);
}
g_debug("Opening maildir `%s'", maildir);
if ((ret = save_maildir(STDIN_FILENO, maildir, opt_create, &mail)) != 0) {
g_free(maildir);
return ret;
}
g_free(maildir);
if ((ret = save_database(db, mail, conf_tags)) != 0 && opt_fatal) {
unlink(mail);
return ret;
}
g_strfreev(conf_tags);
g_strfreev(opt_tags);
g_strfreev(opt_rtags);
g_free(mail);
notmuch_database_close(db);
return 0;
}