summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AUTHORS1
-rw-r--r--BUGS4
-rw-r--r--COPYING340
-rw-r--r--ChangeLog510
-rw-r--r--HOWTO41
-rw-r--r--INSTALL182
-rw-r--r--Makefile.am28
-rw-r--r--Makefile.in381
-rw-r--r--NEWS187
-rw-r--r--README18
-rw-r--r--TODO5
-rw-r--r--YEAR200010
-rw-r--r--acconfig.h21
-rw-r--r--acinclude.m4133
-rw-r--r--aclocal.m4276
-rw-r--r--config.h.in67
-rwxr-xr-xconfigure2777
-rw-r--r--configure.in53
-rw-r--r--doc/Makefile.am8
-rw-r--r--doc/Makefile.in291
-rw-r--r--doc/diagram21
-rw-r--r--doc/nullmailer-inject.1240
-rw-r--r--doc/nullmailer-queue.851
-rw-r--r--doc/nullmailer-send.872
-rw-r--r--doc/nullmailer.730
-rw-r--r--doc/sendmail.175
-rwxr-xr-xinstall-sh251
-rw-r--r--lib/Makefile.am39
-rw-r--r--lib/Makefile.in408
-rw-r--r--lib/ac/dirent.h17
-rw-r--r--lib/ac/time.h10
-rw-r--r--lib/ac/wait.h10
-rw-r--r--lib/address.cc644
-rw-r--r--lib/address.h8
-rw-r--r--lib/canonicalize.cc40
-rw-r--r--lib/canonicalize.h7
-rw-r--r--lib/cli/ChangeLog119
-rw-r--r--lib/cli/Makefile.am9
-rw-r--r--lib/cli/Makefile.in277
-rw-r--r--lib/cli/cli.h59
-rw-r--r--lib/cli/cli2pod.pl213
-rw-r--r--lib/cli/clitest.cc47
-rw-r--r--lib/cli/main.cc342
-rw-r--r--lib/cli/messages.cc44
-rw-r--r--lib/config_read.cc36
-rw-r--r--lib/config_readint.cc36
-rw-r--r--lib/config_readlist.cc44
-rw-r--r--lib/configio.h11
-rw-r--r--lib/connect.h8
-rw-r--r--lib/defines.h13
-rw-r--r--lib/errcodes.cc45
-rw-r--r--lib/errcodes.h26
-rw-r--r--lib/fdbuf/ChangeLog161
-rw-r--r--lib/fdbuf/Makefile.am22
-rw-r--r--lib/fdbuf/Makefile.in301
-rw-r--r--lib/fdbuf/fdbuf.cc107
-rw-r--r--lib/fdbuf/fdbuf.h82
-rw-r--r--lib/fdbuf/fdbuf_copy.cc38
-rw-r--r--lib/fdbuf/fdibuf.cc192
-rw-r--r--lib/fdbuf/fdibuf.h50
-rw-r--r--lib/fdbuf/fdibuf_mystring.cc52
-rw-r--r--lib/fdbuf/fdibuf_netstring.cc41
-rw-r--r--lib/fdbuf/fdobuf.cc209
-rw-r--r--lib/fdbuf/fdobuf.h89
-rw-r--r--lib/fdbuf/fdobuf_chownmod.cc34
-rw-r--r--lib/fdbuf/fdobuf_seek.cc48
-rw-r--r--lib/fdbuf/fdobuf_signed.cc38
-rw-r--r--lib/fdbuf/fdobuf_unsigned.cc34
-rw-r--r--lib/hostname.cc85
-rw-r--r--lib/hostname.h7
-rw-r--r--lib/itoa.cc23
-rw-r--r--lib/itoa.h11
-rw-r--r--lib/list.h196
-rw-r--r--lib/listtest.cc50
-rw-r--r--lib/make_defines.sh9
-rw-r--r--lib/makefield.cc71
-rw-r--r--lib/mergelib.sh16
-rw-r--r--lib/mystring/ChangeLog116
-rw-r--r--lib/mystring/Makefile.am25
-rw-r--r--lib/mystring/Makefile.in310
-rw-r--r--lib/mystring/append.cc19
-rw-r--r--lib/mystring/assign.cc55
-rw-r--r--lib/mystring/count.cc25
-rw-r--r--lib/mystring/fdobuf.cc9
-rw-r--r--lib/mystring/find_first_ch.cc11
-rw-r--r--lib/mystring/find_first_of.cc22
-rw-r--r--lib/mystring/find_last_ch.cc14
-rw-r--r--lib/mystring/find_last_of.cc24
-rw-r--r--lib/mystring/iter.cc48
-rw-r--r--lib/mystring/iter.h38
-rw-r--r--lib/mystring/join.cc61
-rw-r--r--lib/mystring/join.h75
-rw-r--r--lib/mystring/lower.cc19
-rw-r--r--lib/mystring/lstrip.cc10
-rw-r--r--lib/mystring/mystring.cc28
-rw-r--r--lib/mystring/mystring.h125
-rw-r--r--lib/mystring/rep.cc157
-rw-r--r--lib/mystring/rep.h46
-rw-r--r--lib/mystring/rstrip.cc10
-rw-r--r--lib/mystring/strip.cc13
-rw-r--r--lib/mystring/sub.cc37
-rw-r--r--lib/mystring/subst.cc18
-rw-r--r--lib/mystring/trace.h10
-rw-r--r--lib/mystring/upper.cc21
-rw-r--r--lib/netstring.cc13
-rw-r--r--lib/netstring.h8
-rw-r--r--lib/tcpconnect.cc68
-rwxr-xr-xmissing190
-rwxr-xr-xmkinstalldirs40
-rw-r--r--nullmailer-1.00RC5.spec85
-rw-r--r--protocols/Makefile.am11
-rw-r--r--protocols/Makefile.in312
-rw-r--r--protocols/protocol.cc52
-rw-r--r--protocols/protocol.h12
-rw-r--r--protocols/qmqp.cc134
-rw-r--r--protocols/smtp.cc149
-rw-r--r--scripts/CVS/Entries3
-rw-r--r--scripts/CVS/Repository1
-rw-r--r--scripts/CVS/Root1
-rwxr-xr-xscripts/nullmailer-log.run2
-rwxr-xr-xscripts/nullmailer.run2
-rw-r--r--src/Makefile.am28
-rw-r--r--src/Makefile.in381
-rw-r--r--src/inject.cc581
-rw-r--r--src/mailq.cc59
-rw-r--r--src/queue.cc200
-rw-r--r--src/send.cc316
-rw-r--r--src/sendmail.cc136
-rw-r--r--stamp-h.in1
-rw-r--r--test/Makefile.am24
-rw-r--r--test/Makefile.in294
-rw-r--r--test/address-test.cc182
-rw-r--r--test/address-trace.cc2
-rw-r--r--test/tests/CVS/Entries3
-rw-r--r--test/tests/CVS/Repository1
-rw-r--r--test/tests/CVS/Root1
-rw-r--r--test/tests/inject/CVS/Entries8
-rw-r--r--test/tests/inject/CVS/Repository1
-rw-r--r--test/tests/inject/CVS/Root1
-rw-r--r--test/tests/inject/bad-headers15
-rw-r--r--test/tests/inject/copy19
-rw-r--r--test/tests/inject/date12
-rw-r--r--test/tests/inject/from66
-rw-r--r--test/tests/inject/headers22
-rw-r--r--test/tests/inject/message-id24
-rw-r--r--test/tests/inject/recips50
-rw-r--r--test/tests/inject/return-path9
-rw-r--r--test/tests/inject/sender76
-rw-r--r--test/tests/protocols44
-rw-r--r--test/tests/queue/CVS/Entries2
-rw-r--r--test/tests/queue/CVS/Repository1
-rw-r--r--test/tests/queue/CVS/Root1
-rw-r--r--test/tests/queue/rewrite45
153 files changed, 15585 insertions, 0 deletions
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..56dd0b0
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1 @@
+Bruce Guenter <bruceg@em.ca>
diff --git a/BUGS b/BUGS
new file mode 100644
index 0000000..e69139e
--- /dev/null
+++ b/BUGS
@@ -0,0 +1,4 @@
+If you find anything in these programs that you would consider a bug,
+please report it immediately to:
+ Bruce Guenter <bruceg@em.ca>
+Thank you!
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..d60c31a
--- /dev/null
+++ b/COPYING
@@ -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/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..1d87298
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,510 @@
+2000-10-05 Bruce Guenter <bruce@bruce-guenter.dyndns.org>
+
+ * lib/hostname.cc: Fixed the prototype for getdomainname.
+
+2000-10-02 Bruce Guenter <bruce@bruce-guenter.dyndns.org>
+
+ * protocols/smtp.cc (docmd): Return proper error codes for
+ permanent and temporary SMTP failures.
+
+2000-08-28 Bruce Guenter <bruce@bruce-guenter.dyndns.org>
+
+ * Released version 1.00RC4
+
+ * lib/address.cc (RULE(domain)): Modified to handle (and strip) a
+ trailing period in the domain name.
+
+2000-08-15 Bruce Guenter <bruce@bruce-guenter.dyndns.org>
+
+ * lib/hostname.cc (getnames): Added an extern declaration of
+ getdomainname for systems that don't declare it.
+
+2000-08-10 Bruce Guenter <bruce@bruce-guenter.dyndns.org>
+
+ * Released version 1.00RC3
+
+ * src/inject.cc (read_header): Fixed header parsing logic.
+
+2000-08-07 Bruce Guenter <bruce@bruce-guenter.dyndns.org>
+
+ * src/inject.cc: Treat the first non-header line as the first line
+ of the body.
+
+ * src/sendmail.cc: Ignore the -L option (set the identifier for
+ syslog messages).
+
+2000-07-12 Bruce Guenter <bruce@bruce-guenter.dyndns.org>
+
+ * src/send.cc: Added code to handle buggy named pipes that require
+ both a reader and a writer to be opened simultaneously.
+
+ * lib/tcpconnect.cc (tcpconnect): AF_INET should have been PF_INET
+ in call to socket. Also, the sin_family needed to be set to
+ AF_INET.
+
+2000-07-03 Bruce Guenter <bruce@bruce-guenter.dyndns.org>
+
+ * lib/hostname.cc (getnames): Fixed typo that caused systems
+ without "domainname" in struct utsname to fail to compile.
+
+2000-06-28 Bruce Guenter <bruce@bruce-guenter.dyndns.org>
+
+ * Released version 1.00RC2
+
+ * lib/hostname.cc (getnames): Changed the logic here to append the
+ domain name to the node name to produce the fully qualified host
+ name if the node name does not already contain the domain name.
+
+ * protocols/smtp.cc: Changed all the calls to smtp::docmd to use
+ the start of the range instead of the expected response. This may
+ have been causing some SMTP sessions to fail.
+
+2000-06-19 Bruce Guenter <bruce@bruce-guenter.dyndns.org>
+
+ * lib/tcpconnect.cc (tcpconnect): Removed an extraneous const from
+ the call to connect.
+
+2000-06-15 Bruce Guenter <bruce@bruce-guenter.dyndns.org>
+
+ * Released version 1.00RC1
+
+ * Fixed up copyright notices in all the sources.
+
+ * lib/makefield.cc (make_date): Totally reworked the logic here if
+ tm_gmtoff is detected to fix timezone and DST detection bugs.
+
+2000-01-11 Bruce Guenter <bguenter@bguenter.pointsnorth.com>
+
+ * Released version 0.40
+
+ * lib/makefield.cc: Fixed up to autodetect (with the help of
+ configure) the tm_isdst and tm_gmtoff flags in struct tm.
+
+2000-01-11 Bruce Guenter <bruceg@daedalus.bfsmedia.com>
+
+ * lib/tcpconnect.cc: Reordered the include files here to avoid
+ problems with FreeBSD headers.
+
+2000-01-10 Bruce Guenter <bruceg@daedalus.bfsmedia.com>
+
+ * lib/address.cc: Renamed isspecial to issymbol to avoid problems
+ on FreeBSD caused by an existing "isspecial" macro.
+
+ * src/sendmail.cc (cli_main): Fixed typo that caused parseargs to
+ not be called.
+
+1999-10-22 Bruce Guenter <bguenter@mikhail.qcc.sk.ca>
+
+ * protocols/protocol.cc (cli_main): Use the already opened FD to
+ load the message from instead of opening it.
+
+ * src/send.cc (send_one): Open the named file for writing before
+ attempting to send message, and pass it to exec_protocol.
+ (exec_protocol): Dup the open message to FD 0 before executing
+ program.
+
+1999-10-21 Bruce Guenter <bguenter@mikhail.qcc.sk.ca>
+
+ * Released version 0.39
+
+ * lib/list.h: Added a const_list_iterator, as well as a copy
+ constructor for list<T>.
+
+1999-10-20 Bruce Guenter <bguenter@mikhail.qcc.sk.ca>
+
+ * src/inject.cc (parse_line): Added test for non-RFC header lines
+ (ie lines starting with anything except a sequence of
+ non-whitespace characters follows by a colon).
+ (read_header): Test if the first header line is a continuation
+ line and fail if so.
+
+ * src/send.cc (load_remotes): Fixed parsing of "remotes" control
+ file to allow any whitespace between, before, and after elements,
+ as well as to handle lines starting with a '#' as comments.
+
+1999-10-04 Bruce Guenter <bguenter@mikhail.qcc.sk.ca>
+
+ * Released version 0.38
+
+ * src/send.cc (load_config): Don't fail reading the configuration
+ if pausetime can't be read.
+
+1999-09-23 Bruce Guenter <bguenter@mikhail.qcc.sk.ca>
+
+ * Released version 0.37
+
+ * lib/address.cc (RULE(route_spec)): Made the "phrase" optional to
+ allow addresses like "<foo@bar>" (note, no comment) to be parsed.
+
+1999-09-16 Bruce Guenter <bguenter@mikhail.qcc.sk.ca>
+
+ * src/send.cc (send_all): Load the config each time the queue is
+ run.
+ (do_select): Removed the logic here to handle reloading the config
+ on HUP, since it's reloaded all the time.
+ (load_files): Removed the 'stat' on the queue directory as an
+ indicator of if it needs to be rescanned, and made the contents
+ reloaded always.
+ (do_select): Force a reload of the queue if the select times out.
+
+1999-09-11 Bruce Guenter <bguenter@mikhail.qcc.sk.ca>
+
+ * Released version 0.36
+
+ * src/sendmail.cc: Rewrote to use the CLI library.
+
+ * src/inject.cc: Rewrote to use the CLI library.
+
+ * protocols/protocol.cc: Rewrote to use the CLI library.
+
+1999-09-02 Bruce Guenter <bguenter@mikhail.qcc.sk.ca>
+
+ * Released version 0.35
+
+1999-08-26 Bruce Guenter <bguenter@mikhail.qcc.sk.ca>
+
+ * src/send.cc (remote): Parse options from the string.
+ (load_remotes): Handle options after the protocol name.
+ (exec_protocol): Build an argument list including options.
+
+ * protocols/protocol.cc (parse_args): Added support for a port
+ number.
+
+ * protocols/qmqp.cc: Adapted to use generic interface.
+
+ * protocols/smtp.cc: Adapted to use generic interface.
+
+ * protocols/protocol.cc (main): Started writing a generic protocol
+ library, which will open the message file and determine a port
+ number.
+
+ * src/send.cc (load_files): Stat the queue before opening it to
+ see if the contents have changed.
+
+1999-07-22 Bruce Guenter <bguenter@mikhail.qcc.sk.ca>
+
+ * lib/hostname.cc (getnames): Switched the implementation of
+ domainname and hostname to use uname(2). This fixes a problem
+ observed with empty domain names.
+
+1999-07-16 Bruce Guenter <bguenter@mikhail.qcc.sk.ca>
+
+ * lib/address.cc: Rewrote this parsing framework to do a top-level
+ tokenization before parsing, and then parse based on those
+ tokens.
+
+1999-07-15 Bruce Guenter <bguenter@mikhail.qcc.sk.ca>
+
+ * Imported latest mystring and fdbuf libraries, and adapted the
+ rest of the code to call the new routines.
+
+1999-03-30 Bruce Guenter <bguenter@mikhail.qcc.sk.ca>
+
+ * Integrated new modularized mystring library from vmailmgr.
+
+1999-03-27 Bruce Guenter <bguenter@mikhail.qcc.sk.ca>
+
+ * Released version 0.33
+
+ * src/queue.cc (copyenv): Only do the envelope remapping on
+ recipient addresses.
+
+ * lib/listtest.cc: Wrote test code for the list class (not
+ compiled, but included in the distribution).
+
+ * lib/list.h (remove): Fixed (hopefully) the code to advance the
+ prev/curr pointers after removing a node.
+
+ * src/send.cc (catchsender): Removed an extraneous return line.
+
+ * doc/nullmailer-queue.8: Updated to describe the admin address
+ facility.
+
+ * src/queue.cc (main): Load in the "admin" address and localhost
+ to determine how to remap addresses.
+ If the hostname is localhost, remap this address to the admin
+ address.
+
+1999-03-04 Bruce Guenter <bguenter@mikhail.qcc.sk.ca>
+
+ * Released version 0.32
+
+ * lib/address.cc (unquote): Wrote this routine to remove quoting
+ and escaped characters from a string.
+ (quote): Wrote this routine to add necessary quoting and escaping
+ to addresses.
+ (RULE(quoted_string)): Unquote strings before returning them.
+ Modified many other routines to handle unquoting.
+
+1999-02-25 Bruce Guenter <bguenter@mikhail.qcc.sk.ca>
+
+ * Released version 0.31
+
+ * Makefile.am (install-root): Neede to make nullmailer-queue
+ setuid nullmail here.
+
+ * HOWTO: Added a quick guide to getting nullmailer running.
+
+1999-02-23 Bruce Guenter <bguenter@mikhail.qcc.sk.ca>
+
+ * Released version 0.30
+
+ * src/inject.cc (struct header_field): Do not empty the recipient
+ list when a resent field is seen if header recipients are being
+ ignored.
+
+ * doc/nullmailer-inject.1: Adjusted the section on setting the
+ host name to account for the below change.
+
+ * src/inject.cc (setup_from): Set the host name to defaulthost
+ instead of hostname(), and canonicalize host and shost before
+ using them.
+
+ * lib/fdbuf_copy.cc (fdbuf_copy): Added an initial EOF test and
+ moved the loop's EOF test to the end of the loop.
+
+1999-02-22 Bruce Guenter <bguenter@mikhail.qcc.sk.ca>
+
+ * src/inject.cc (send_body): Removed the test to see if fin is at
+ EOF before calling fdbuf_copy.
+
+ * lib/fdbuf_copy.cc (fdbuf_copy): Revised loop termination
+ condition from in.last_count() == 0 (which could happen at EOF) to
+ !in.eof() (since EOF is not an error condition).
+
+ * Released version 0.29
+
+ * src/inject.cc: Fixed a number of offsets in the header_has_* and
+ header_field_* declarations.
+
+ * doc/nullmailer-inject.1: Modified the documentation to describe
+ the "-n" (do not queue) and "-v" (show envelope) flags.
+
+ * src/inject.cc: Added handling for flags to print out the message
+ and optionally the envelope instead of queueing the message.
+
+ * src/sendmail.cc (parseargs): Added a whole long list of sendmail
+ flags to ignore.
+
+ * lib/address.cc (RULE(route)): fixed missing pointer advance
+
+1999-02-21 Bruce Guenter <bguenter@mikhail.qcc.sk.ca>
+
+ * test/address-test.cc: Moved this testing code out of the main
+ address.cc source code module.
+
+1999-02-20 Bruce Guenter <bguenter@mikhail.qcc.sk.ca>
+
+ * lib/address.cc (RULE(address)): Reversed order of group and
+ mailbox.
+ (RULE(phrase)): Fixed the extra trailing space added by this rule
+ along with cleaning up how this rule works.
+ (RULE(mailboxes)): Added this rule, a parallel of addresses, for
+ use in group.
+ (RULE(group)): Fixed several bugs in this rule.
+
+1999-02-19 Bruce Guenter <bguenter@mikhail.qcc.sk.ca>
+
+ * lib/address.cc (RULE(quoted_string)): Fixed inclusion of quotes
+ in quoted addresses.
+ (TEST_ADDRESS): Added in a self-test framework
+ (RULE(comment)): fixed missing comment carry-through
+ (RULE(group)): fixed missing comment insertion
+ (RULE(addresses)): fixed missing comment insertion
+ (RULE(local_part)): forgot to advance pointer if a comment was
+ matched.
+ (RULE(domain)): forgot to advance pointer after SKIPDELIM
+ (RULE(addr_spec)): forgot to advance pointer after SKIPDELIM
+
+1999-02-18 Bruce Guenter <bguenter@mikhail.qcc.sk.ca>
+
+ * Released version 0.28
+
+ * src/sendmail.cc (main): Pass "-e" to inject (use either) instead
+ of "-a" (use args only) if sendmail was not passed a "-t",
+ otherwise pass "-b" (use both) instead of "-h" (use header only).
+
+ * spec: Fixed the useradd part of this script to add the
+ "nullmail" user instead of "$1".
+
+ * init: Reworked large parts of this script to make it work on my
+ systems.
+
+ * src/send.cc (read_trigger): Modified behavior of this routine to
+ read a chunk of data from the trigger before closing it. This
+ prevents the trigger from being "pulled" after it's been reopened.
+
+ * src/sendmail.cc: Prefixed all error messages with "sendmail:".
+
+ * src/inject.cc (setup_from): Added code to handle the "c" flag --
+ use "address (comment)" style in the generated from line instead
+ of "comment <address>".
+ (exec_queue): Fixed error message to print out the actual value of
+ SBIN_DIR, plus prefixing the message with "nullmailer-inject".
+
+ * Released version 0.27
+
+ * src/inject.cc (main): Whoops -- write should have been writeln.
+
+ * protocols/qmqp.cc: Completed (with minimal testing) the QMQP
+ module.
+
+ * lib/fdbuf_copy.cc (fdbuf_copy): Added a "noflush" option to make
+ calling flush on the output fdbuf optional.
+
+ * lib/makefield.cc (make_date): Fixed bug: neglected to
+ NUL-terminate the timezone string.
+
+ * lib/canonicalize.cc (canonicalize): Moved this function out of
+ address.cc
+
+ * lib/errcodes.cc (errorstr): Added some new error codes
+
+ * lib/fdibuf.cc (getchar): Wrote this routine to read in a single
+ character.
+ (getnetstring): Wrote this routine to read in a netstring
+
+ * lib/netstring.cc (strnl2net): Wrote this routine that converts a
+ string plus a newline character into a netstring. This avoids an
+ extra memory allocation and copy to do the concatenation before
+ making the netstring.
+
+ * protocols/qmqp.cc: Started a QMQP protocol module.
+
+ * lib/netstring.cc (str2net): Wrote this routine to convert
+ strings into netstrings (for details, see
+ ftp://koobera.math.uic.edu/www/proto/netstrings.txt).
+
+ * protocols/smtp.cc (main): Moved the message file open above the
+ connection to avoid making a connection if the file is unreadable.
+
+ * lib/fdibuf.cc (rewind): Wrote this routine to rewind an open
+ fdibuf.
+
+ * src/inject.cc (make_recipient_list): Completed code to handle
+ the "t" flag.
+
+ * doc/nullmailer-inject.1: Added section describing the parsing of
+ the NULLMAILER_FLAGS environment variable.
+
+ * src/inject.cc (struct header_field): Added code to handle fields
+ that are ignored.
+ (fix_header): Added preliminary code to add in a missing to field.
+ (parse_flags): Wrote this routine to handle the NULLMAILER_FLAGS
+ environment variable.
+ (parse_args): Added a call to parse_flags.
+
+1999-02-17 Bruce Guenter <bguenter@mikhail.qcc.sk.ca>
+
+ * Released version 0.26
+
+ * Moved address.cc, address.h, makefield.cc into lib.
+
+1999-02-16 Bruce Guenter <bguenter@mikhail.qcc.sk.ca>
+
+ * src/queue.cc (deliver): Fixed unique filename generator to call
+ itoa only once per constructor, and to avoid calling time() and
+ getpid() more than necessary.
+
+ * src/send.cc (exec_protocol): Stripped out the error messages
+ printed in this routine, since they go nowhere anyways.
+ (send_one): Added tracing information about program execution.
+
+ * src/makefield.cc (make_messageid): Can't have two calls to itoa
+ as arguments to the same function call (mystring constructor in
+ this case) because itoa uses a static buffer.
+
+ * src/inject.cc (exec_queue): Execute nullmailer-queue from
+ SBIN_DIR.
+
+ * lib/defines.h: Added a definition for SBIN_DIR.
+
+1999-02-15 Bruce Guenter <bguenter@mikhail.qcc.sk.ca>
+
+ * Released version 0.25
+
+ * doc/nullmailer-send.8: Updated the documentation to reflect the
+ new parsing code for "remotes".
+
+ * src/makefield.cc (make_messageid): Changed the format of the
+ message-id string to make it easier to generate and more unique.
+ (make_date): Fixed timezone number generator code.
+
+ * lib/itoa.cc (itoa): Fixed bug in padding code that caused the
+ string to be padded with unending NUL bytes instead of zeros.
+
+ * lib/config_readlist.cc (config_readlist): Modified to strip all
+ the lines that are read in, to ignore lines that start with a
+ pound ('#') or are empty, and to return false if no lines were
+ read.
+
+ * lib/config_read.cc (config_read): Modified to strip the
+ resulting string.
+
+ * lib/mystring.cc: Revised lstrip, rstrip, and strip to return
+ *this if no modifications to the string were necessary.
+
+ * src/send.cc (load_config): Rewrote the logic of this routine to
+ always load all the config files, and moved the loading of the
+ remotes into a separate section.
+ (load_remotes): Added support for loading "hostname protocol"
+ pairs from the remotes file.
+
+ * protocols/smtp.cc (main): Filename is argv[2], not argv[1].
+
+ * src/address.cc (RULE(local_part)): Fixed another pointer
+ increment bug.
+
+ * src/inject.cc (main): Moved check for no recipients into here.
+
+1999-02-14 Bruce Guenter <bguenter@mikhail.qcc.sk.ca>
+
+ * lib/hostname.cc: Fixed a problem that could cause
+ nullmailer-inject (and possibly others) to core dump on exit.
+
+ * src/inject.cc (send_body): Fixed bug that caused transmission of
+ an empty body (legal) to nullmailer-queue to fail.
+ (read_header): Added a check to ensure that at least one recipient
+ was given.
+
+1999-02-13 Bruce Guenter <bguenter@mikhail.qcc.sk.ca>
+
+ * src/send.cc: Rewrote the portion of this code that executes the
+ protocol program to not do a connect, and to expect a numerical
+ error code from the exit status of the program. Also implemented
+ a configurable pause between queue runs.
+
+ * protocols/smtp.cc: Rewrote this module extensively. It now
+ expects the hostname as the first command-line parameter and the
+ filename as the second, and returns a single error code (no
+ text error messages and no pipes).
+
+1999-02-12 Bruce Guenter <bguenter@mikhail.qcc.sk.ca>
+
+ * src/address.cc (RULE(domain)): Fixed pointer increment bug in
+ this rule.
+
+ * doc/nullmailer-inject.1: Updated to reflect status of
+ configuration variable reading.
+
+ * src/makefield.cc (make_messageid): Use idhost instead of
+ hostname().
+
+ * src/inject.cc (read_config): Read the defaultdomain,
+ defaulthost, and idhost config files.
+
+ * src/address.cc (canonicalize): Use the defaulthost and
+ defaultdomain strings, declared in src/inject.cc, instead of
+ hostname() and domainname().
+
+ * src/inject.cc: Added code to parse the command line options as
+ documented in the man page.
+
+1999-02-11 Bruce Guenter <bguenter@mikhail.qcc.sk.ca>
+
+ * Released version 0.22
+
+ * src/sendmail.cc: Completed the basics of this program.
+
+ * doc/nullmailer-inject.1: Filled in the DESCRIPTION a little bit.
+
diff --git a/HOWTO b/HOWTO
new file mode 100644
index 0000000..7115854
--- /dev/null
+++ b/HOWTO
@@ -0,0 +1,41 @@
+Configuration of this program in the typical case is quite simple.
+
+1. Compile and install the program. If you are using the RPM, skip this
+step. See the INSTALL file for more details. Note that this package is
+designed to execute as a non-priveleged user named "nullmail". When you
+do the final install, add the "nullmail" user (typically with either a
+non-priveleged group or a new "nullmail" group) and run "make
+install-root" to set up the files with the proper permissions.
+
+2. Determine who your relay host is. This is the computer or computers
+to which you will send all your mail.
+
+3. Into the file SYSCONFDIR/nullmailer/remotes, put one line for each of
+your relay hosts:
+ HOSTNAME PROTOCOL
+You will have specified the SYSCONFDIR during configuration of the
+install step. On most systems, it will be /usr/local/etc. The RPMs use
+/etc. HOSTNAME is the fully-qualified host name of the relay host, or
+its numerical IP address. PROTOCOL will typically be "smtp" (without
+the quotes), but QMQP[1] is also supported with the "qmqp" module.
+
+4. Start nullmailer-send. If you are using the RPM, ignore the rest of
+the instructions and type:
+ /etc/rc.d/init.d/nullmailer start
+Otherwise, you will need to set up the appropriate scripts to run
+nullmailer-send in the background, with its output going to a logging
+program. The following is an appropriate run script for use with
+daemontools[2]:
+ #!/bin/sh
+ exec setuidgid nullmail nullmailer-send 2>&1
+
+5. You're done! The included sendmail emulator front-end should allow
+most (if not all) sendmail-compatible programs to run without any
+changes. See the man page for nullmailer-inject for details on outgoing
+email message header formatting options.
+
+Footnotes:
+1. QMQP is a high-speed mail queueing protocol, used with qmail. See
+http://cr.yp.to/proto/qmqp.html
+2. See http://cr.yp.to/daemontools.html. I have RPMS available at
+http://em.ca/~bruceg/rpms/daemontools/
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..b42a17a
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,182 @@
+Basic Installation
+==================
+
+ These are generic installation instructions.
+
+ The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation. It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions. Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, a file
+`config.cache' that saves the results of its tests to speed up
+reconfiguring, and a file `config.log' containing compiler output
+(useful mainly for debugging `configure').
+
+ If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release. If at some point `config.cache'
+contains results you don't want to keep, you may remove or edit it.
+
+ The file `configure.in' is used to create `configure' by a program
+called `autoconf'. You only need `configure.in' if you want to change
+it or regenerate `configure' using a newer version of `autoconf'.
+
+The simplest way to compile this package is:
+
+ 1. `cd' to the directory containing the package's source code and type
+ `./configure' to configure the package for your system. If you're
+ using `csh' on an old version of System V, you might need to type
+ `sh ./configure' instead to prevent `csh' from trying to execute
+ `configure' itself.
+
+ Running `configure' takes awhile. While running, it prints some
+ messages telling which features it is checking for.
+
+ 2. Type `make' to compile the package.
+
+ 3. Optionally, type `make check' to run any self-tests that come with
+ the package.
+
+ 4. Type `make install' to install the programs and any data files and
+ documentation.
+
+ 5. You can remove the program binaries and object files from the
+ source code directory by typing `make clean'. To also remove the
+ files that `configure' created (so you can compile the package for
+ a different kind of computer), type `make distclean'. There is
+ also a `make maintainer-clean' target, but that is intended mainly
+ for the package's developers. If you use it, you may have to get
+ all sorts of other programs in order to regenerate files that came
+ with the distribution.
+
+Compilers and Options
+=====================
+
+ Some systems require unusual options for compilation or linking that
+the `configure' script does not know about. You can give `configure'
+initial values for variables by setting them in the environment. Using
+a Bourne-compatible shell, you can do that on the command line like
+this:
+ CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure
+
+Or on systems that have the `env' program, you can do it like this:
+ env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure
+
+Compiling For Multiple Architectures
+====================================
+
+ You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory. To do this, you must use a version of `make' that
+supports the `VPATH' variable, such as GNU `make'. `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script. `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.
+
+ If you have to use a `make' that does not supports the `VPATH'
+variable, you have to compile the package for one architecture at a time
+in the source code directory. After you have installed the package for
+one architecture, use `make distclean' before reconfiguring for another
+architecture.
+
+Installation Names
+==================
+
+ By default, `make install' will install the package's files in
+`/usr/local/bin', `/usr/local/man', etc. You can specify an
+installation prefix other than `/usr/local' by giving `configure' the
+option `--prefix=PATH'.
+
+ You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files. If you
+give `configure' the option `--exec-prefix=PATH', the package will use
+PATH as the prefix for installing programs and libraries.
+Documentation and other data files will still use the regular prefix.
+
+ In addition, if you use an unusual directory layout you can give
+options like `--bindir=PATH' to specify different values for particular
+kinds of files. Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them.
+
+ If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+Optional Features
+=================
+
+ Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System). The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+ For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+Specifying the System Type
+==========================
+
+ There may be some features `configure' can not figure out
+automatically, but needs to determine by the type of host the package
+will run on. Usually `configure' can figure that out, but if it prints
+a message saying it can not guess the host type, give it the
+`--host=TYPE' option. TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name with three fields:
+ CPU-COMPANY-SYSTEM
+
+See the file `config.sub' for the possible values of each field. If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the host type.
+
+ If you are building compiler tools for cross-compiling, you can also
+use the `--target=TYPE' option to select the type of system they will
+produce code for and the `--build=TYPE' option to select the type of
+system on which you are compiling the package.
+
+Sharing Defaults
+================
+
+ If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists. Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Operation Controls
+==================
+
+ `configure' recognizes the following options to control how it
+operates.
+
+`--cache-file=FILE'
+ Use and save the results of the tests in FILE instead of
+ `./config.cache'. Set FILE to `/dev/null' to disable caching, for
+ debugging `configure'.
+
+`--help'
+ Print a summary of the options to `configure', and exit.
+
+`--quiet'
+`--silent'
+`-q'
+ Do not print messages saying which checks are being made. To
+ suppress all normal output, redirect it to `/dev/null' (any error
+ messages will still be shown).
+
+`--srcdir=DIR'
+ Look for the package's source code in directory DIR. Usually
+ `configure' can determine that directory automatically.
+
+`--version'
+ Print the version of Autoconf used to generate the `configure'
+ script, and exit.
+
+`configure' also accepts some other, not widely useful, options.
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..e70c9a4
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,28 @@
+localstatedir = @localstatedir@/nullmailer
+sysconfdir = @sysconfdir@/nullmailer
+
+EXTRA_DIST = BUGS HOWTO INSTALL TODO YEAR2000 scripts/*
+SUBDIRS = doc lib protocols src test
+
+install-data-local:
+ @$(NORMAL_INSTALL)
+ $(mkinstalldirs) $(DESTDIR)$(localstatedir)/queue
+ chmod 700 $(DESTDIR)$(localstatedir)/queue
+ $(mkinstalldirs) $(DESTDIR)$(localstatedir)/tmp
+ chmod 700 $(DESTDIR)$(localstatedir)/tmp
+ $(mkinstalldirs) $(DESTDIR)$(sysconfdir)
+ $(RM) -f $(DESTDIR)$(localstatedir)/trigger
+ mkfifo $(DESTDIR)$(localstatedir)/trigger
+ chmod 600 $(DESTDIR)$(localstatedir)/trigger
+
+install-root:
+ chown nullmail $(DESTDIR)$(localstatedir)/*
+ chown nullmail $(DESTDIR)$(sbindir)/nullmailer-queue
+ chmod u+s $(DESTDIR)$(sbindir)/nullmailer-queue
+ chown nullmail $(DESTDIR)$(bindir)/mailq
+ chmod u+s $(DESTDIR)$(bindir)/mailq
+
+dist-hook:
+ sed -e s/@VERSION\@/@VERSION@/ \
+ <spec >$(distdir)/nullmailer-@VERSION@.spec
+ find $(distdir)/scripts -name '*~' | xargs -r rm
diff --git a/Makefile.in b/Makefile.in
new file mode 100644
index 0000000..2c7acdd
--- /dev/null
+++ b/Makefile.in
@@ -0,0 +1,381 @@
+# Makefile.in generated automatically by automake 1.4a from Makefile.am
+
+# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sharedstatedir = @sharedstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DESTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = .
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_FLAG =
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+CC = @CC@
+CXX = @CXX@
+MAKEINFO = @MAKEINFO@
+MKDIR = @MKDIR@
+PACKAGE = @PACKAGE@
+RANLIB = @RANLIB@
+RM = @RM@
+STRIP = @STRIP@
+VERSION = @VERSION@
+
+localstatedir = @localstatedir@/nullmailer
+sysconfdir = @sysconfdir@/nullmailer
+
+EXTRA_DIST = BUGS HOWTO INSTALL TODO YEAR2000 scripts/*
+SUBDIRS = doc lib protocols src test
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = config.h
+CONFIG_CLEAN_FILES =
+DIST_COMMON = README ./stamp-h.in AUTHORS COPYING ChangeLog INSTALL \
+Makefile.am Makefile.in NEWS TODO acconfig.h acinclude.m4 aclocal.m4 \
+config.h.in configure configure.in install-sh missing mkinstalldirs
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = gtar
+GZIP_ENV = --best
+all: all-redirect
+.SUFFIXES:
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
+ cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps Makefile
+
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ cd $(top_builddir) \
+ && CONFIG_FILES=$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+$(ACLOCAL_M4): configure.in acinclude.m4
+ cd $(srcdir) && $(ACLOCAL)
+
+config.status: $(srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ $(SHELL) ./config.status --recheck
+$(srcdir)/configure: $(srcdir)/configure.in $(ACLOCAL_M4) $(CONFIGURE_DEPENDENCIES)
+ cd $(srcdir) && $(AUTOCONF)
+
+config.h: stamp-h
+ @if test ! -f $@; then \
+ rm -f stamp-h; \
+ $(MAKE) stamp-h; \
+ else :; fi
+stamp-h: $(srcdir)/config.h.in $(top_builddir)/config.status
+ cd $(top_builddir) \
+ && CONFIG_FILES= CONFIG_HEADERS=config.h \
+ $(SHELL) ./config.status
+ @echo timestamp > stamp-h 2> /dev/null
+$(srcdir)/config.h.in: $(srcdir)/stamp-h.in
+ @if test ! -f $@; then \
+ rm -f $(srcdir)/stamp-h.in; \
+ $(MAKE) $(srcdir)/stamp-h.in; \
+ else :; fi
+$(srcdir)/stamp-h.in: $(top_srcdir)/configure.in $(ACLOCAL_M4) acconfig.h
+ cd $(top_srcdir) && $(AUTOHEADER)
+ @echo timestamp > $(srcdir)/stamp-h.in 2> /dev/null
+
+mostlyclean-hdr:
+
+clean-hdr:
+
+distclean-hdr:
+ -rm -f config.h
+
+maintainer-clean-hdr:
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run `make' without going through this Makefile.
+# To change the values of `make' variables: instead of editing Makefiles,
+# (1) if the variable is set in `config.status', edit `config.status'
+# (which will cause the Makefiles to be regenerated when you run `make');
+# (2) otherwise, pass the desired values on the `make' command line.
+
+@SET_MAKE@
+
+all-recursive install-data-recursive install-exec-recursive \
+installdirs-recursive install-recursive uninstall-recursive \
+check-recursive installcheck-recursive info-recursive dvi-recursive:
+ @set fnord $(MAKEFLAGS); amf=$$2; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+mostlyclean-recursive clean-recursive distclean-recursive \
+maintainer-clean-recursive:
+ @set fnord $(MAKEFLAGS); amf=$$2; \
+ dot_seen=no; \
+ rev=''; list='$(SUBDIRS)'; for subdir in $$list; do \
+ rev="$$subdir $$rev"; \
+ test "$$subdir" = "." && dot_seen=yes; \
+ done; \
+ test "$$dot_seen" = "no" && rev=". $$rev"; \
+ target=`echo $@ | sed s/-recursive//`; \
+ for subdir in $$rev; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \
+ done && test -z "$$fail"
+tags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
+ done
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP)
+ list='$(SOURCES) $(HEADERS)'; \
+ unique=`for i in $$list; do echo $$i; done | \
+ awk ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ here=`pwd` && cd $(srcdir) \
+ && mkid -f$$here/ID $$unique $(LISP)
+
+TAGS: tags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test -f $$subdir/TAGS && tags="$$tags -i $$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ list='$(SOURCES) $(HEADERS)'; \
+ unique=`for i in $$list; do echo $$i; done | \
+ awk ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(ETAGS_ARGS)config.h.in$$unique$(LISP)$$tags" \
+ || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags config.h.in $$unique $(LISP) -o $$here/TAGS)
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+ -rm -f TAGS ID
+
+maintainer-clean-tags:
+
+distdir = $(PACKAGE)-$(VERSION)
+top_distdir = $(distdir)
+
+# This target untars the dist file and tries a VPATH configuration. Then
+# it guarantees that the distribution is self-contained by making another
+# tarfile.
+distcheck: dist
+ -rm -rf $(distdir)
+ GZIP=$(GZIP_ENV) $(TAR) zxf $(distdir).tar.gz
+ mkdir $(distdir)/=build
+ mkdir $(distdir)/=inst
+ dc_install_base=`cd $(distdir)/=inst && pwd`; \
+ cd $(distdir)/=build \
+ && ../configure --srcdir=.. --prefix=$$dc_install_base \
+ && $(MAKE) $(AM_MAKEFLAGS) \
+ && $(MAKE) $(AM_MAKEFLAGS) dvi \
+ && $(MAKE) $(AM_MAKEFLAGS) check \
+ && $(MAKE) $(AM_MAKEFLAGS) install \
+ && $(MAKE) $(AM_MAKEFLAGS) installcheck \
+ && $(MAKE) $(AM_MAKEFLAGS) dist
+ -rm -rf $(distdir)
+ @banner="$(distdir).tar.gz is ready for distribution"; \
+ dashes=`echo "$$banner" | sed s/./=/g`; \
+ echo "$$dashes"; \
+ echo "$$banner"; \
+ echo "$$dashes"
+dist: distdir
+ -chmod -R a+r $(distdir)
+ GZIP=$(GZIP_ENV) $(TAR) chozf $(distdir).tar.gz $(distdir)
+ -rm -rf $(distdir)
+dist-all: distdir
+ -chmod -R a+r $(distdir)
+ GZIP=$(GZIP_ENV) $(TAR) chozf $(distdir).tar.gz $(distdir)
+ -rm -rf $(distdir)
+distdir: $(DISTFILES)
+ -rm -rf $(distdir)
+ mkdir $(distdir)
+ -chmod 777 $(distdir)
+ $(mkinstalldirs) $(distdir)/scripts
+ @for file in $(DISTFILES); do \
+ d=$(srcdir); \
+ if test -d $$d/$$file; then \
+ cp -pr $$d/$$file $(distdir)/$$file; \
+ else \
+ test -f $(distdir)/$$file \
+ || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+ || cp -p $$d/$$file $(distdir)/$$file || :; \
+ fi; \
+ done
+ for subdir in $(SUBDIRS); do \
+ if test "$$subdir" = .; then :; else \
+ test -d $(distdir)/$$subdir \
+ || mkdir $(distdir)/$$subdir \
+ || exit 1; \
+ chmod 777 $(distdir)/$$subdir; \
+ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir=../$(distdir) distdir=../$(distdir)/$$subdir distdir) \
+ || exit 1; \
+ fi; \
+ done
+ $(MAKE) $(AM_MAKEFLAGS) top_distdir="$(top_distdir)" distdir="$(distdir)" dist-hook
+info-am:
+info: info-recursive
+dvi-am:
+dvi: dvi-recursive
+check-am: all-am
+check: check-recursive
+installcheck-am:
+installcheck: installcheck-recursive
+all-recursive-am: config.h
+ $(MAKE) $(AM_MAKEFLAGS) all-recursive
+
+install-exec-am:
+install-exec: install-exec-recursive
+
+install-data-am: install-data-local
+install-data: install-data-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-recursive
+uninstall-am:
+uninstall: uninstall-recursive
+all-am: Makefile config.h
+all-redirect: all-recursive-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_STRIP_FLAG=-s install
+installdirs: installdirs-recursive
+installdirs-am:
+
+
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -rm -f Makefile $(CONFIG_CLEAN_FILES)
+ -rm -f config.cache config.log stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+mostlyclean-am: mostlyclean-hdr mostlyclean-tags mostlyclean-generic
+
+mostlyclean: mostlyclean-recursive
+
+clean-am: clean-hdr clean-tags clean-generic mostlyclean-am
+
+clean: clean-recursive
+
+distclean-am: distclean-hdr distclean-tags distclean-generic clean-am
+
+distclean: distclean-recursive
+ -rm -f config.status
+
+maintainer-clean-am: maintainer-clean-hdr maintainer-clean-tags \
+ maintainer-clean-generic distclean-am
+ @echo "This command is intended for maintainers to use;"
+ @echo "it deletes files that may require special tools to rebuild."
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f config.status
+
+.PHONY: mostlyclean-hdr distclean-hdr clean-hdr maintainer-clean-hdr \
+install-data-recursive uninstall-data-recursive install-exec-recursive \
+uninstall-exec-recursive installdirs-recursive uninstalldirs-recursive \
+all-recursive check-recursive installcheck-recursive info-recursive \
+dvi-recursive mostlyclean-recursive distclean-recursive clean-recursive \
+maintainer-clean-recursive tags tags-recursive mostlyclean-tags \
+distclean-tags clean-tags maintainer-clean-tags distdir info-am info \
+dvi-am dvi check check-am installcheck-am installcheck all-recursive-am \
+install-exec-am install-exec install-data-local install-data-am \
+install-data install-am install uninstall-am uninstall all-redirect \
+all-am all installdirs-am installdirs mostlyclean-generic \
+distclean-generic clean-generic maintainer-clean-generic clean \
+mostlyclean distclean maintainer-clean
+
+
+install-data-local:
+ @$(NORMAL_INSTALL)
+ $(mkinstalldirs) $(DESTDIR)$(localstatedir)/queue
+ chmod 700 $(DESTDIR)$(localstatedir)/queue
+ $(mkinstalldirs) $(DESTDIR)$(localstatedir)/tmp
+ chmod 700 $(DESTDIR)$(localstatedir)/tmp
+ $(mkinstalldirs) $(DESTDIR)$(sysconfdir)
+ $(RM) -f $(DESTDIR)$(localstatedir)/trigger
+ mkfifo $(DESTDIR)$(localstatedir)/trigger
+ chmod 600 $(DESTDIR)$(localstatedir)/trigger
+
+install-root:
+ chown nullmail $(DESTDIR)$(localstatedir)/*
+ chown nullmail $(DESTDIR)$(sbindir)/nullmailer-queue
+ chmod u+s $(DESTDIR)$(sbindir)/nullmailer-queue
+ chown nullmail $(DESTDIR)$(bindir)/mailq
+ chmod u+s $(DESTDIR)$(bindir)/mailq
+
+dist-hook:
+ sed -e s/@VERSION\@/@VERSION@/ \
+ <spec >$(distdir)/nullmailer-@VERSION@.spec
+ find $(distdir)/scripts -name '*~' | xargs -r rm
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..74eb15e
--- /dev/null
+++ b/NEWS
@@ -0,0 +1,187 @@
+This file lists all the major user-visible changes to nullmailer.
+-------------------------------------------------------------------------------
+Changes in version 1.00RC5
+
+- Fixed getdomainname prototype in lib/hostname.cc.
+- Return proper error codes for permanent and temporary SMTP failures.
+- Adapted to use supervise-scripts 3.
+
+Note: If no further bugs are found, this will become the official
+version 1.00 release.
+-------------------------------------------------------------------------------
+Changes in version 1.00RC4
+
+- Fixed the reversed logic in the named pipe bug check.
+- Updated the HOWTO notes.
+- Fixed a compile problem on Solaris (and possibly other systems).
+- Fixed address parsing to strip a trailing period in the domain name.
+-------------------------------------------------------------------------------
+Changes in version 1.00RC3
+
+- Treat the first non-header line in a message as the first line of the
+ body, even if it isn't preceded by a blank line.
+- Fixed another host name bug causing compilation failures on systems
+ without "domainname" in struct utsname.
+- Fixed some typos that would prevent proper TCP connections on many
+ systems.
+- Handle systems that require both a reader and a writer on a named pipe
+ to do a proper select.
+- Added a man page for the sendmail emulator, and an overall man page.
+- Fixed a bug in the fdbuf library that was causing data loss or damage.
+-------------------------------------------------------------------------------
+Changes in version 1.00RC2
+
+- Fixed a bug in the way host names are determined. This should fix
+ problems with nullmailer-queue reporting an invalid envelope.
+
+- Fixed a portability bug in the mergelib.sh script.
+
+- Fixed a potential bug in the SMTP protocol response handling.
+-------------------------------------------------------------------------------
+Changes in version 1.00RC1
+
+- Imported latest fdbuf, mystring, and cli libraries.
+
+- Fixed a bug in the timezone handling on systems with tm_gmtoff.
+-------------------------------------------------------------------------------
+Changes in version 0.40
+
+- Fixed some compile problems to allow nullmailer to compile on FreeBSD.
+
+- Fixed a bug in the sendmail emulator to allow it to set the sender
+ name and address from the command line properly.
+
+- Modified the CLI library to behave more like the standard getopt
+ library.
+
+- Made a change to protocol between nullmailer-send and protocol
+ modules. nullmailer-send now opens up the message files and passes
+ them to the protocol module as FD 0 instead of passing a filename.
+
+- Added some notes to the nullmailer-send manual page explaining how
+ messages are delivered.
+-------------------------------------------------------------------------------
+Changes in version 0.39
+
+- Fixed problems in nullmailer-send in parsing the "remotes" file. It
+ previously did not handle comment lines or tabs or multiple white
+ space.
+
+- Made nullmailer-inject stricter about header lines to ensure that they
+ comply with RFC822.
+
+- Several minor updates to the libraries to bring them up to date.
+-------------------------------------------------------------------------------
+Changes in version 0.38
+
+- Fixed bug in nullmailer-send that caused it to refuse to send mail
+ when the optional "pausetime" configuration file did not exist.
+-------------------------------------------------------------------------------
+Changes in version 0.37
+
+- Fixed bug in address parser that caused strings like "<a@b.c>"
+ (without a leading comment) to fail.
+
+- Make nullmailer-send rescan the mail queue each time it wakes up,
+ rather than only if the timestamp changes to avoids race conditions.
+
+- Make nullmailer-send reload its config files ("remotes" and
+ "pausetime" each time it scans the queue).
+
+- Fixed top-level install-root target to run chmod/chown on the right
+ path to nullmailer-queue.
+
+- Added a configure test for libinet, libsocket, and libxnet libraries
+ for systems that have their networking code seperate from the main C
+ library (such as Solaris).
+-------------------------------------------------------------------------------
+Changes in version 0.36
+
+- Imported generic CLI library, to avoid the use of getopt on systems
+ that don't have one.
+-------------------------------------------------------------------------------
+Changes in version 0.35
+
+- Protocols now take a "-p #" to specify the port number to connect to.
+
+- This option can be specified in the "remotes" file immediately after
+ the protocol name.
+
+- nullmailer-send will now only rescan the mail queue if its timestamp
+ has changed since the last scan.
+
+- Fixed an observed problem with empty domain names by using uname(2)
+ instead of domainname and hostname.
+
+- The header address parsing code is rewritten to do a lexical
+ tokenization before parsing.
+
+- Imported new fdbuf and mystring libraries
+
+- Updated init scripts and RPM spec to work with new daemontools 0.61
+ and supervise-scripts packages.
+-------------------------------------------------------------------------------
+Changes in version 0.33
+- fixed a bug in the "list" template class that caused nullmailer-send
+ to only send out one message before sleeping
+- added a trivial address remapping facility to nullmailer-queue to
+ allow local addresses to be redirected to a remote administrator
+ address.
+-------------------------------------------------------------------------------
+Changes in version 0.32
+- the address parser now deals properly with quoted addresses
+-------------------------------------------------------------------------------
+Changes in version 0.31
+- added a HOWTO document
+- "make install-root" will now properly make nullmailer-queue setuid
+ nullmail
+-------------------------------------------------------------------------------
+Changes in version 0.30
+- fixed bug in the I/O library that caused nullmailer-inject to return
+ an error on messages with a single blank line following the header,
+ even though the message was successfully sent to nullmailer-queue
+- in nullmailer-inject, the hostname of the sender is set from the
+ defaulthost config file instead of hostname() (note that default is
+ set from hostname() if the file does not exist)
+- fixed a bug in nullmailer-inject that would cause it to incorrectly
+ clear its recipient list when using command-line recipients with a
+ "resent" message
+-------------------------------------------------------------------------------
+Changes in version 0.29
+- included the testing framework (mostly empty) into the package
+- fixed some bugs in nullmailer-inject caused by incorrect offsets into
+ the array of header fields
+- many bug fixes to the address parsing framework
+- nullmailer-inject now has an option to only print out the message
+ instead of passing it on to nullmailer-queue
+- many sendmail flags are now ignored instead of causing errors in the
+ sendmail front end to nullmailer-inject
+-------------------------------------------------------------------------------
+Changes in version 0.28
+- fixed the bugs in the spec and init script
+- nullmailer-inject now handles the "c" flag like qmail-inject
+- changed some error messages
+- the sendmail front end should have its header vs command-line
+ recipients logic fixed now
+-------------------------------------------------------------------------------
+Changes in version 0.27
+- added a QMQP protocol module
+- fixed a missing NUL-termination when creating the Date header line
+- nullmailer-inject now parses the NULLMAILER_FLAGS -- see the man page
+-------------------------------------------------------------------------------
+Changes in version 0.26
+- nullmailer-queue and nullmailer-send now go into sbin instead of bin
+- bugfixes to the unique number generation routines
+- moved some files around internally
+-------------------------------------------------------------------------------
+Changes in version 0.25
+- nullmailer-send now reads a protocol name along with the remote host
+- nullmailer-inject now handles its command-line options properly, as
+ well as reading and using defaulthost, defaultdomain, and idhost
+- fixed several bugs in the address parsing and date-generation code
+- revised the interface between nullmailer-send and the protocol modules
+ to simplify the interface and nullmailer-send
+-------------------------------------------------------------------------------
+Changes in version 0.22
+- added simple sendmail front end
+-------------------------------------------------------------------------------
diff --git a/README b/README
new file mode 100644
index 0000000..ed454b2
--- /dev/null
+++ b/README
@@ -0,0 +1,18 @@
+nullmailer
+Simple relay-only mail transport agent
+Bruce Guenter <bruceg@em.ca>
+Version 1.00RC5
+2000-12-29
+
+This is nullmailer, a sendmail/qmail/etc replacement MTA for hosts which
+relay to a fixed set of smart relays. It is designed to be simple to
+configure, secure, and easily extendable.
+
+A mailing list has been set up to discuss this package. To subscribe,
+send an email to:
+ nullmailer-subscribe@lists.em.ca
+
+This program is Copyright(C) 2000 Bruce Guenter, and may be copied
+according to the GNU GENERAL PUBLIC LICENSE (GPL) Version 2 or a later
+version. A copy of this license is included with this package. This
+package comes with no warranty of any kind.
diff --git a/TODO b/TODO
new file mode 100644
index 0000000..147cc5e
--- /dev/null
+++ b/TODO
@@ -0,0 +1,5 @@
+- For version 2: three-state queueing
+ - Queue message partially (tmp -> holding)
+ - Send to recipient immediately
+ - Remove from holding if sending succeeds
+ - Complete queueing (holding -> queue) if sending fails
diff --git a/YEAR2000 b/YEAR2000
new file mode 100644
index 0000000..ef64c15
--- /dev/null
+++ b/YEAR2000
@@ -0,0 +1,10 @@
+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.
+
+This program does not read in any dates from the user in any format.
+Any date manipulation is done in terms of seconds since the UNIX epoch.
+Any conversion from seconds into a readable form includes a full four
+digit year. As far as I am aware, no parts of this package will have
+any problems on the year 2000 or well beyond.
diff --git a/acconfig.h b/acconfig.h
new file mode 100644
index 0000000..4c56f26
--- /dev/null
+++ b/acconfig.h
@@ -0,0 +1,21 @@
+/* Package name */
+#undef PACKAGE
+
+/* Version number */
+#undef VERSION
+
+#undef GLOBAL_CONFIG
+#undef LOCAL_CONFIG
+
+/* Generic buffer size */
+#undef BUFSIZE
+
+#define QUEUE_DIR "@localstatedir@/nullmailer"
+
+#undef TM_HAS_GMTOFF
+
+#undef TM_HAS_ISDST
+
+#undef UTSNAME_HAS_DOMAINNAME
+
+#undef NAMEDPIPEBUG
diff --git a/acinclude.m4 b/acinclude.m4
new file mode 100644
index 0000000..df10b37
--- /dev/null
+++ b/acinclude.m4
@@ -0,0 +1,133 @@
+dnl TRY_CXX_FLAG(FLAG,[ACTION-IF-FOUND[,ACTION-IF-NOT-FOUND]])
+AC_DEFUN(TRY_CXX_FLAG,
+[echo >conftest.cc
+if ${CXX-g++} ${CXXFLAGS} -c [$1] conftest.cc >/dev/null 2>&1; then
+ ifelse([$2], , :, [rm -f conftest*
+ $2])
+else
+ ifelse([$3], , :, [rm -f conftest*
+ $3])
+fi
+rm -f conftest*])
+
+AC_DEFUN(CXX_NO_RTTI,
+[AC_CACHE_CHECK(whether ${CXX-g++} accepts -fno-rtti,
+ local_cv_flag_NO_RTTI,
+ TRY_CXX_FLAG(-fno-rtti,
+ local_cv_flag_NO_RTTI=yes,
+ local_cv_flag_NO_RTTI=no))
+test "$local_cv_flag_NO_RTTI" = yes && CXXFLAGS="$CXXFLAGS -fno-rtti"
+])
+
+AC_DEFUN(CXX_NO_EXCEPTIONS,
+[AC_CACHE_CHECK(whether ${CXX-g++} accepts -fno-exceptions,
+ local_cv_flag_NO_EXCEPTIONS,
+ TRY_CXX_FLAG(-fno-exceptions,
+ local_cv_flag_NO_EXCEPTIONS=yes,
+ local_cv_flag_NO_EXCEPTIONS=no))
+test "$local_cv_flag_NO_EXCEPTIONS" = yes && CXXFLAGS="$CXXFLAGS -fno-exceptions"
+])
+
+dnl TRY_STRUCT_TM_MEMBER(MEMBER,FLAGNAME)
+AC_DEFUN(TRY_STRUCT_TM_MEMBER,
+[ AC_CACHE_CHECK(whether struct tm contains [$1],
+ [$2],
+ cat >conftest.c <<EOF
+#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
+int main() { struct tm* foo; foo->[$1]; }
+EOF
+ if ${CC} ${CFLAGS} -c conftest.c >/dev/null 2>&1; then
+ [$2]=yes
+ else
+ [$2]=no
+ fi
+ rm -f conftest*)
+])
+
+AC_DEFUN(TEST_STRUCT_TM,
+ TRY_STRUCT_TM_MEMBER(tm_isdst, local_cv_flag_TM_HAS_ISDST)
+ TRY_STRUCT_TM_MEMBER(__tm_isdst, local_cv_flag_TM_HAS___ISDST)
+ if test "$local_cv_flag_TM_HAS_ISDST" = yes
+ then AC_DEFINE(TM_HAS_ISDST,tm_isdst)
+ elif test "$local_cv_flag_TM_HAS___ISDST" = yes
+ then AC_DEFINE(TM_HAS_ISDST,__tm_isdst)
+ fi
+ TRY_STRUCT_TM_MEMBER(tm_gmtoff, local_cv_flag_TM_HAS_GMTOFF)
+ TRY_STRUCT_TM_MEMBER(__tm_gmtoff, local_cv_flag_TM_HAS___GMTOFF)
+ if test "$local_cv_flag_TM_HAS_GMTOFF" = yes
+ then AC_DEFINE(TM_HAS_GMTOFF,tm_gmtoff)
+ elif test "$local_cv_flag_TM_HAS___GMTOFF" = yes
+ then AC_DEFINE(TM_HAS_GMTOFF,__tm_gmtoff)
+ fi
+)
+
+dnl TRY_STRUCT_UTSNAME_MEMBER(MEMBER,FLAGNAME)
+AC_DEFUN(TRY_STRUCT_UTSNAME_MEMBER,
+[ AC_CACHE_CHECK(whether struct utsname contains [$1],
+ [$2],
+ cat >conftest.c <<EOF
+#include <sys/utsname.h>
+int main() { struct utsname* foo; foo->[$1]; }
+EOF
+ if ${CC} ${CFLAGS} -c conftest.c >/dev/null 2>&1; then
+ [$2]=yes
+ else
+ [$2]=no
+ fi
+ rm -f conftest*)
+])
+
+AC_DEFUN(TEST_STRUCT_UTSNAME,
+ TRY_STRUCT_UTSNAME_MEMBER(domainname, local_cv_flag_UTSNAME_HAS_DOMAINNAME)
+ TRY_STRUCT_UTSNAME_MEMBER(__domainname,
+ local_cv_flag_UTSNAME_HAS___DOMAINNAME)
+ if test "$local_cv_flag_UTSNAME_HAS_DOMAINNAME" = yes
+ then AC_DEFINE(UTSNAME_HAS_DOMAINNAME,domainname)
+ elif test "$local_cv_flag_UTSNAME_HAS___DOMAINNAME" = yes
+ then AC_DEFINE(UTSNAME_HAS_DOMAINNAME,__domainname)
+ fi
+)
+
+AC_DEFUN(CHECK_NAMED_PIPE_BUG,
+[ AC_CACHE_CHECK(whether named pipes are buggy,
+ local_cv_flag_NAMEDPIPEBUG,
+ cat >conftest.c <<EOF
+#include <fcntl.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+int main(int argc, char** argv)
+{
+ struct timeval tv;
+ fd_set rfds;
+ int fd = open(*(argv+1), O_RDONLY | O_NONBLOCK);
+ FD_ZERO(&rfds);
+ FD_SET(fd,&rfds);
+ tv.tv_sec = tv.tv_usec = 0;
+ return (select(fd+1, &rfds, 0, 0,&tv) > 0) ? 0 : 1;
+}
+EOF
+ if ! ${CC} ${CFLAGS} conftest.c -o conftest 2>/dev/null
+ then
+ echo Compile failed
+ exit 1
+ fi
+ mkfifo conftest.pipe
+ if ./conftest conftest.pipe
+ then
+ AC_DEFINE(NAMEDPIPEBUG, 1)
+ local_cv_flag_NAMEDPIPEBUG=yes
+ else
+ local_cv_flag_NAMEDPIPEBUG=no
+ fi
+ rm -f conftest*)
+])
diff --git a/aclocal.m4 b/aclocal.m4
new file mode 100644
index 0000000..503a518
--- /dev/null
+++ b/aclocal.m4
@@ -0,0 +1,276 @@
+dnl aclocal.m4 generated automatically by aclocal 1.4a
+
+dnl Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl This program is distributed in the hope that it will be useful,
+dnl but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+dnl even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+dnl PARTICULAR PURPOSE.
+
+dnl TRY_CXX_FLAG(FLAG,[ACTION-IF-FOUND[,ACTION-IF-NOT-FOUND]])
+AC_DEFUN(TRY_CXX_FLAG,
+[echo >conftest.cc
+if ${CXX-g++} ${CXXFLAGS} -c [$1] conftest.cc >/dev/null 2>&1; then
+ ifelse([$2], , :, [rm -f conftest*
+ $2])
+else
+ ifelse([$3], , :, [rm -f conftest*
+ $3])
+fi
+rm -f conftest*])
+
+AC_DEFUN(CXX_NO_RTTI,
+[AC_CACHE_CHECK(whether ${CXX-g++} accepts -fno-rtti,
+ local_cv_flag_NO_RTTI,
+ TRY_CXX_FLAG(-fno-rtti,
+ local_cv_flag_NO_RTTI=yes,
+ local_cv_flag_NO_RTTI=no))
+test "$local_cv_flag_NO_RTTI" = yes && CXXFLAGS="$CXXFLAGS -fno-rtti"
+])
+
+AC_DEFUN(CXX_NO_EXCEPTIONS,
+[AC_CACHE_CHECK(whether ${CXX-g++} accepts -fno-exceptions,
+ local_cv_flag_NO_EXCEPTIONS,
+ TRY_CXX_FLAG(-fno-exceptions,
+ local_cv_flag_NO_EXCEPTIONS=yes,
+ local_cv_flag_NO_EXCEPTIONS=no))
+test "$local_cv_flag_NO_EXCEPTIONS" = yes && CXXFLAGS="$CXXFLAGS -fno-exceptions"
+])
+
+dnl TRY_STRUCT_TM_MEMBER(MEMBER,FLAGNAME)
+AC_DEFUN(TRY_STRUCT_TM_MEMBER,
+[ AC_CACHE_CHECK(whether struct tm contains [$1],
+ [$2],
+ cat >conftest.c <<EOF
+#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
+int main() { struct tm* foo; foo->[$1]; }
+EOF
+ if ${CC} ${CFLAGS} -c conftest.c >/dev/null 2>&1; then
+ [$2]=yes
+ else
+ [$2]=no
+ fi
+ rm -f conftest*)
+])
+
+AC_DEFUN(TEST_STRUCT_TM,
+ TRY_STRUCT_TM_MEMBER(tm_isdst, local_cv_flag_TM_HAS_ISDST)
+ TRY_STRUCT_TM_MEMBER(__tm_isdst, local_cv_flag_TM_HAS___ISDST)
+ if test "$local_cv_flag_TM_HAS_ISDST" = yes
+ then AC_DEFINE(TM_HAS_ISDST,tm_isdst)
+ elif test "$local_cv_flag_TM_HAS___ISDST" = yes
+ then AC_DEFINE(TM_HAS_ISDST,__tm_isdst)
+ fi
+ TRY_STRUCT_TM_MEMBER(tm_gmtoff, local_cv_flag_TM_HAS_GMTOFF)
+ TRY_STRUCT_TM_MEMBER(__tm_gmtoff, local_cv_flag_TM_HAS___GMTOFF)
+ if test "$local_cv_flag_TM_HAS_GMTOFF" = yes
+ then AC_DEFINE(TM_HAS_GMTOFF,tm_gmtoff)
+ elif test "$local_cv_flag_TM_HAS___GMTOFF" = yes
+ then AC_DEFINE(TM_HAS_GMTOFF,__tm_gmtoff)
+ fi
+)
+
+dnl TRY_STRUCT_UTSNAME_MEMBER(MEMBER,FLAGNAME)
+AC_DEFUN(TRY_STRUCT_UTSNAME_MEMBER,
+[ AC_CACHE_CHECK(whether struct utsname contains [$1],
+ [$2],
+ cat >conftest.c <<EOF
+#include <sys/utsname.h>
+int main() { struct utsname* foo; foo->[$1]; }
+EOF
+ if ${CC} ${CFLAGS} -c conftest.c >/dev/null 2>&1; then
+ [$2]=yes
+ else
+ [$2]=no
+ fi
+ rm -f conftest*)
+])
+
+AC_DEFUN(TEST_STRUCT_UTSNAME,
+ TRY_STRUCT_UTSNAME_MEMBER(domainname, local_cv_flag_UTSNAME_HAS_DOMAINNAME)
+ TRY_STRUCT_UTSNAME_MEMBER(__domainname,
+ local_cv_flag_UTSNAME_HAS___DOMAINNAME)
+ if test "$local_cv_flag_UTSNAME_HAS_DOMAINNAME" = yes
+ then AC_DEFINE(UTSNAME_HAS_DOMAINNAME,domainname)
+ elif test "$local_cv_flag_UTSNAME_HAS___DOMAINNAME" = yes
+ then AC_DEFINE(UTSNAME_HAS_DOMAINNAME,__domainname)
+ fi
+)
+
+AC_DEFUN(CHECK_NAMED_PIPE_BUG,
+[ AC_CACHE_CHECK(whether named pipes are buggy,
+ local_cv_flag_NAMEDPIPEBUG,
+ cat >conftest.c <<EOF
+#include <fcntl.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+int main(int argc, char** argv)
+{
+ struct timeval tv;
+ fd_set rfds;
+ int fd = open(*(argv+1), O_RDONLY | O_NONBLOCK);
+ FD_ZERO(&rfds);
+ FD_SET(fd,&rfds);
+ tv.tv_sec = tv.tv_usec = 0;
+ return (select(fd+1, &rfds, 0, 0,&tv) > 0) ? 0 : 1;
+}
+EOF
+ if ! ${CC} ${CFLAGS} conftest.c -o conftest 2>/dev/null
+ then
+ echo Compile failed
+ exit 1
+ fi
+ mkfifo conftest.pipe
+ if ./conftest conftest.pipe
+ then
+ AC_DEFINE(NAMEDPIPEBUG, 1)
+ local_cv_flag_NAMEDPIPEBUG=yes
+ else
+ local_cv_flag_NAMEDPIPEBUG=no
+ fi
+ rm -f conftest*)
+])
+
+# Do all the work for Automake. This macro actually does too much --
+# some checks are only needed if your package does certain things.
+# But this isn't really a big deal.
+
+# serial 1
+
+dnl Usage:
+dnl AM_INIT_AUTOMAKE(package,version, [no-define])
+
+AC_DEFUN(AM_INIT_AUTOMAKE,
+[AC_REQUIRE([AC_PROG_INSTALL])
+dnl We require 2.13 because we rely on SHELL being computed by configure.
+AC_PREREQ([2.13])
+PACKAGE=[$1]
+AC_SUBST(PACKAGE)
+VERSION=[$2]
+AC_SUBST(VERSION)
+dnl test to see if srcdir already configured
+if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then
+ AC_MSG_ERROR([source directory already configured; run "make distclean" there first])
+fi
+ifelse([$3],,
+AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package])
+AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package]))
+AC_REQUIRE([AM_SANITY_CHECK])
+AC_REQUIRE([AC_ARG_PROGRAM])
+dnl FIXME This is truly gross.
+missing_dir=`cd $ac_aux_dir && pwd`
+AM_MISSING_PROG(ACLOCAL, aclocal, $missing_dir)
+AM_MISSING_PROG(AUTOCONF, autoconf, $missing_dir)
+AM_MISSING_PROG(AUTOMAKE, automake, $missing_dir)
+AM_MISSING_PROG(AUTOHEADER, autoheader, $missing_dir)
+AM_MISSING_PROG(MAKEINFO, makeinfo, $missing_dir)
+AC_REQUIRE([AC_PROG_MAKE_SET])])
+
+#
+# Check to make sure that the build environment is sane.
+#
+
+AC_DEFUN(AM_SANITY_CHECK,
+[AC_MSG_CHECKING([whether build environment is sane])
+# Just in case
+sleep 1
+echo timestamp > conftestfile
+# Do `set' in a subshell so we don't clobber the current shell's
+# arguments. Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+ set X `ls -Lt $srcdir/configure conftestfile 2> /dev/null`
+ if test "[$]*" = "X"; then
+ # -L didn't work.
+ set X `ls -t $srcdir/configure conftestfile`
+ fi
+ if test "[$]*" != "X $srcdir/configure conftestfile" \
+ && test "[$]*" != "X conftestfile $srcdir/configure"; then
+
+ # If neither matched, then we have a broken ls. This can happen
+ # if, for instance, CONFIG_SHELL is bash and it inherits a
+ # broken ls alias from the environment. This has actually
+ # happened. Such a system could not be considered "sane".
+ AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken
+alias in your environment])
+ fi
+
+ test "[$]2" = conftestfile
+ )
+then
+ # Ok.
+ :
+else
+ AC_MSG_ERROR([newly created file is older than distributed files!
+Check your system clock])
+fi
+rm -f conftest*
+AC_MSG_RESULT(yes)])
+
+dnl AM_MISSING_PROG(NAME, PROGRAM, DIRECTORY)
+dnl The program must properly implement --version.
+AC_DEFUN(AM_MISSING_PROG,
+[AC_MSG_CHECKING(for working $2)
+# Run test in a subshell; some versions of sh will print an error if
+# an executable is not found, even if stderr is redirected.
+# Redirect stdin to placate older versions of autoconf. Sigh.
+if ($2 --version) < /dev/null > /dev/null 2>&1; then
+ $1=$2
+ AC_MSG_RESULT(found)
+else
+ $1="$3/missing $2"
+ AC_MSG_RESULT(missing)
+fi
+AC_SUBST($1)])
+
+# Like AC_CONFIG_HEADER, but automatically create stamp file.
+
+AC_DEFUN(AM_CONFIG_HEADER,
+[AC_PREREQ([2.12])
+AC_CONFIG_HEADER([$1])
+dnl When config.status generates a header, we must update the stamp-h file.
+dnl This file resides in the same directory as the config header
+dnl that is generated. We must strip everything past the first ":",
+dnl and everything past the last "/".
+AC_OUTPUT_COMMANDS(changequote(<<,>>)dnl
+ifelse(patsubst(<<$1>>, <<[^ ]>>, <<>>), <<>>,
+<<test -z "<<$>>CONFIG_HEADERS" || echo timestamp > patsubst(<<$1>>, <<^\([^:]*/\)?.*>>, <<\1>>)stamp-h<<>>dnl>>,
+<<am_indx=1
+for am_file in <<$1>>; do
+ case " <<$>>CONFIG_HEADERS " in
+ *" <<$>>am_file "*<<)>>
+ echo timestamp > `echo <<$>>am_file | sed -e 's%:.*%%' -e 's%[^/]*$%%'`stamp-h$am_indx
+ ;;
+ esac
+ am_indx=`expr "<<$>>am_indx" + 1`
+done<<>>dnl>>)
+changequote([,]))])
+
+# Define a conditional.
+
+AC_DEFUN(AM_CONDITIONAL,
+[AC_SUBST($1_TRUE)
+AC_SUBST($1_FALSE)
+if $2; then
+ $1_TRUE=
+ $1_FALSE='#'
+else
+ $1_TRUE='#'
+ $1_FALSE=
+fi])
+
diff --git a/config.h.in b/config.h.in
new file mode 100644
index 0000000..364b9f2
--- /dev/null
+++ b/config.h.in
@@ -0,0 +1,67 @@
+/* config.h.in. Generated automatically from configure.in by autoheader. */
+
+/* Define if you have <sys/wait.h> that is POSIX.1 compatible. */
+#undef HAVE_SYS_WAIT_H
+
+/* Define to `unsigned' if <sys/types.h> doesn't define. */
+#undef size_t
+
+/* Define if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Define if you can safely include both <sys/time.h> and <time.h>. */
+#undef TIME_WITH_SYS_TIME
+
+/* Generic buffer size */
+#undef BUFSIZE
+
+#undef TM_HAS_GMTOFF
+
+#undef TM_HAS_ISDST
+
+#undef UTSNAME_HAS_DOMAINNAME
+
+#undef NAMEDPIPEBUG
+
+/* Define if you have the getdomainname function. */
+#undef HAVE_GETDOMAINNAME
+
+/* Define if you have the gethostname function. */
+#undef HAVE_GETHOSTNAME
+
+/* Define if you have the setenv function. */
+#undef HAVE_SETENV
+
+/* Define if you have the srandom function. */
+#undef HAVE_SRANDOM
+
+/* Define if you have the <dirent.h> header file. */
+#undef HAVE_DIRENT_H
+
+/* Define if you have the <ndir.h> header file. */
+#undef HAVE_NDIR_H
+
+/* Define if you have the <sys/dir.h> header file. */
+#undef HAVE_SYS_DIR_H
+
+/* Define if you have the <sys/ndir.h> header file. */
+#undef HAVE_SYS_NDIR_H
+
+/* Define if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define if you have the inet library (-linet). */
+#undef HAVE_LIBINET
+
+/* Define if you have the socket library (-lsocket). */
+#undef HAVE_LIBSOCKET
+
+/* Define if you have the xnet library (-lxnet). */
+#undef HAVE_LIBXNET
+
+/* Name of package */
+#undef PACKAGE
+
+/* Version number of package */
+#undef VERSION
+
diff --git a/configure b/configure
new file mode 100755
index 0000000..0961211
--- /dev/null
+++ b/configure
@@ -0,0 +1,2777 @@
+#! /bin/sh
+
+
+
+
+
+
+
+
+
+# Do all the work for Automake. This macro actually does too much --
+# some checks are only needed if your package does certain things.
+# But this isn't really a big deal.
+
+# serial 1
+
+
+
+
+#
+# Check to make sure that the build environment is sane.
+#
+
+
+
+
+
+# Like AC_CONFIG_HEADER, but automatically create stamp file.
+
+
+
+# Define a conditional.
+
+
+
+# Guess values for system-dependent variables and create Makefiles.
+# Generated automatically using autoconf version 2.13
+# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc.
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+
+# Defaults:
+ac_help=
+ac_default_prefix=/usr/local
+# Any additions from configure.in:
+
+# Initialize some variables set by options.
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+build=NONE
+cache_file=./config.cache
+exec_prefix=NONE
+host=NONE
+no_create=
+nonopt=NONE
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+target=NONE
+verbose=
+x_includes=NONE
+x_libraries=NONE
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datadir='${prefix}/share'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+libdir='${exec_prefix}/lib'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+infodir='${prefix}/info'
+mandir='${prefix}/man'
+
+# Initialize some other variables.
+subdirs=
+MFLAGS= MAKEFLAGS=
+SHELL=${CONFIG_SHELL-/bin/sh}
+# Maximum number of lines to put in a shell here document.
+ac_max_here_lines=12
+
+ac_prev=
+for ac_option
+do
+
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval "$ac_prev=\$ac_option"
+ ac_prev=
+ continue
+ fi
+
+ case "$ac_option" in
+ -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+ *) ac_optarg= ;;
+ esac
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case "$ac_option" in
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir="$ac_optarg" ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build="$ac_optarg" ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file="$ac_optarg" ;;
+
+ -datadir | --datadir | --datadi | --datad | --data | --dat | --da)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
+ | --da=*)
+ datadir="$ac_optarg" ;;
+
+ -disable-* | --disable-*)
+ ac_feature=`echo $ac_option|sed -e 's/-*disable-//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then
+ { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+ fi
+ ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+ eval "enable_${ac_feature}=no" ;;
+
+ -enable-* | --enable-*)
+ ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then
+ { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+ fi
+ ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+ case "$ac_option" in
+ *=*) ;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "enable_${ac_feature}='$ac_optarg'" ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix="$ac_optarg" ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he)
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat << EOF
+Usage: configure [options] [host]
+Options: [defaults in brackets after descriptions]
+Configuration:
+ --cache-file=FILE cache test results in FILE
+ --help print this message
+ --no-create do not create output files
+ --quiet, --silent do not print \`checking...' messages
+ --version print the version of autoconf that created configure
+Directory and file names:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [same as prefix]
+ --bindir=DIR user executables in DIR [EPREFIX/bin]
+ --sbindir=DIR system admin executables in DIR [EPREFIX/sbin]
+ --libexecdir=DIR program executables in DIR [EPREFIX/libexec]
+ --datadir=DIR read-only architecture-independent data in DIR
+ [PREFIX/share]
+ --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data in DIR
+ [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data in DIR [PREFIX/var]
+ --libdir=DIR object code libraries in DIR [EPREFIX/lib]
+ --includedir=DIR C header files in DIR [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include]
+ --infodir=DIR info documentation in DIR [PREFIX/info]
+ --mandir=DIR man documentation in DIR [PREFIX/man]
+ --srcdir=DIR find the sources in DIR [configure dir or ..]
+ --program-prefix=PREFIX prepend PREFIX to installed program names
+ --program-suffix=SUFFIX append SUFFIX to installed program names
+ --program-transform-name=PROGRAM
+ run sed PROGRAM on installed program names
+EOF
+ cat << EOF
+Host type:
+ --build=BUILD configure for building on BUILD [BUILD=HOST]
+ --host=HOST configure for HOST [guessed]
+ --target=TARGET configure for TARGET [TARGET=HOST]
+Features and packages:
+ --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
+ --enable-FEATURE[=ARG] include FEATURE [ARG=yes]
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --x-includes=DIR X include files are in DIR
+ --x-libraries=DIR X library files are in DIR
+EOF
+ if test -n "$ac_help"; then
+ echo "--enable and --with options recognized:$ac_help"
+ fi
+ exit 0 ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host="$ac_optarg" ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir="$ac_optarg" ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir="$ac_optarg" ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir="$ac_optarg" ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir="$ac_optarg" ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst \
+ | --locals | --local | --loca | --loc | --lo)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* \
+ | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
+ localstatedir="$ac_optarg" ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir="$ac_optarg" ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir="$ac_optarg" ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix="$ac_optarg" ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix="$ac_optarg" ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix="$ac_optarg" ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name="$ac_optarg" ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir="$ac_optarg" ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir="$ac_optarg" ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site="$ac_optarg" ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir="$ac_optarg" ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir="$ac_optarg" ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target="$ac_optarg" ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers)
+ echo "configure generated by autoconf version 2.13"
+ exit 0 ;;
+
+ -with-* | --with-*)
+ ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then
+ { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+ fi
+ ac_package=`echo $ac_package| sed 's/-/_/g'`
+ case "$ac_option" in
+ *=*) ;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "with_${ac_package}='$ac_optarg'" ;;
+
+ -without-* | --without-*)
+ ac_package=`echo $ac_option|sed -e 's/-*without-//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then
+ { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+ fi
+ ac_package=`echo $ac_package| sed 's/-/_/g'`
+ eval "with_${ac_package}=no" ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes="$ac_optarg" ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries="$ac_optarg" ;;
+
+ -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; }
+ ;;
+
+ *)
+ if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then
+ echo "configure: warning: $ac_option: invalid host type" 1>&2
+ fi
+ if test "x$nonopt" != xNONE; then
+ { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; }
+ fi
+ nonopt="$ac_option"
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; }
+fi
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+# File descriptor usage:
+# 0 standard input
+# 1 file creation
+# 2 errors and warnings
+# 3 some systems may open it to /dev/tty
+# 4 used on the Kubota Titan
+# 6 checking for... messages and results
+# 5 compiler messages saved in config.log
+if test "$silent" = yes; then
+ exec 6>/dev/null
+else
+ exec 6>&1
+fi
+exec 5>./config.log
+
+echo "\
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+" 1>&5
+
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Also quote any args containing shell metacharacters.
+ac_configure_args=
+for ac_arg
+do
+ case "$ac_arg" in
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c) ;;
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;;
+ *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*)
+ ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+ *) ac_configure_args="$ac_configure_args $ac_arg" ;;
+ esac
+done
+
+# NLS nuisances.
+# Only set these to C if already set. These must not be set unconditionally
+# because not all systems understand e.g. LANG=C (notably SCO).
+# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'!
+# Non-C LC_CTYPE values break the ctype check.
+if test "${LANG+set}" = set; then LANG=C; export LANG; fi
+if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi
+if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi
+if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -rf conftest* confdefs.h
+# AIX cpp loses on an empty file, so make sure it contains at least a newline.
+echo > confdefs.h
+
+# A filename unique to this package, relative to the directory that
+# configure is in, which we can look for to find out if srcdir is correct.
+ac_unique_file=lib/defines.h
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then its parent.
+ ac_prog=$0
+ ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'`
+ test "x$ac_confdir" = "x$ac_prog" && ac_confdir=.
+ srcdir=$ac_confdir
+ if test ! -r $srcdir/$ac_unique_file; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r $srcdir/$ac_unique_file; then
+ if test "$ac_srcdir_defaulted" = yes; then
+ { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; }
+ else
+ { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; }
+ fi
+fi
+srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'`
+
+# Prefer explicitly selected file to automatically selected ones.
+if test -z "$CONFIG_SITE"; then
+ if test "x$prefix" != xNONE; then
+ CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
+ else
+ CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
+ fi
+fi
+for ac_site_file in $CONFIG_SITE; do
+ if test -r "$ac_site_file"; then
+ echo "loading site script $ac_site_file"
+ . "$ac_site_file"
+ fi
+done
+
+if test -r "$cache_file"; then
+ echo "loading cache $cache_file"
+ . $cache_file
+else
+ echo "creating cache $cache_file"
+ > $cache_file
+fi
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+ac_exeext=
+ac_objext=o
+if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then
+ # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu.
+ if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then
+ ac_n= ac_c='
+' ac_t=' '
+ else
+ ac_n=-n ac_c= ac_t=
+ fi
+else
+ ac_n= ac_c='\c' ac_t=
+fi
+
+
+ac_aux_dir=
+for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do
+ if test -f $ac_dir/install-sh; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install-sh -c"
+ break
+ elif test -f $ac_dir/install.sh; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install.sh -c"
+ break
+ fi
+done
+if test -z "$ac_aux_dir"; then
+ { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; }
+fi
+ac_config_guess=$ac_aux_dir/config.guess
+ac_config_sub=$ac_aux_dir/config.sub
+ac_configure=$ac_aux_dir/configure # This should be Cygnus configure.
+
+# Find a good install program. We prefer a C program (faster),
+# so one script is as good as another. But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# ./install, which can be erroneously created by make from ./install.sh.
+echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6
+echo "configure:589: checking for a BSD compatible install" >&5
+if test -z "$INSTALL"; then
+if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ IFS="${IFS= }"; ac_save_IFS="$IFS"; IFS=":"
+ for ac_dir in $PATH; do
+ # Account for people who put trailing slashes in PATH elements.
+ case "$ac_dir/" in
+ /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;;
+ *)
+ # OSF1 and SCO ODT 3.0 have their own names for install.
+ # Don't use installbsd from OSF since it installs stuff as root
+ # by default.
+ for ac_prog in ginstall scoinst install; do
+ if test -f $ac_dir/$ac_prog; then
+ if test $ac_prog = install &&
+ grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then
+ # AIX install. It has an incompatible calling convention.
+ :
+ else
+ ac_cv_path_install="$ac_dir/$ac_prog -c"
+ break 2
+ fi
+ fi
+ done
+ ;;
+ esac
+ done
+ IFS="$ac_save_IFS"
+
+fi
+ if test "${ac_cv_path_install+set}" = set; then
+ INSTALL="$ac_cv_path_install"
+ else
+ # As a last resort, use the slow shell script. We don't cache a
+ # path for INSTALL within a source directory, because that will
+ # break other packages using the cache if that directory is
+ # removed, or if the path is relative.
+ INSTALL="$ac_install_sh"
+ fi
+fi
+echo "$ac_t""$INSTALL" 1>&6
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+echo $ac_n "checking whether build environment is sane""... $ac_c" 1>&6
+echo "configure:642: checking whether build environment is sane" >&5
+# Just in case
+sleep 1
+echo timestamp > conftestfile
+# Do `set' in a subshell so we don't clobber the current shell's
+# arguments. Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+ set X `ls -Lt $srcdir/configure conftestfile 2> /dev/null`
+ if test "$*" = "X"; then
+ # -L didn't work.
+ set X `ls -t $srcdir/configure conftestfile`
+ fi
+ if test "$*" != "X $srcdir/configure conftestfile" \
+ && test "$*" != "X conftestfile $srcdir/configure"; then
+
+ # If neither matched, then we have a broken ls. This can happen
+ # if, for instance, CONFIG_SHELL is bash and it inherits a
+ # broken ls alias from the environment. This has actually
+ # happened. Such a system could not be considered "sane".
+ { echo "configure: error: ls -t appears to fail. Make sure there is not a broken
+alias in your environment" 1>&2; exit 1; }
+ fi
+
+ test "$2" = conftestfile
+ )
+then
+ # Ok.
+ :
+else
+ { echo "configure: error: newly created file is older than distributed files!
+Check your system clock" 1>&2; exit 1; }
+fi
+rm -f conftest*
+echo "$ac_t""yes" 1>&6
+if test "$program_transform_name" = s,x,x,; then
+ program_transform_name=
+else
+ # Double any \ or $. echo might interpret backslashes.
+ cat <<\EOF_SED > conftestsed
+s,\\,\\\\,g; s,\$,$$,g
+EOF_SED
+ program_transform_name="`echo $program_transform_name|sed -f conftestsed`"
+ rm -f conftestsed
+fi
+test "$program_prefix" != NONE &&
+ program_transform_name="s,^,${program_prefix},; $program_transform_name"
+# Use a double $ so make ignores it.
+test "$program_suffix" != NONE &&
+ program_transform_name="s,\$\$,${program_suffix},; $program_transform_name"
+
+# sed with no file args requires a program.
+test "$program_transform_name" = "" && program_transform_name="s,x,x,"
+
+echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6
+echo "configure:699: checking whether ${MAKE-make} sets \${MAKE}" >&5
+set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftestmake <<\EOF
+all:
+ @echo 'ac_maketemp="${MAKE}"'
+EOF
+# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
+eval `${MAKE-make} -f conftestmake 2>/dev/null | grep temp=`
+if test -n "$ac_maketemp"; then
+ eval ac_cv_prog_make_${ac_make}_set=yes
+else
+ eval ac_cv_prog_make_${ac_make}_set=no
+fi
+rm -f conftestmake
+fi
+if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ SET_MAKE=
+else
+ echo "$ac_t""no" 1>&6
+ SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+
+
+PACKAGE=nullmailer
+
+VERSION=1.00RC5
+
+if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then
+ { echo "configure: error: source directory already configured; run "make distclean" there first" 1>&2; exit 1; }
+fi
+cat >> confdefs.h <<EOF
+#define PACKAGE "$PACKAGE"
+EOF
+
+cat >> confdefs.h <<EOF
+#define VERSION "$VERSION"
+EOF
+
+
+
+missing_dir=`cd $ac_aux_dir && pwd`
+echo $ac_n "checking for working aclocal""... $ac_c" 1>&6
+echo "configure:746: checking for working aclocal" >&5
+# Run test in a subshell; some versions of sh will print an error if
+# an executable is not found, even if stderr is redirected.
+# Redirect stdin to placate older versions of autoconf. Sigh.
+if (aclocal --version) < /dev/null > /dev/null 2>&1; then
+ ACLOCAL=aclocal
+ echo "$ac_t""found" 1>&6
+else
+ ACLOCAL="$missing_dir/missing aclocal"
+ echo "$ac_t""missing" 1>&6
+fi
+
+echo $ac_n "checking for working autoconf""... $ac_c" 1>&6
+echo "configure:759: checking for working autoconf" >&5
+# Run test in a subshell; some versions of sh will print an error if
+# an executable is not found, even if stderr is redirected.
+# Redirect stdin to placate older versions of autoconf. Sigh.
+if (autoconf --version) < /dev/null > /dev/null 2>&1; then
+ AUTOCONF=autoconf
+ echo "$ac_t""found" 1>&6
+else
+ AUTOCONF="$missing_dir/missing autoconf"
+ echo "$ac_t""missing" 1>&6
+fi
+
+echo $ac_n "checking for working automake""... $ac_c" 1>&6
+echo "configure:772: checking for working automake" >&5
+# Run test in a subshell; some versions of sh will print an error if
+# an executable is not found, even if stderr is redirected.
+# Redirect stdin to placate older versions of autoconf. Sigh.
+if (automake --version) < /dev/null > /dev/null 2>&1; then
+ AUTOMAKE=automake
+ echo "$ac_t""found" 1>&6
+else
+ AUTOMAKE="$missing_dir/missing automake"
+ echo "$ac_t""missing" 1>&6
+fi
+
+echo $ac_n "checking for working autoheader""... $ac_c" 1>&6
+echo "configure:785: checking for working autoheader" >&5
+# Run test in a subshell; some versions of sh will print an error if
+# an executable is not found, even if stderr is redirected.
+# Redirect stdin to placate older versions of autoconf. Sigh.
+if (autoheader --version) < /dev/null > /dev/null 2>&1; then
+ AUTOHEADER=autoheader
+ echo "$ac_t""found" 1>&6
+else
+ AUTOHEADER="$missing_dir/missing autoheader"
+ echo "$ac_t""missing" 1>&6
+fi
+
+echo $ac_n "checking for working makeinfo""... $ac_c" 1>&6
+echo "configure:798: checking for working makeinfo" >&5
+# Run test in a subshell; some versions of sh will print an error if
+# an executable is not found, even if stderr is redirected.
+# Redirect stdin to placate older versions of autoconf. Sigh.
+if (makeinfo --version) < /dev/null > /dev/null 2>&1; then
+ MAKEINFO=makeinfo
+ echo "$ac_t""found" 1>&6
+else
+ MAKEINFO="$missing_dir/missing makeinfo"
+ echo "$ac_t""missing" 1>&6
+fi
+
+
+
+
+
+echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6
+echo "configure:815: checking whether ${MAKE-make} sets \${MAKE}" >&5
+set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftestmake <<\EOF
+all:
+ @echo 'ac_maketemp="${MAKE}"'
+EOF
+# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
+eval `${MAKE-make} -f conftestmake 2>/dev/null | grep temp=`
+if test -n "$ac_maketemp"; then
+ eval ac_cv_prog_make_${ac_make}_set=yes
+else
+ eval ac_cv_prog_make_${ac_make}_set=no
+fi
+rm -f conftestmake
+fi
+if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ SET_MAKE=
+else
+ echo "$ac_t""no" 1>&6
+ SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+
+# Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:845: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_CC="gcc"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+ echo "$ac_t""$CC" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+if test -z "$CC"; then
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:875: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_prog_rejected=no
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+ fi
+ ac_cv_prog_CC="cc"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+if test $ac_prog_rejected = yes; then
+ # We found a bogon in the path, so make sure we never use it.
+ set dummy $ac_cv_prog_CC
+ shift
+ if test $# -gt 0; then
+ # We chose a different compiler from the bogus one.
+ # However, it has the same basename, so the bogon will be chosen
+ # first if we set CC to just the basename; use the full file name.
+ shift
+ set dummy "$ac_dir/$ac_word" "$@"
+ shift
+ ac_cv_prog_CC="$@"
+ fi
+fi
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+ echo "$ac_t""$CC" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+ if test -z "$CC"; then
+ case "`uname -s`" in
+ *win32* | *WIN32*)
+ # Extract the first word of "cl", so it can be a program name with args.
+set dummy cl; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:926: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_CC="cl"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+ echo "$ac_t""$CC" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+ ;;
+ esac
+ fi
+ test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; }
+fi
+
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6
+echo "configure:958: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+cat > conftest.$ac_ext << EOF
+
+#line 969 "configure"
+#include "confdefs.h"
+
+main(){return(0);}
+EOF
+if { (eval echo configure:974: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ ac_cv_prog_cc_works=yes
+ # If we can't run a trivial program, we are probably using a cross compiler.
+ if (./conftest; exit) 2>/dev/null; then
+ ac_cv_prog_cc_cross=no
+ else
+ ac_cv_prog_cc_cross=yes
+ fi
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ ac_cv_prog_cc_works=no
+fi
+rm -fr conftest*
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo "$ac_t""$ac_cv_prog_cc_works" 1>&6
+if test $ac_cv_prog_cc_works = no; then
+ { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; }
+fi
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6
+echo "configure:1000: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5
+echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6
+echo "configure:1005: checking whether we are using GNU C" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.c <<EOF
+#ifdef __GNUC__
+ yes;
+#endif
+EOF
+if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:1014: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
+ ac_cv_prog_gcc=yes
+else
+ ac_cv_prog_gcc=no
+fi
+fi
+
+echo "$ac_t""$ac_cv_prog_gcc" 1>&6
+
+if test $ac_cv_prog_gcc = yes; then
+ GCC=yes
+else
+ GCC=
+fi
+
+ac_test_CFLAGS="${CFLAGS+set}"
+ac_save_CFLAGS="$CFLAGS"
+CFLAGS=
+echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6
+echo "configure:1033: checking whether ${CC-cc} accepts -g" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ echo 'void f(){}' > conftest.c
+if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then
+ ac_cv_prog_cc_g=yes
+else
+ ac_cv_prog_cc_g=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_prog_cc_g" 1>&6
+if test "$ac_test_CFLAGS" = set; then
+ CFLAGS="$ac_save_CFLAGS"
+elif test $ac_cv_prog_cc_g = yes; then
+ if test "$GCC" = yes; then
+ CFLAGS="-g -O2"
+ else
+ CFLAGS="-g"
+ fi
+else
+ if test "$GCC" = yes; then
+ CFLAGS="-O2"
+ else
+ CFLAGS=
+ fi
+fi
+
+for ac_prog in $CCC c++ g++ gcc CC cxx cc++ cl
+do
+# Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1069: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CXX'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$CXX"; then
+ ac_cv_prog_CXX="$CXX" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_CXX="$ac_prog"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+fi
+fi
+CXX="$ac_cv_prog_CXX"
+if test -n "$CXX"; then
+ echo "$ac_t""$CXX" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+test -n "$CXX" && break
+done
+test -n "$CXX" || CXX="gcc"
+
+
+echo $ac_n "checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works""... $ac_c" 1>&6
+echo "configure:1101: checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works" >&5
+
+ac_ext=C
+# CXXFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='${CXX-g++} -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CXX-g++} -o conftest${ac_exeext} $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cxx_cross
+
+cat > conftest.$ac_ext << EOF
+
+#line 1112 "configure"
+#include "confdefs.h"
+
+int main(){return(0);}
+EOF
+if { (eval echo configure:1117: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ ac_cv_prog_cxx_works=yes
+ # If we can't run a trivial program, we are probably using a cross compiler.
+ if (./conftest; exit) 2>/dev/null; then
+ ac_cv_prog_cxx_cross=no
+ else
+ ac_cv_prog_cxx_cross=yes
+ fi
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ ac_cv_prog_cxx_works=no
+fi
+rm -fr conftest*
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo "$ac_t""$ac_cv_prog_cxx_works" 1>&6
+if test $ac_cv_prog_cxx_works = no; then
+ { echo "configure: error: installation or configuration problem: C++ compiler cannot create executables." 1>&2; exit 1; }
+fi
+echo $ac_n "checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6
+echo "configure:1143: checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) is a cross-compiler" >&5
+echo "$ac_t""$ac_cv_prog_cxx_cross" 1>&6
+cross_compiling=$ac_cv_prog_cxx_cross
+
+echo $ac_n "checking whether we are using GNU C++""... $ac_c" 1>&6
+echo "configure:1148: checking whether we are using GNU C++" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_gxx'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.C <<EOF
+#ifdef __GNUC__
+ yes;
+#endif
+EOF
+if { ac_try='${CXX-g++} -E conftest.C'; { (eval echo configure:1157: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
+ ac_cv_prog_gxx=yes
+else
+ ac_cv_prog_gxx=no
+fi
+fi
+
+echo "$ac_t""$ac_cv_prog_gxx" 1>&6
+
+if test $ac_cv_prog_gxx = yes; then
+ GXX=yes
+else
+ GXX=
+fi
+
+ac_test_CXXFLAGS="${CXXFLAGS+set}"
+ac_save_CXXFLAGS="$CXXFLAGS"
+CXXFLAGS=
+echo $ac_n "checking whether ${CXX-g++} accepts -g""... $ac_c" 1>&6
+echo "configure:1176: checking whether ${CXX-g++} accepts -g" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_cxx_g'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ echo 'void f(){}' > conftest.cc
+if test -z "`${CXX-g++} -g -c conftest.cc 2>&1`"; then
+ ac_cv_prog_cxx_g=yes
+else
+ ac_cv_prog_cxx_g=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_prog_cxx_g" 1>&6
+if test "$ac_test_CXXFLAGS" = set; then
+ CXXFLAGS="$ac_save_CXXFLAGS"
+elif test $ac_cv_prog_cxx_g = yes; then
+ if test "$GXX" = yes; then
+ CXXFLAGS="-g -O2"
+ else
+ CXXFLAGS="-g"
+ fi
+else
+ if test "$GXX" = yes; then
+ CXXFLAGS="-O2"
+ else
+ CXXFLAGS=
+ fi
+fi
+
+echo $ac_n "checking whether ${CXX-g++} accepts -fno-rtti""... $ac_c" 1>&6
+echo "configure:1208: checking whether ${CXX-g++} accepts -fno-rtti" >&5
+if eval "test \"`echo '$''{'local_cv_flag_NO_RTTI'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ echo >conftest.cc
+if ${CXX-g++} ${CXXFLAGS} -c -fno-rtti conftest.cc >/dev/null 2>&1; then
+ rm -f conftest*
+ local_cv_flag_NO_RTTI=yes
+else
+ rm -f conftest*
+ local_cv_flag_NO_RTTI=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$local_cv_flag_NO_RTTI" 1>&6
+test "$local_cv_flag_NO_RTTI" = yes && CXXFLAGS="$CXXFLAGS -fno-rtti"
+
+echo $ac_n "checking whether ${CXX-g++} accepts -fno-exceptions""... $ac_c" 1>&6
+echo "configure:1227: checking whether ${CXX-g++} accepts -fno-exceptions" >&5
+if eval "test \"`echo '$''{'local_cv_flag_NO_EXCEPTIONS'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ echo >conftest.cc
+if ${CXX-g++} ${CXXFLAGS} -c -fno-exceptions conftest.cc >/dev/null 2>&1; then
+ rm -f conftest*
+ local_cv_flag_NO_EXCEPTIONS=yes
+else
+ rm -f conftest*
+ local_cv_flag_NO_EXCEPTIONS=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$local_cv_flag_NO_EXCEPTIONS" 1>&6
+test "$local_cv_flag_NO_EXCEPTIONS" = yes && CXXFLAGS="$CXXFLAGS -fno-exceptions"
+
+
+CFLAGS="$CFLAGS -W -Wall"
+CXXFLAGS="$CXXFLAGS -W -Wall"
+
+# Find a good install program. We prefer a C program (faster),
+# so one script is as good as another. But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# ./install, which can be erroneously created by make from ./install.sh.
+echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6
+echo "configure:1261: checking for a BSD compatible install" >&5
+if test -z "$INSTALL"; then
+if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ IFS="${IFS= }"; ac_save_IFS="$IFS"; IFS=":"
+ for ac_dir in $PATH; do
+ # Account for people who put trailing slashes in PATH elements.
+ case "$ac_dir/" in
+ /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;;
+ *)
+ # OSF1 and SCO ODT 3.0 have their own names for install.
+ # Don't use installbsd from OSF since it installs stuff as root
+ # by default.
+ for ac_prog in ginstall scoinst install; do
+ if test -f $ac_dir/$ac_prog; then
+ if test $ac_prog = install &&
+ grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then
+ # AIX install. It has an incompatible calling convention.
+ :
+ else
+ ac_cv_path_install="$ac_dir/$ac_prog -c"
+ break 2
+ fi
+ fi
+ done
+ ;;
+ esac
+ done
+ IFS="$ac_save_IFS"
+
+fi
+ if test "${ac_cv_path_install+set}" = set; then
+ INSTALL="$ac_cv_path_install"
+ else
+ # As a last resort, use the slow shell script. We don't cache a
+ # path for INSTALL within a source directory, because that will
+ # break other packages using the cache if that directory is
+ # removed, or if the path is relative.
+ INSTALL="$ac_install_sh"
+ fi
+fi
+echo "$ac_t""$INSTALL" 1>&6
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+# Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1316: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$RANLIB"; then
+ ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_RANLIB="ranlib"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+ test -z "$ac_cv_prog_RANLIB" && ac_cv_prog_RANLIB=":"
+fi
+fi
+RANLIB="$ac_cv_prog_RANLIB"
+if test -n "$RANLIB"; then
+ echo "$ac_t""$RANLIB" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+# Extract the first word of "strip", so it can be a program name with args.
+set dummy strip; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1346: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_path_STRIP'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ case "$STRIP" in
+ /*)
+ ac_cv_path_STRIP="$STRIP" # Let the user override the test with a path.
+ ;;
+ ?:/*)
+ ac_cv_path_STRIP="$STRIP" # Let the user override the test with a dos path.
+ ;;
+ *)
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_path_STRIP="$ac_dir/$ac_word"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+ ;;
+esac
+fi
+STRIP="$ac_cv_path_STRIP"
+if test -n "$STRIP"; then
+ echo "$ac_t""$STRIP" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+# Extract the first word of "rm", so it can be a program name with args.
+set dummy rm; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1381: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_path_RM'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ case "$RM" in
+ /*)
+ ac_cv_path_RM="$RM" # Let the user override the test with a path.
+ ;;
+ ?:/*)
+ ac_cv_path_RM="$RM" # Let the user override the test with a dos path.
+ ;;
+ *)
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_path_RM="$ac_dir/$ac_word"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+ ;;
+esac
+fi
+RM="$ac_cv_path_RM"
+if test -n "$RM"; then
+ echo "$ac_t""$RM" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+# Extract the first word of "mkdir", so it can be a program name with args.
+set dummy mkdir; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1416: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_path_MKDIR'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ case "$MKDIR" in
+ /*)
+ ac_cv_path_MKDIR="$MKDIR" # Let the user override the test with a path.
+ ;;
+ ?:/*)
+ ac_cv_path_MKDIR="$MKDIR" # Let the user override the test with a dos path.
+ ;;
+ *)
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_path_MKDIR="$ac_dir/$ac_word"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+ ;;
+esac
+fi
+MKDIR="$ac_cv_path_MKDIR"
+if test -n "$MKDIR"; then
+ echo "$ac_t""$MKDIR" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+
+echo $ac_n "checking for socket in -lxnet""... $ac_c" 1>&6
+echo "configure:1450: checking for socket in -lxnet" >&5
+ac_lib_var=`echo xnet'_'socket | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lxnet $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1458 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char socket();
+
+int main() {
+socket()
+; return 0; }
+EOF
+if { (eval echo configure:1469: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_lib=HAVE_LIB`echo xnet | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+ LIBS="-lxnet $LIBS"
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+echo $ac_n "checking for socket in -linet""... $ac_c" 1>&6
+echo "configure:1497: checking for socket in -linet" >&5
+ac_lib_var=`echo inet'_'socket | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-linet $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1505 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char socket();
+
+int main() {
+socket()
+; return 0; }
+EOF
+if { (eval echo configure:1516: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_lib=HAVE_LIB`echo inet | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+ LIBS="-linet $LIBS"
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+echo $ac_n "checking for socket in -lsocket""... $ac_c" 1>&6
+echo "configure:1544: checking for socket in -lsocket" >&5
+ac_lib_var=`echo socket'_'socket | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lsocket $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1552 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char socket();
+
+int main() {
+socket()
+; return 0; }
+EOF
+if { (eval echo configure:1563: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_lib=HAVE_LIB`echo socket | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+ LIBS="-lsocket $LIBS"
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+
+ac_header_dirent=no
+for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr that defines DIR""... $ac_c" 1>&6
+echo "configure:1596: checking for $ac_hdr that defines DIR" >&5
+if eval "test \"`echo '$''{'ac_cv_header_dirent_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1601 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <$ac_hdr>
+int main() {
+DIR *dirp = 0;
+; return 0; }
+EOF
+if { (eval echo configure:1609: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ eval "ac_cv_header_dirent_$ac_safe=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_dirent_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_dirent_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+ ac_header_dirent=$ac_hdr; break
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+# Two versions of opendir et al. are in -ldir and -lx on SCO Xenix.
+if test $ac_header_dirent = dirent.h; then
+echo $ac_n "checking for opendir in -ldir""... $ac_c" 1>&6
+echo "configure:1634: checking for opendir in -ldir" >&5
+ac_lib_var=`echo dir'_'opendir | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-ldir $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1642 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char opendir();
+
+int main() {
+opendir()
+; return 0; }
+EOF
+if { (eval echo configure:1653: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ LIBS="$LIBS -ldir"
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+else
+echo $ac_n "checking for opendir in -lx""... $ac_c" 1>&6
+echo "configure:1675: checking for opendir in -lx" >&5
+ac_lib_var=`echo x'_'opendir | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lx $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1683 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char opendir();
+
+int main() {
+opendir()
+; return 0; }
+EOF
+if { (eval echo configure:1694: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ LIBS="$LIBS -lx"
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+fi
+
+echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6
+echo "configure:1717: checking how to run the C preprocessor" >&5
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+ CPP=
+fi
+if test -z "$CPP"; then
+if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ # This must be in double quotes, not single quotes, because CPP may get
+ # substituted into the Makefile and "${CC-cc}" will confuse make.
+ CPP="${CC-cc} -E"
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp.
+ cat > conftest.$ac_ext <<EOF
+#line 1732 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1738: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ :
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ CPP="${CC-cc} -E -traditional-cpp"
+ cat > conftest.$ac_ext <<EOF
+#line 1749 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1755: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ :
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ CPP="${CC-cc} -nologo -E"
+ cat > conftest.$ac_ext <<EOF
+#line 1766 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1772: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ :
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ CPP=/lib/cpp
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+ ac_cv_prog_CPP="$CPP"
+fi
+ CPP="$ac_cv_prog_CPP"
+else
+ ac_cv_prog_CPP="$CPP"
+fi
+echo "$ac_t""$CPP" 1>&6
+
+echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6
+echo "configure:1797: checking for ANSI C header files" >&5
+if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1802 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1810: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ ac_cv_header_stdc=yes
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+if test $ac_cv_header_stdc = yes; then
+ # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 1827 "configure"
+#include "confdefs.h"
+#include <string.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "memchr" >/dev/null 2>&1; then
+ :
+else
+ rm -rf conftest*
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 1845 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "free" >/dev/null 2>&1; then
+ :
+else
+ rm -rf conftest*
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+if test "$cross_compiling" = yes; then
+ :
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1866 "configure"
+#include "confdefs.h"
+#include <ctype.h>
+#define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int main () { int i; for (i = 0; i < 256; i++)
+if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2);
+exit (0); }
+
+EOF
+if { (eval echo configure:1877: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ :
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ ac_cv_header_stdc=no
+fi
+rm -fr conftest*
+fi
+
+fi
+fi
+
+echo "$ac_t""$ac_cv_header_stdc" 1>&6
+if test $ac_cv_header_stdc = yes; then
+ cat >> confdefs.h <<\EOF
+#define STDC_HEADERS 1
+EOF
+
+fi
+
+echo $ac_n "checking for sys/wait.h that is POSIX.1 compatible""... $ac_c" 1>&6
+echo "configure:1901: checking for sys/wait.h that is POSIX.1 compatible" >&5
+if eval "test \"`echo '$''{'ac_cv_header_sys_wait_h'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1906 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/wait.h>
+#ifndef WEXITSTATUS
+#define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
+#endif
+#ifndef WIFEXITED
+#define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
+#endif
+int main() {
+int s;
+wait (&s);
+s = WIFEXITED (s) ? WEXITSTATUS (s) : 1;
+; return 0; }
+EOF
+if { (eval echo configure:1922: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ac_cv_header_sys_wait_h=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_header_sys_wait_h=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_header_sys_wait_h" 1>&6
+if test $ac_cv_header_sys_wait_h = yes; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_SYS_WAIT_H 1
+EOF
+
+fi
+
+echo $ac_n "checking whether time.h and sys/time.h may both be included""... $ac_c" 1>&6
+echo "configure:1943: checking whether time.h and sys/time.h may both be included" >&5
+if eval "test \"`echo '$''{'ac_cv_header_time'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1948 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/time.h>
+#include <time.h>
+int main() {
+struct tm *tp;
+; return 0; }
+EOF
+if { (eval echo configure:1957: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ac_cv_header_time=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_header_time=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_header_time" 1>&6
+if test $ac_cv_header_time = yes; then
+ cat >> confdefs.h <<\EOF
+#define TIME_WITH_SYS_TIME 1
+EOF
+
+fi
+
+for ac_hdr in unistd.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:1981: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1986 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1991: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+
+echo $ac_n "checking for size_t""... $ac_c" 1>&6
+echo "configure:2019: checking for size_t" >&5
+if eval "test \"`echo '$''{'ac_cv_type_size_t'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2024 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "(^|[^a-zA-Z_0-9])size_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_type_size_t=yes
+else
+ rm -rf conftest*
+ ac_cv_type_size_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_size_t" 1>&6
+if test $ac_cv_type_size_t = no; then
+ cat >> confdefs.h <<\EOF
+#define size_t unsigned
+EOF
+
+fi
+
+
+ echo $ac_n "checking whether struct tm contains tm_isdst""... $ac_c" 1>&6
+echo "configure:2053: checking whether struct tm contains tm_isdst" >&5
+if eval "test \"`echo '$''{'local_cv_flag_TM_HAS_ISDST'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat >conftest.c <<EOF
+#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
+int main() { struct tm* foo; foo->tm_isdst; }
+EOF
+ if ${CC} ${CFLAGS} -c conftest.c >/dev/null 2>&1; then
+ local_cv_flag_TM_HAS_ISDST=yes
+ else
+ local_cv_flag_TM_HAS_ISDST=no
+ fi
+ rm -f conftest*
+fi
+
+echo "$ac_t""$local_cv_flag_TM_HAS_ISDST" 1>&6
+
+ echo $ac_n "checking whether struct tm contains __tm_isdst""... $ac_c" 1>&6
+echo "configure:2081: checking whether struct tm contains __tm_isdst" >&5
+if eval "test \"`echo '$''{'local_cv_flag_TM_HAS___ISDST'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat >conftest.c <<EOF
+#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
+int main() { struct tm* foo; foo->__tm_isdst; }
+EOF
+ if ${CC} ${CFLAGS} -c conftest.c >/dev/null 2>&1; then
+ local_cv_flag_TM_HAS___ISDST=yes
+ else
+ local_cv_flag_TM_HAS___ISDST=no
+ fi
+ rm -f conftest*
+fi
+
+echo "$ac_t""$local_cv_flag_TM_HAS___ISDST" 1>&6
+
+ if test "$local_cv_flag_TM_HAS_ISDST" = yes
+ then cat >> confdefs.h <<\EOF
+#define TM_HAS_ISDST tm_isdst
+EOF
+
+ elif test "$local_cv_flag_TM_HAS___ISDST" = yes
+ then cat >> confdefs.h <<\EOF
+#define TM_HAS_ISDST __tm_isdst
+EOF
+
+ fi
+ echo $ac_n "checking whether struct tm contains tm_gmtoff""... $ac_c" 1>&6
+echo "configure:2120: checking whether struct tm contains tm_gmtoff" >&5
+if eval "test \"`echo '$''{'local_cv_flag_TM_HAS_GMTOFF'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat >conftest.c <<EOF
+#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
+int main() { struct tm* foo; foo->tm_gmtoff; }
+EOF
+ if ${CC} ${CFLAGS} -c conftest.c >/dev/null 2>&1; then
+ local_cv_flag_TM_HAS_GMTOFF=yes
+ else
+ local_cv_flag_TM_HAS_GMTOFF=no
+ fi
+ rm -f conftest*
+fi
+
+echo "$ac_t""$local_cv_flag_TM_HAS_GMTOFF" 1>&6
+
+ echo $ac_n "checking whether struct tm contains __tm_gmtoff""... $ac_c" 1>&6
+echo "configure:2148: checking whether struct tm contains __tm_gmtoff" >&5
+if eval "test \"`echo '$''{'local_cv_flag_TM_HAS___GMTOFF'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat >conftest.c <<EOF
+#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
+int main() { struct tm* foo; foo->__tm_gmtoff; }
+EOF
+ if ${CC} ${CFLAGS} -c conftest.c >/dev/null 2>&1; then
+ local_cv_flag_TM_HAS___GMTOFF=yes
+ else
+ local_cv_flag_TM_HAS___GMTOFF=no
+ fi
+ rm -f conftest*
+fi
+
+echo "$ac_t""$local_cv_flag_TM_HAS___GMTOFF" 1>&6
+
+ if test "$local_cv_flag_TM_HAS_GMTOFF" = yes
+ then cat >> confdefs.h <<\EOF
+#define TM_HAS_GMTOFF tm_gmtoff
+EOF
+
+ elif test "$local_cv_flag_TM_HAS___GMTOFF" = yes
+ then cat >> confdefs.h <<\EOF
+#define TM_HAS_GMTOFF __tm_gmtoff
+EOF
+
+ fi
+
+ echo $ac_n "checking whether struct utsname contains domainname""... $ac_c" 1>&6
+echo "configure:2188: checking whether struct utsname contains domainname" >&5
+if eval "test \"`echo '$''{'local_cv_flag_UTSNAME_HAS_DOMAINNAME'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat >conftest.c <<EOF
+#include <sys/utsname.h>
+int main() { struct utsname* foo; foo->domainname; }
+EOF
+ if ${CC} ${CFLAGS} -c conftest.c >/dev/null 2>&1; then
+ local_cv_flag_UTSNAME_HAS_DOMAINNAME=yes
+ else
+ local_cv_flag_UTSNAME_HAS_DOMAINNAME=no
+ fi
+ rm -f conftest*
+fi
+
+echo "$ac_t""$local_cv_flag_UTSNAME_HAS_DOMAINNAME" 1>&6
+
+ echo $ac_n "checking whether struct utsname contains __domainname""... $ac_c" 1>&6
+echo "configure:2207: checking whether struct utsname contains __domainname" >&5
+if eval "test \"`echo '$''{'local_cv_flag_UTSNAME_HAS___DOMAINNAME'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat >conftest.c <<EOF
+#include <sys/utsname.h>
+int main() { struct utsname* foo; foo->__domainname; }
+EOF
+ if ${CC} ${CFLAGS} -c conftest.c >/dev/null 2>&1; then
+ local_cv_flag_UTSNAME_HAS___DOMAINNAME=yes
+ else
+ local_cv_flag_UTSNAME_HAS___DOMAINNAME=no
+ fi
+ rm -f conftest*
+fi
+
+echo "$ac_t""$local_cv_flag_UTSNAME_HAS___DOMAINNAME" 1>&6
+
+ if test "$local_cv_flag_UTSNAME_HAS_DOMAINNAME" = yes
+ then cat >> confdefs.h <<\EOF
+#define UTSNAME_HAS_DOMAINNAME domainname
+EOF
+
+ elif test "$local_cv_flag_UTSNAME_HAS___DOMAINNAME" = yes
+ then cat >> confdefs.h <<\EOF
+#define UTSNAME_HAS_DOMAINNAME __domainname
+EOF
+
+ fi
+
+ echo $ac_n "checking whether named pipes are buggy""... $ac_c" 1>&6
+echo "configure:2238: checking whether named pipes are buggy" >&5
+if eval "test \"`echo '$''{'local_cv_flag_NAMEDPIPEBUG'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat >conftest.c <<EOF
+#include <fcntl.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+int main(int argc, char** argv)
+{
+ struct timeval tv;
+ fd_set rfds;
+ int fd = open(*(argv+1), O_RDONLY | O_NONBLOCK);
+ FD_ZERO(&rfds);
+ FD_SET(fd,&rfds);
+ tv.tv_sec = tv.tv_usec = 0;
+ return (select(fd+1, &rfds, 0, 0,&tv) > 0) ? 0 : 1;
+}
+EOF
+ if ! ${CC} ${CFLAGS} conftest.c -o conftest 2>/dev/null
+ then
+ echo Compile failed
+ exit 1
+ fi
+ mkfifo conftest.pipe
+ if ./conftest conftest.pipe
+ then
+ cat >> confdefs.h <<\EOF
+#define NAMEDPIPEBUG 1
+EOF
+
+ local_cv_flag_NAMEDPIPEBUG=yes
+ else
+ local_cv_flag_NAMEDPIPEBUG=no
+ fi
+ rm -f conftest*
+fi
+
+echo "$ac_t""$local_cv_flag_NAMEDPIPEBUG" 1>&6
+
+
+for ac_func in gethostname getdomainname setenv
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:2283: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2288 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:2311: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+for ac_func in srandom
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:2338: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2343 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:2366: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+
+cat >> confdefs.h <<\EOF
+#define BUFSIZE 4096
+EOF
+
+
+
+if false; then
+ FDBUF_NO_MYSTRING_TRUE=
+ FDBUF_NO_MYSTRING_FALSE='#'
+else
+ FDBUF_NO_MYSTRING_TRUE='#'
+ FDBUF_NO_MYSTRING_FALSE=
+fi
+
+trap '' 1 2 15
+cat > confcache <<\EOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs. It is not useful on other systems.
+# If it contains results you don't want to keep, you may remove or edit it.
+#
+# By default, configure uses ./config.cache as the cache file,
+# creating it if it does not exist already. You can give configure
+# the --cache-file=FILE option to use a different cache file; that is
+# what configure does when it calls configure scripts in
+# subdirectories, so they share the cache.
+# Giving --cache-file=/dev/null disables caching, for debugging configure.
+# config.status only pays attention to the cache file if you give it the
+# --recheck option to rerun configure.
+#
+EOF
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, don't put newlines in cache variables' values.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(set) 2>&1 |
+ case `(ac_space=' '; set | grep ac_space) 2>&1` in
+ *ac_space=\ *)
+ # `set' does not quote correctly, so add quotes (double-quote substitution
+ # turns \\\\ into \\, and sed turns \\ into \).
+ sed -n \
+ -e "s/'/'\\\\''/g" \
+ -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p"
+ ;;
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p'
+ ;;
+ esac >> confcache
+if cmp -s $cache_file confcache; then
+ :
+else
+ if test -w $cache_file; then
+ echo "updating cache $cache_file"
+ cat confcache > $cache_file
+ else
+ echo "not updating unwritable cache $cache_file"
+ fi
+fi
+rm -f confcache
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# Any assignment to VPATH causes Sun make to only execute
+# the first set of double-colon rules, so remove it if not needed.
+# If there is a colon in the path, we need to keep it.
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d'
+fi
+
+trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15
+
+DEFS=-DHAVE_CONFIG_H
+
+# Without the "./", some shells look in PATH for config.status.
+: ${CONFIG_STATUS=./config.status}
+
+echo creating $CONFIG_STATUS
+rm -f $CONFIG_STATUS
+cat > $CONFIG_STATUS <<EOF
+#! /bin/sh
+# Generated automatically by configure.
+# Run this file to recreate the current configuration.
+# This directory was configured as follows,
+# on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+#
+# $0 $ac_configure_args
+#
+# Compiler output produced by configure, useful for debugging
+# configure, is in ./config.log if it exists.
+
+ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]"
+for ac_option
+do
+ case "\$ac_option" in
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion"
+ exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;;
+ -version | --version | --versio | --versi | --vers | --ver | --ve | --v)
+ echo "$CONFIG_STATUS generated by autoconf version 2.13"
+ exit 0 ;;
+ -help | --help | --hel | --he | --h)
+ echo "\$ac_cs_usage"; exit 0 ;;
+ *) echo "\$ac_cs_usage"; exit 1 ;;
+ esac
+done
+
+ac_given_srcdir=$srcdir
+ac_given_INSTALL="$INSTALL"
+
+trap 'rm -fr `echo "Makefile doc/Makefile lib/Makefile lib/cli/Makefile lib/fdbuf/Makefile lib/mystring/Makefile protocols/Makefile src/Makefile test/Makefile config.h" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+# Protect against being on the right side of a sed subst in config.status.
+sed 's/%@/@@/; s/@%/@@/; s/%g\$/@g/; /@g\$/s/[\\\\&%]/\\\\&/g;
+ s/@@/%@/; s/@@/@%/; s/@g\$/%g/' > conftest.subs <<\\CEOF
+$ac_vpsub
+$extrasub
+s%@SHELL@%$SHELL%g
+s%@CFLAGS@%$CFLAGS%g
+s%@CPPFLAGS@%$CPPFLAGS%g
+s%@CXXFLAGS@%$CXXFLAGS%g
+s%@FFLAGS@%$FFLAGS%g
+s%@DEFS@%$DEFS%g
+s%@LDFLAGS@%$LDFLAGS%g
+s%@LIBS@%$LIBS%g
+s%@exec_prefix@%$exec_prefix%g
+s%@prefix@%$prefix%g
+s%@program_transform_name@%$program_transform_name%g
+s%@bindir@%$bindir%g
+s%@sbindir@%$sbindir%g
+s%@libexecdir@%$libexecdir%g
+s%@datadir@%$datadir%g
+s%@sysconfdir@%$sysconfdir%g
+s%@sharedstatedir@%$sharedstatedir%g
+s%@localstatedir@%$localstatedir%g
+s%@libdir@%$libdir%g
+s%@includedir@%$includedir%g
+s%@oldincludedir@%$oldincludedir%g
+s%@infodir@%$infodir%g
+s%@mandir@%$mandir%g
+s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g
+s%@INSTALL_SCRIPT@%$INSTALL_SCRIPT%g
+s%@INSTALL_DATA@%$INSTALL_DATA%g
+s%@PACKAGE@%$PACKAGE%g
+s%@VERSION@%$VERSION%g
+s%@ACLOCAL@%$ACLOCAL%g
+s%@AUTOCONF@%$AUTOCONF%g
+s%@AUTOMAKE@%$AUTOMAKE%g
+s%@AUTOHEADER@%$AUTOHEADER%g
+s%@MAKEINFO@%$MAKEINFO%g
+s%@SET_MAKE@%$SET_MAKE%g
+s%@CC@%$CC%g
+s%@CXX@%$CXX%g
+s%@RANLIB@%$RANLIB%g
+s%@STRIP@%$STRIP%g
+s%@RM@%$RM%g
+s%@MKDIR@%$MKDIR%g
+s%@CPP@%$CPP%g
+s%@FDBUF_NO_MYSTRING_TRUE@%$FDBUF_NO_MYSTRING_TRUE%g
+s%@FDBUF_NO_MYSTRING_FALSE@%$FDBUF_NO_MYSTRING_FALSE%g
+
+CEOF
+EOF
+
+cat >> $CONFIG_STATUS <<\EOF
+
+# Split the substitutions into bite-sized pieces for seds with
+# small command number limits, like on Digital OSF/1 and HP-UX.
+ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script.
+ac_file=1 # Number of current file.
+ac_beg=1 # First line for current file.
+ac_end=$ac_max_sed_cmds # Line after last line for current file.
+ac_more_lines=:
+ac_sed_cmds=""
+while $ac_more_lines; do
+ if test $ac_beg -gt 1; then
+ sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file
+ else
+ sed "${ac_end}q" conftest.subs > conftest.s$ac_file
+ fi
+ if test ! -s conftest.s$ac_file; then
+ ac_more_lines=false
+ rm -f conftest.s$ac_file
+ else
+ if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds="sed -f conftest.s$ac_file"
+ else
+ ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file"
+ fi
+ ac_file=`expr $ac_file + 1`
+ ac_beg=$ac_end
+ ac_end=`expr $ac_end + $ac_max_sed_cmds`
+ fi
+done
+if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds=cat
+fi
+EOF
+
+cat >> $CONFIG_STATUS <<EOF
+
+CONFIG_FILES=\${CONFIG_FILES-"Makefile doc/Makefile lib/Makefile lib/cli/Makefile lib/fdbuf/Makefile lib/mystring/Makefile protocols/Makefile src/Makefile test/Makefile"}
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then
+ # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+ case "$ac_file" in
+ *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+ ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+ *) ac_file_in="${ac_file}.in" ;;
+ esac
+
+ # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories.
+
+ # Remove last slash and all that follows it. Not all systems have dirname.
+ ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+ if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+ # The file is in a subdirectory.
+ test ! -d "$ac_dir" && mkdir "$ac_dir"
+ ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`"
+ # A "../" for each directory in $ac_dir_suffix.
+ ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'`
+ else
+ ac_dir_suffix= ac_dots=
+ fi
+
+ case "$ac_given_srcdir" in
+ .) srcdir=.
+ if test -z "$ac_dots"; then top_srcdir=.
+ else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;;
+ /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;;
+ *) # Relative path.
+ srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix"
+ top_srcdir="$ac_dots$ac_given_srcdir" ;;
+ esac
+
+ case "$ac_given_INSTALL" in
+ [/$]*) INSTALL="$ac_given_INSTALL" ;;
+ *) INSTALL="$ac_dots$ac_given_INSTALL" ;;
+ esac
+
+ echo creating "$ac_file"
+ rm -f "$ac_file"
+ configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure."
+ case "$ac_file" in
+ *Makefile*) ac_comsub="1i\\
+# $configure_input" ;;
+ *) ac_comsub= ;;
+ esac
+
+ ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+ sed -e "$ac_comsub
+s%@configure_input@%$configure_input%g
+s%@srcdir@%$srcdir%g
+s%@top_srcdir@%$top_srcdir%g
+s%@INSTALL@%$INSTALL%g
+" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file
+fi; done
+rm -f conftest.s*
+
+# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where
+# NAME is the cpp macro being defined and VALUE is the value it is being given.
+#
+# ac_d sets the value in "#define NAME VALUE" lines.
+ac_dA='s%^\([ ]*\)#\([ ]*define[ ][ ]*\)'
+ac_dB='\([ ][ ]*\)[^ ]*%\1#\2'
+ac_dC='\3'
+ac_dD='%g'
+# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE".
+ac_uA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)'
+ac_uB='\([ ]\)%\1#\2define\3'
+ac_uC=' '
+ac_uD='\4%g'
+# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE".
+ac_eA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)'
+ac_eB='$%\1#\2define\3'
+ac_eC=' '
+ac_eD='%g'
+
+if test "${CONFIG_HEADERS+set}" != set; then
+EOF
+cat >> $CONFIG_STATUS <<EOF
+ CONFIG_HEADERS="config.h"
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+fi
+for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then
+ # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+ case "$ac_file" in
+ *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+ ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+ *) ac_file_in="${ac_file}.in" ;;
+ esac
+
+ echo creating $ac_file
+
+ rm -f conftest.frag conftest.in conftest.out
+ ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+ cat $ac_file_inputs > conftest.in
+
+EOF
+
+# Transform confdefs.h into a sed script conftest.vals that substitutes
+# the proper values into config.h.in to produce config.h. And first:
+# Protect against being on the right side of a sed subst in config.status.
+# Protect against being in an unquoted here document in config.status.
+rm -f conftest.vals
+cat > conftest.hdr <<\EOF
+s/[\\&%]/\\&/g
+s%[\\$`]%\\&%g
+s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp
+s%ac_d%ac_u%gp
+s%ac_u%ac_e%gp
+EOF
+sed -n -f conftest.hdr confdefs.h > conftest.vals
+rm -f conftest.hdr
+
+# This sed command replaces #undef with comments. This is necessary, for
+# example, in the case of _POSIX_SOURCE, which is predefined and required
+# on some systems where configure will not decide to define it.
+cat >> conftest.vals <<\EOF
+s%^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */%
+EOF
+
+# Break up conftest.vals because some shells have a limit on
+# the size of here documents, and old seds have small limits too.
+
+rm -f conftest.tail
+while :
+do
+ ac_lines=`grep -c . conftest.vals`
+ # grep -c gives empty output for an empty file on some AIX systems.
+ if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi
+ # Write a limited-size here document to conftest.frag.
+ echo ' cat > conftest.frag <<CEOF' >> $CONFIG_STATUS
+ sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS
+ echo 'CEOF
+ sed -f conftest.frag conftest.in > conftest.out
+ rm -f conftest.in
+ mv conftest.out conftest.in
+' >> $CONFIG_STATUS
+ sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail
+ rm -f conftest.vals
+ mv conftest.tail conftest.vals
+done
+rm -f conftest.vals
+
+cat >> $CONFIG_STATUS <<\EOF
+ rm -f conftest.frag conftest.h
+ echo "/* $ac_file. Generated automatically by configure. */" > conftest.h
+ cat conftest.in >> conftest.h
+ rm -f conftest.in
+ if cmp -s $ac_file conftest.h 2>/dev/null; then
+ echo "$ac_file is unchanged"
+ rm -f conftest.h
+ else
+ # Remove last slash and all that follows it. Not all systems have dirname.
+ ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+ if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+ # The file is in a subdirectory.
+ test ! -d "$ac_dir" && mkdir "$ac_dir"
+ fi
+ rm -f $ac_file
+ mv conftest.h $ac_file
+ fi
+fi; done
+
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+test -z "$CONFIG_HEADERS" || echo timestamp > stamp-h
+
+exit 0
+EOF
+chmod +x $CONFIG_STATUS
+rm -fr confdefs* $ac_clean_files
+test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1
+
diff --git a/configure.in b/configure.in
new file mode 100644
index 0000000..7225bb3
--- /dev/null
+++ b/configure.in
@@ -0,0 +1,53 @@
+AC_INIT(lib/defines.h)
+AM_INIT_AUTOMAKE(nullmailer, 1.00RC5)
+AM_CONFIG_HEADER(config.h)
+AC_PROG_MAKE_SET
+
+dnl Checks for programs.
+AC_PROG_CC
+AC_PROG_CXX
+CXX_NO_RTTI
+CXX_NO_EXCEPTIONS
+
+CFLAGS="$CFLAGS -W -Wall"
+CXXFLAGS="$CXXFLAGS -W -Wall"
+
+AC_PROG_INSTALL
+AC_PROG_RANLIB
+AC_PATH_PROG(STRIP, strip)
+AC_PATH_PROG(RM, rm)
+AC_PATH_PROG(MKDIR, mkdir)
+
+dnl Checks for libraries.
+AC_CHECK_LIB(xnet, socket)
+AC_CHECK_LIB(inet, socket)
+AC_CHECK_LIB(socket, socket)
+
+dnl Checks for header files.
+AC_HEADER_DIRENT
+AC_HEADER_STDC
+AC_HEADER_SYS_WAIT
+AC_HEADER_TIME
+dnl AC_CHECK_HEADERS(fcntl.h sys/time.h shadow.h crypt.h)
+AC_CHECK_HEADERS(unistd.h)
+
+dnl Checks for typedefs, structures, and compiler characteristics.
+dnl AC_TYPE_UID_T
+dnl AC_TYPE_SIGNAL
+dnl AC_C_INLINE
+dnl AC_TYPE_PID_T
+AC_TYPE_SIZE_T
+
+TEST_STRUCT_TM
+TEST_STRUCT_UTSNAME
+CHECK_NAMED_PIPE_BUG
+
+dnl Checks for library functions.
+AC_CHECK_FUNCS(gethostname getdomainname setenv)
+dnl AC_CHECK_FUNCS(gettimeofday mkdir putenv rmdir socket)
+AC_CHECK_FUNCS(srandom)
+
+AC_DEFINE(BUFSIZE, 4096)
+AM_CONDITIONAL(FDBUF_NO_MYSTRING, false)
+
+AC_OUTPUT(Makefile doc/Makefile lib/Makefile lib/cli/Makefile lib/fdbuf/Makefile lib/mystring/Makefile protocols/Makefile src/Makefile test/Makefile)
diff --git a/doc/Makefile.am b/doc/Makefile.am
new file mode 100644
index 0000000..27651a7
--- /dev/null
+++ b/doc/Makefile.am
@@ -0,0 +1,8 @@
+# info_TEXINFOS = nullmailer.texi
+man_MANS = \
+ nullmailer-inject.1 \
+ sendmail.1 \
+ nullmailer.7 \
+ nullmailer-queue.8 \
+ nullmailer-send.8
+EXTRA_DIST = diagram $(man_MANS)
diff --git a/doc/Makefile.in b/doc/Makefile.in
new file mode 100644
index 0000000..dfff02b
--- /dev/null
+++ b/doc/Makefile.in
@@ -0,0 +1,291 @@
+# Makefile.in generated automatically by automake 1.4a from Makefile.am
+
+# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+# info_TEXINFOS = nullmailer.texi
+
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DESTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_FLAG =
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+CC = @CC@
+CXX = @CXX@
+MAKEINFO = @MAKEINFO@
+MKDIR = @MKDIR@
+PACKAGE = @PACKAGE@
+RANLIB = @RANLIB@
+RM = @RM@
+STRIP = @STRIP@
+VERSION = @VERSION@
+
+man_MANS = nullmailer-inject.1 sendmail.1 nullmailer.7 nullmailer-queue.8 nullmailer-send.8
+
+EXTRA_DIST = diagram $(man_MANS)
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = ../config.h
+CONFIG_CLEAN_FILES =
+man1dir = $(mandir)/man1
+man7dir = $(mandir)/man7
+man8dir = $(mandir)/man8
+MANS = $(man_MANS)
+
+NROFF = nroff
+DIST_COMMON = Makefile.am Makefile.in
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = gtar
+GZIP_ENV = --best
+all: all-redirect
+.SUFFIXES:
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
+ cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps doc/Makefile
+
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ cd $(top_builddir) \
+ && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+
+install-man1:
+ $(mkinstalldirs) $(DESTDIR)$(man1dir)
+ @list='$(man1_MANS)'; \
+ l2='$(man_MANS)'; for i in $$l2; do \
+ case "$$i" in \
+ *.1*) list="$$list $$i" ;; \
+ esac; \
+ done; \
+ for i in $$list; do \
+ if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \
+ else file=$$i; fi; \
+ ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+ inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+ echo " $(INSTALL_DATA) $$file $(DESTDIR)$(man1dir)/$$inst"; \
+ $(INSTALL_DATA) $$file $(DESTDIR)$(man1dir)/$$inst; \
+ done
+
+uninstall-man1:
+ @list='$(man1_MANS)'; \
+ l2='$(man_MANS)'; for i in $$l2; do \
+ case "$$i" in \
+ *.1*) list="$$list $$i" ;; \
+ esac; \
+ done; \
+ for i in $$list; do \
+ ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+ inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+ echo " rm -f $(DESTDIR)$(man1dir)/$$inst"; \
+ rm -f $(DESTDIR)$(man1dir)/$$inst; \
+ done
+
+install-man7:
+ $(mkinstalldirs) $(DESTDIR)$(man7dir)
+ @list='$(man7_MANS)'; \
+ l2='$(man_MANS)'; for i in $$l2; do \
+ case "$$i" in \
+ *.7*) list="$$list $$i" ;; \
+ esac; \
+ done; \
+ for i in $$list; do \
+ if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \
+ else file=$$i; fi; \
+ ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+ inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+ echo " $(INSTALL_DATA) $$file $(DESTDIR)$(man7dir)/$$inst"; \
+ $(INSTALL_DATA) $$file $(DESTDIR)$(man7dir)/$$inst; \
+ done
+
+uninstall-man7:
+ @list='$(man7_MANS)'; \
+ l2='$(man_MANS)'; for i in $$l2; do \
+ case "$$i" in \
+ *.7*) list="$$list $$i" ;; \
+ esac; \
+ done; \
+ for i in $$list; do \
+ ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+ inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+ echo " rm -f $(DESTDIR)$(man7dir)/$$inst"; \
+ rm -f $(DESTDIR)$(man7dir)/$$inst; \
+ done
+
+install-man8:
+ $(mkinstalldirs) $(DESTDIR)$(man8dir)
+ @list='$(man8_MANS)'; \
+ l2='$(man_MANS)'; for i in $$l2; do \
+ case "$$i" in \
+ *.8*) list="$$list $$i" ;; \
+ esac; \
+ done; \
+ for i in $$list; do \
+ if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \
+ else file=$$i; fi; \
+ ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+ inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+ echo " $(INSTALL_DATA) $$file $(DESTDIR)$(man8dir)/$$inst"; \
+ $(INSTALL_DATA) $$file $(DESTDIR)$(man8dir)/$$inst; \
+ done
+
+uninstall-man8:
+ @list='$(man8_MANS)'; \
+ l2='$(man_MANS)'; for i in $$l2; do \
+ case "$$i" in \
+ *.8*) list="$$list $$i" ;; \
+ esac; \
+ done; \
+ for i in $$list; do \
+ ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+ inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+ echo " rm -f $(DESTDIR)$(man8dir)/$$inst"; \
+ rm -f $(DESTDIR)$(man8dir)/$$inst; \
+ done
+install-man: $(MANS)
+ @$(NORMAL_INSTALL)
+ $(MAKE) $(AM_MAKEFLAGS) install-man1 install-man7 install-man8
+uninstall-man:
+ @$(NORMAL_UNINSTALL)
+ $(MAKE) $(AM_MAKEFLAGS) uninstall-man1 uninstall-man7 uninstall-man8
+tags: TAGS
+TAGS:
+
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = doc
+
+distdir: $(DISTFILES)
+ @for file in $(DISTFILES); do \
+ d=$(srcdir); \
+ if test -d $$d/$$file; then \
+ cp -pr $$d/$$file $(distdir)/$$file; \
+ else \
+ test -f $(distdir)/$$file \
+ || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+ || cp -p $$d/$$file $(distdir)/$$file || :; \
+ fi; \
+ done
+info-am:
+info: info-am
+dvi-am:
+dvi: dvi-am
+check-am: all-am
+check: check-am
+installcheck-am:
+installcheck: installcheck-am
+install-exec-am:
+install-exec: install-exec-am
+
+install-data-am: install-man
+install-data: install-data-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-am
+uninstall-am: uninstall-man
+uninstall: uninstall-am
+all-am: Makefile $(MANS)
+all-redirect: all-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_STRIP_FLAG=-s install
+installdirs:
+ $(mkinstalldirs) $(DESTDIR)$(mandir)/man1 $(DESTDIR)$(mandir)/man7 \
+ $(DESTDIR)$(mandir)/man8
+
+
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -rm -f Makefile $(CONFIG_CLEAN_FILES)
+ -rm -f config.cache config.log stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+mostlyclean-am: mostlyclean-generic
+
+mostlyclean: mostlyclean-am
+
+clean-am: clean-generic mostlyclean-am
+
+clean: clean-am
+
+distclean-am: distclean-generic clean-am
+
+distclean: distclean-am
+
+maintainer-clean-am: maintainer-clean-generic distclean-am
+ @echo "This command is intended for maintainers to use;"
+ @echo "it deletes files that may require special tools to rebuild."
+
+maintainer-clean: maintainer-clean-am
+
+.PHONY: install-man1 uninstall-man1 install-man7 uninstall-man7 \
+install-man8 uninstall-man8 install-man uninstall-man tags distdir \
+info-am info dvi-am dvi check check-am installcheck-am installcheck \
+install-exec-am install-exec install-data-am install-data install-am \
+install uninstall-am uninstall all-redirect all-am all installdirs \
+mostlyclean-generic distclean-generic clean-generic \
+maintainer-clean-generic clean mostlyclean distclean maintainer-clean
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/doc/diagram b/doc/diagram
new file mode 100644
index 0000000..a8f0ac5
--- /dev/null
+++ b/doc/diagram
@@ -0,0 +1,21 @@
+qmail-inject sendmail
+ \ /
+ \ /
+ \ /
+ nullmailer-inject
+ |
+ |
+ |
+ nullmailer-queue
+ |
+ |
+ |
+ QUEUE/tmp -> QUEUE/queue
+ |
+ |
+ |
+ nullmailer-send
+ |
+ |
+ |
+ BIN/PROTOCOL
diff --git a/doc/nullmailer-inject.1 b/doc/nullmailer-inject.1
new file mode 100644
index 0000000..885bbbb
--- /dev/null
+++ b/doc/nullmailer-inject.1
@@ -0,0 +1,240 @@
+.TH nullmailer-inject 1
+.SH NAME
+nullmailer-inject \- Reformat and inject a message into the queue.
+.SH SYNOPSIS
+.B nullmailer-inject
+[\-a]
+[\-b]
+[\-e]
+[\-f sender]
+[\-h]
+.I [recipient [recipient ...]]
+.SH DESCRIPTION
+This program reads a email message from standard input, reformats its
+header to comply with RFC822, and sends the resulting message to the
+queue.
+.SS HEADER FIELDS
+The following lines are parsed for recipient addresses:
+.IR To ,
+.IR Cc ,
+.IR Bcc ,
+.IR Apparently-To ,
+.IR Resent-To ,
+.IR Resent-Cc ,
+and
+.IR Resent-Bcc .
+
+The following sender address lines are parsed and rewritten:
+.IR Sender ,
+.IR From ,
+.IR Reply-To ,
+.IR Return-Path ,
+.IR Return-Receipt-To ,
+.IR Errors-To ,
+.IR Resent-Sender ,
+.IR Resent-From ,
+and
+.IR Resent-Reply-To .
+If the
+.I Return-Path
+header field is present and contains a single address, its contents
+will be used to set the envelope sender address.
+
+If the message contains any of the following fields, it is treated as
+a resent message:
+.IR Resent-Sender ,
+.IR Resent-From ,
+.IR Resent-Reply-To ,
+.IR Resent-To ,
+.IR Resent-Cc ,
+.IR Resent-Bcc ,
+.IR Resent-Date ,
+.IR Resent-Message-ID .
+If the message is resent, only the recipient fields prefixed with
+.I Resent-
+are examined for addresses.
+
+Any occurrences of
+.IR Bcc ,
+.IR Resent-Bcc ,
+.IR Return-Path ,
+or
+.I Content-Length
+are discarded after they are parsed (if necessary).
+
+If the header lacks a
+.I Message-Id
+field, a unique string is generated and added to the message.
+If the header lacks a
+.I Date
+field, the current local date and time in RFC822 format is appended to
+the message.
+If the message has no
+.I To
+or
+.I Cc
+fields, the following line is appended to the message:
+
+.EX
+ Cc: recipient list not shown: ;
+.EE
+.SS ADDRESS LISTS
+Address lists are expected to follow the syntax set out in RFC822.
+The following is a simplified explanation of the syntax.
+
+An address list is list of addresses seperated by commas.
+An individual address may have one of the following three forms:
+.IR user@fqdn ,
+.IR comment <user@fqdn> ,
+or
+.IR phrase: address-list; .
+Any of the first two forms may be used within the address list of the
+third form.
+Any word containing special characters must be placed in double quotes
+and the special characters must be preceded with a backslash.
+Comments may be placed between addresses in parenthesis.
+All comments are ignored.
+
+Addresses lists are reformatted as they are parsed for ease of later
+re-parsing when the message reaches the destination(s).
+If an address is missing a fqdn,
+.B nullmailer-inject
+adds one.
+.SH OPTIONS
+.TP
+.I -a
+Use only the command line arguments as recipient addresses.
+Ignore the header recipient lines.
+.TP
+.I -b
+Use both the command line arguments and data from the message header
+as recipient addresses.
+.TP
+.I -e
+Use either the command line arguments (if there are any) or data from
+the message header (if there are no arguments) as the recipient
+addresses.
+.TP
+.I -f sender
+Set the envelope sender address to
+.I sender .
+.TP
+.I -h
+Use only data from the message header as the recipient addresses.
+.TP
+.I -n
+Do not queue the message, but print the reformatted contents to
+standard output.
+.TP
+.I -v
+Print out the envelope (sender and recipient addresses) preceding the
+message when printing the message to standard output.
+.SH RETURN VALUE
+Exits 0 if it was successful, otherwise it prints a diagnostic message
+to standard output and exits 1.
+.SH ENVIRONMENT
+The environment variable
+.BR NULLMAILER_FLAGS
+is parsed and the behavior of
+.B nullmailer-inject
+is modified if any of the following letters are present:
+.TP
+.B c
+Use "address (comment)" style in the generated
+.B From
+field instead of the default "comment <address>" style.
+.TP
+.B f
+Ignore and remove any
+.B From
+header lines and always insert a generated one.
+.TP
+.B i
+Ignore and remove any
+.B Message-Id
+header lines.
+.TP
+.B s
+Ignore and remove any
+.B Return-Path
+header lines.
+.TP
+.B t
+Insert a
+.BR To
+line containing a list of the recipients if the header does not
+contain either a
+.B To
+or a
+.B Cc
+field.
+If the message is determined to be a resent message (see above), a
+.B Resent-To
+field is added if the header does not contain either a
+.BR Resent-To
+or a
+.BR Resent-Cc
+field.
+.PP
+The user name is set by
+.BR NULLMAILER_USER ,
+.BR MAILUSER ,
+.BR USER ,
+or
+.BR LOGNAME ,
+whichever comes first or
+.I unknown
+if none of the above are set.
+
+The host name is set by the canonicalized value of
+.BR NULLMAILER_HOST ,
+.BR MAILHOST ,
+or
+.BR HOSTNAME ,
+whichever comes first, or the
+.I defaulthost
+config file if none of the above are set (see below).
+
+The full name of the user is set by
+.BR NULLMAILER_NAME ,
+.BR MAILNAME ,
+or
+.BR NAME ,
+whichever comes first.
+
+The user and host name of the envelope sender default to the user and
+host name set above, but may be overridden by
+.BR NULLMAILER_SUSER
+and
+.BR NULLMAILER_SHOST .
+.SH CONTROL FILES
+When reading the following files, a single line is read and stripped
+of all leading and trailing whitespace characters.
+.TP
+.B defaultdomain
+The content of this file is appended to any host name that does not
+contain a period, including
+.BR defaulthost
+and
+.BR idhost .
+Defaults to the value of the
+.I domainname
+system call.
+.TP
+.B defaulthost
+The content of this file is appended to any address that is missing a
+host name.
+Defaults to the value of the
+.I hostname
+system call.
+.TP
+.B idhost
+The content of this file is used when building the message-id string
+for the message.
+Defaults to the canonicalized value of
+.BR defaulthost .
+.SH SEE ALSO
+nullmailer-queue(8)
+.SH NOTES
+This document glosses over very many details of how address parsing
+and rewriting actually works (among other things).
diff --git a/doc/nullmailer-queue.8 b/doc/nullmailer-queue.8
new file mode 100644
index 0000000..c9b2bae
--- /dev/null
+++ b/doc/nullmailer-queue.8
@@ -0,0 +1,51 @@
+.TH nullmailer-queue 8
+.SH NAME
+nullmailer-queue \- insert mail messages into the queue
+.SH SYNOPSIS
+.B nullmailer-queue
+.SH DESCRIPTION
+This program reads a formatted mail message from standard input and
+safely injects it into the outgoing mail queue.
+.PP
+The data sent into standard input is expected to have the following
+format: one line containing the envelope sender, one or more lines
+containing the recipients, a single blank line, and then the contents
+of the message exactly as it is to be transmitted to the destination.
+All lines are terminated with a single line-feed character.
+All addresses must contain a fully-qualified domain name.
+.PP
+.SH RETURN VALUE
+Exits 0 if it successfully queues the message.
+If it failed to queue the message, it exits 1 and prints an error
+message to stdandard output.
+.SH CONTROL FILES
+.TP
+.B adminaddr
+If this file is not empty, all recipients to users at either
+"localhost" (the literal string) or the canonical host name (based on
+the values returned by the
+.I hostname
+and the
+.I domainname
+system calls) are remapped to this address.
+This is provided to allow local daemons to be able to send email to
+"somebody@localhost" and have it go somewhere sensible instead of
+being bounced by your relay host.
+.SH OTHER FILES
+.TP
+.B /var/nullmailer/queue
+The directory into which the completed messages are moved.
+.TP
+.B /var/nullmailer/tmp
+The directory in which messages are formed temporarily.
+.TP
+.B /var/nullmailer/trigger
+A pipe used to trigger
+.BR nullmailer-send
+to immediately start sending the message from the queue.
+.SH SEE ALSO
+nullmailer-inject(1),
+nullmailer-send(8)
+.SH LIMITATIONS
+This program should enforce system-wide configurable message length
+limits.
diff --git a/doc/nullmailer-send.8 b/doc/nullmailer-send.8
new file mode 100644
index 0000000..b7c8277
--- /dev/null
+++ b/doc/nullmailer-send.8
@@ -0,0 +1,72 @@
+.TH nullmailer-send 8
+.SH NAME
+nullmailer-send \- Send queued messages
+.SH SYNOPSIS
+.B nullmailer-send
+.SH DESCRIPTION
+This program is responsible for coordinating the transmission of
+messages that have been queued by
+.BR nullmailer-queue .
+It uses a variety of protocol modules to deliver the messages from the
+queue to remote "smart" servers.
+.P
+When the program starts, the queue is scanned to build a list of
+messages to send.
+The queue is rescanned when either the trigger is pulled, or after
+.B pausetime
+seconds have elapsed after the last failed delivery.
+When there are no messages in the queue, nullmailer does no rescanning
+until the trigger is pulled.
+Pulling the trigger consists of opening up the trigger named pipe and
+writing a single byte to it, which causes this program to be awakened
+(if it's not already processing the queue).
+This procedure is done by
+.B nullmailer-queue
+to ensure that messages are delivered immediately.
+.P
+Delivery of messages consists of reading the list of remote servers and
+then trying to deliver the messages to these servers as follows.
+For each remote in the list, the named protocol handler is executed once
+for each message remaining in the queue.
+If the protocol handler succeeds, the message is removed from the queue
+and processing continues with the next message.
+If it fails, the remote is skipped and processing of the remaing
+messages continues with the next remote.
+When all the remotes have been tried,
+.B nullmailer-send
+sleeps for a number of seconds specified by
+.B pausetime
+before retrying sending the contents of the queue.
+.SH CONTROL FILES
+All the control files are reread each time the queue is run.
+.TP
+.B pausetime
+The number of seconds to pause between successive queue runs when
+there are messages in the queue (defaults to
+.IR 60 ).
+.TP
+.B remotes
+This file contains a list of remote servers to which to send each
+message.
+Each line of this file contains a remote host name or address and an
+optional protocol string, separated by white space.
+The protocol name defaults to
+.IR smtp .
+Blank lines and lines starting with a pound are ignored.
+.SH FILES
+.TP
+.B /var/nullmailer/queue
+The message queue.
+.TP
+.B /var/nullmailer/trigger
+A trigger file to cause immediate delivery.
+.TP
+.B /usr/local/etc/nullmailer
+The configuration directory.
+.TP
+.B /usr/local/libexec/nullmailer
+The protocol program directory.
+.SH SEE ALSO
+nullmailer-queue(8),
+nullmailer-inject(1),
+mailq(1)
diff --git a/doc/nullmailer.7 b/doc/nullmailer.7
new file mode 100644
index 0000000..911bbf3
--- /dev/null
+++ b/doc/nullmailer.7
@@ -0,0 +1,30 @@
+.TH nullmailer 7
+.SH NAME
+nullmailer \- Overview of nullmailer documentation
+.SH INTRODUCTION
+.B nullmailer
+is a simple and secure relay-only mail transport agent.
+.P
+Documentation on how messages are reformatted and injected into the
+queue can be found in
+.BR nullmailer-inject (1).
+Documentation on how messages are actually inserted into the queue can
+be found in
+.BR nullmailer-queue (8).
+The process of sending queued messages is described in
+.BR nullmailer-send (8).
+.P
+The following table lists all the control files used by
+.BR nullmailer .
+.RS
+.nf
+.ta 5c
+control file used by
+.I adminaddr \fBnullmailer-queue
+.I defaultdomain \fBnullmailer-inject
+.I defaulthost \fBnullmailer-inject
+.I idhost \fBnullmailer-inject
+.I pausetime \fBnullmailer-send
+.I remotes \fBnullmailer-send
+.fi
+.RE
diff --git a/doc/sendmail.1 b/doc/sendmail.1
new file mode 100644
index 0000000..944fd6c
--- /dev/null
+++ b/doc/sendmail.1
@@ -0,0 +1,75 @@
+.TH sendmail 1
+.SH NAME
+sendmail \- sendmail emulator interface for nullmailer
+.SH SYNOPSIS
+.B sendmail
+[
+.B flags
+] [
+.I recipients
+] <
+.I message
+.SH DESCRIPTION
+This program is a front end program for
+.BR nullmailer-inject .
+It is used by programs that expect a
+.I sendmail
+interface for sending email.
+After parsing the command-line arguments, this program executes
+.B nullmailer-inject
+directly.
+See the documentation for
+.B nullmailer-inject
+for details on how messages are reformatted and queued.
+.SH OPTIONS
+.TP
+.B \-B TYPE
+.TP
+.B \-b MODE
+.TP
+.B \-C FILE
+.TP
+.B \-d DEBUG
+.TP
+.B \-h COUNT
+.TP
+.B \-i
+.TP
+.B \-L TAG
+.TP
+.B \-N DSN
+.TP
+.B \-n
+.TP
+.B \-O OPTION
+.TP
+.B \-o OPTION
+.TP
+.B \-p PROTOCOL
+.TP
+.B \-q TIME
+.TP
+.B \-R RETURN
+.TP
+.B \-U
+.TP
+.B \-V ENVID
+.TP
+.B \-v
+.TP
+.B \-X LOGFILE
+Ignored
+.TP
+.B \-F ADDRESS
+Sets the full name of the sender.
+.TP
+.B \-f ADDRESS
+Sets the envelope sender address.
+.TP
+.B \-r ADDRESS
+An alternate and obsolete form of the -f flag.
+.TP
+.B \-t
+Read message for recipients and ignore the command-line arguments.
+.SH SEE ALSO
+nullmailer-inject(1)
diff --git a/install-sh b/install-sh
new file mode 100755
index 0000000..e9de238
--- /dev/null
+++ b/install-sh
@@ -0,0 +1,251 @@
+#!/bin/sh
+#
+# install - install a program, script, or datafile
+# This comes from X11R5 (mit/util/scripts/install.sh).
+#
+# Copyright 1991 by the Massachusetts Institute of Technology
+#
+# Permission to use, copy, modify, distribute, and sell this software and its
+# documentation for any purpose is hereby granted without fee, provided that
+# the above copyright notice appear in all copies and that both that
+# copyright notice and this permission notice appear in supporting
+# documentation, and that the name of M.I.T. not be used in advertising or
+# publicity pertaining to distribution of the software without specific,
+# written prior permission. M.I.T. makes no representations about the
+# suitability of this software for any purpose. It is provided "as is"
+# without express or implied warranty.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch. It can only install one file at a time, a restriction
+# shared with many OS's install programs.
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+transformbasename=""
+transform_arg=""
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+dir_arg=""
+
+while [ x"$1" != x ]; do
+ case $1 in
+ -c) instcmd="$cpprog"
+ shift
+ continue;;
+
+ -d) dir_arg=true
+ shift
+ continue;;
+
+ -m) chmodcmd="$chmodprog $2"
+ shift
+ shift
+ continue;;
+
+ -o) chowncmd="$chownprog $2"
+ shift
+ shift
+ continue;;
+
+ -g) chgrpcmd="$chgrpprog $2"
+ shift
+ shift
+ continue;;
+
+ -s) stripcmd="$stripprog"
+ shift
+ continue;;
+
+ -t=*) transformarg=`echo $1 | sed 's/-t=//'`
+ shift
+ continue;;
+
+ -b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+ shift
+ continue;;
+
+ *) if [ x"$src" = x ]
+ then
+ src=$1
+ else
+ # this colon is to work around a 386BSD /bin/sh bug
+ :
+ dst=$1
+ fi
+ shift
+ continue;;
+ esac
+done
+
+if [ x"$src" = x ]
+then
+ echo "install: no input file specified"
+ exit 1
+else
+ true
+fi
+
+if [ x"$dir_arg" != x ]; then
+ dst=$src
+ src=""
+
+ if [ -d $dst ]; then
+ instcmd=:
+ chmodcmd=""
+ else
+ instcmd=mkdir
+ fi
+else
+
+# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+# might cause directories to be created, which would be especially bad
+# if $src (and thus $dsttmp) contains '*'.
+
+ if [ -f $src -o -d $src ]
+ then
+ true
+ else
+ echo "install: $src does not exist"
+ exit 1
+ fi
+
+ if [ x"$dst" = x ]
+ then
+ echo "install: no destination specified"
+ exit 1
+ else
+ true
+ fi
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+ if [ -d $dst ]
+ then
+ dst="$dst"/`basename $src`
+ else
+ true
+ fi
+fi
+
+## this sed command emulates the dirname command
+dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+# Make sure that the destination directory exists.
+# this part is taken from Noah Friedman's mkinstalldirs script
+
+# Skip lots of stat calls in the usual case.
+if [ ! -d "$dstdir" ]; then
+defaultIFS='
+'
+IFS="${IFS-${defaultIFS}}"
+
+oIFS="${IFS}"
+# Some sh's can't handle IFS=/ for some reason.
+IFS='%'
+set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
+IFS="${oIFS}"
+
+pathcomp=''
+
+while [ $# -ne 0 ] ; do
+ pathcomp="${pathcomp}${1}"
+ shift
+
+ if [ ! -d "${pathcomp}" ] ;
+ then
+ $mkdirprog "${pathcomp}"
+ else
+ true
+ fi
+
+ pathcomp="${pathcomp}/"
+done
+fi
+
+if [ x"$dir_arg" != x ]
+then
+ $doit $instcmd $dst &&
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
+else
+
+# If we're going to rename the final executable, determine the name now.
+
+ if [ x"$transformarg" = x ]
+ then
+ dstfile=`basename $dst`
+ else
+ dstfile=`basename $dst $transformbasename |
+ sed $transformarg`$transformbasename
+ fi
+
+# don't allow the sed command to completely eliminate the filename
+
+ if [ x"$dstfile" = x ]
+ then
+ dstfile=`basename $dst`
+ else
+ true
+ fi
+
+# Make a temp file name in the proper directory.
+
+ dsttmp=$dstdir/#inst.$$#
+
+# Move or copy the file name to the temp name
+
+ $doit $instcmd $src $dsttmp &&
+
+ trap "rm -f ${dsttmp}" 0 &&
+
+# and set any options; do chmod last to preserve setuid bits
+
+# If any of these fail, we abort the whole thing. If we want to
+# ignore errors from any of these, just make sure not to ignore
+# errors from the above "$doit $instcmd $src $dsttmp" command.
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
+
+# Now rename the file to the real destination.
+
+ $doit $rmcmd -f $dstdir/$dstfile &&
+ $doit $mvcmd $dsttmp $dstdir/$dstfile
+
+fi &&
+
+
+exit 0
diff --git a/lib/Makefile.am b/lib/Makefile.am
new file mode 100644
index 0000000..a993560
--- /dev/null
+++ b/lib/Makefile.am
@@ -0,0 +1,39 @@
+SUBDIRS = cli fdbuf mystring
+noinst_LIBRARIES = libmisc.a libnullmailer.a
+noinst_HEADERS = list.h
+EXTRA_DIST = make_defines.sh listtest.cc mergelib.sh
+CLEANFILES = defines.cc
+
+libmisc_a_SOURCES = \
+ address.h address.cc \
+ canonicalize.h canonicalize.cc \
+ configio.h config_read.cc config_readlist.cc config_readint.cc \
+ connect.h tcpconnect.cc \
+ defines.h defines.cc \
+ errcodes.h errcodes.cc \
+ hostname.h hostname.cc \
+ itoa.h itoa.cc \
+ makefield.cc \
+ netstring.h netstring.cc
+
+libnullmailer_a_SOURCES =
+libnullmailer.a: mergelib.sh libmisc.a fdbuf/libfdbuf.a \
+ mystring/libmystring.a Makefile
+ $(RM) -f libnullmailer.a
+ sh mergelib.sh libnullmailer.a \
+ libmisc.a \
+ fdbuf/libfdbuf.a \
+ mystring/libmystring.a
+
+defines.cc: Makefile.am make_defines.sh
+ @echo Creating defines.cc
+ @sh make_defines.sh \
+ @localstatedir@/nullmailer \
+ @sysconfdir@/nullmailer \
+ @libexecdir@/nullmailer \
+ @bindir@ \
+ @sbindir@
+
+dist-hook:
+ $(RM) -f $(distdir)/defines.cc
+ cp -dP `find ac -name CVS -prune -o -type f -print` $(distdir)
diff --git a/lib/Makefile.in b/lib/Makefile.in
new file mode 100644
index 0000000..0c00b89
--- /dev/null
+++ b/lib/Makefile.in
@@ -0,0 +1,408 @@
+# Makefile.in generated automatically by automake 1.4a from Makefile.am
+
+# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DESTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_FLAG =
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+CC = @CC@
+CXX = @CXX@
+MAKEINFO = @MAKEINFO@
+MKDIR = @MKDIR@
+PACKAGE = @PACKAGE@
+RANLIB = @RANLIB@
+RM = @RM@
+STRIP = @STRIP@
+VERSION = @VERSION@
+
+SUBDIRS = cli fdbuf mystring
+noinst_LIBRARIES = libmisc.a libnullmailer.a
+noinst_HEADERS = list.h
+EXTRA_DIST = make_defines.sh listtest.cc mergelib.sh
+CLEANFILES = defines.cc
+
+libmisc_a_SOURCES = address.h address.cc canonicalize.h canonicalize.cc configio.h config_read.cc config_readlist.cc config_readint.cc connect.h tcpconnect.cc defines.h defines.cc errcodes.h errcodes.cc hostname.h hostname.cc itoa.h itoa.cc makefield.cc netstring.h netstring.cc
+
+
+libnullmailer_a_SOURCES =
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = ../config.h
+CONFIG_CLEAN_FILES =
+LIBRARIES = $(noinst_LIBRARIES)
+
+
+DEFS = @DEFS@ -I. -I$(srcdir) -I..
+CPPFLAGS = @CPPFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+libmisc_a_LIBADD =
+libmisc_a_OBJECTS = address.o canonicalize.o config_read.o \
+config_readlist.o config_readint.o tcpconnect.o defines.o errcodes.o \
+hostname.o itoa.o makefield.o netstring.o
+libnullmailer_a_LIBADD =
+libnullmailer_a_OBJECTS =
+AR = ar
+CXXFLAGS = @CXXFLAGS@
+CXXCOMPILE = $(CXX) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+CXXLD = $(CXX)
+CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(LDFLAGS) -o $@
+CFLAGS = @CFLAGS@
+COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@
+HEADERS = $(noinst_HEADERS)
+
+DIST_COMMON = Makefile.am Makefile.in
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = gtar
+GZIP_ENV = --best
+SOURCES = $(libmisc_a_SOURCES) $(libnullmailer_a_SOURCES)
+OBJECTS = $(libmisc_a_OBJECTS) $(libnullmailer_a_OBJECTS)
+
+all: all-redirect
+.SUFFIXES:
+.SUFFIXES: .S .c .cc .o .s
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
+ cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps lib/Makefile
+
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ cd $(top_builddir) \
+ && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+
+mostlyclean-noinstLIBRARIES:
+
+clean-noinstLIBRARIES:
+ -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
+
+distclean-noinstLIBRARIES:
+
+maintainer-clean-noinstLIBRARIES:
+
+.c.o:
+ $(COMPILE) -c $<
+
+.s.o:
+ $(COMPILE) -c $<
+
+.S.o:
+ $(COMPILE) -c $<
+
+mostlyclean-compile:
+ -rm -f *.o core *.core
+
+clean-compile:
+
+distclean-compile:
+ -rm -f *.tab.c
+
+maintainer-clean-compile:
+
+libmisc.a: $(libmisc_a_OBJECTS) $(libmisc_a_DEPENDENCIES)
+ -rm -f libmisc.a
+ $(AR) cru libmisc.a $(libmisc_a_OBJECTS) $(libmisc_a_LIBADD)
+ $(RANLIB) libmisc.a
+.cc.o:
+ $(CXXCOMPILE) -c $<
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run `make' without going through this Makefile.
+# To change the values of `make' variables: instead of editing Makefiles,
+# (1) if the variable is set in `config.status', edit `config.status'
+# (which will cause the Makefiles to be regenerated when you run `make');
+# (2) otherwise, pass the desired values on the `make' command line.
+
+@SET_MAKE@
+
+all-recursive install-data-recursive install-exec-recursive \
+installdirs-recursive install-recursive uninstall-recursive \
+check-recursive installcheck-recursive info-recursive dvi-recursive:
+ @set fnord $(MAKEFLAGS); amf=$$2; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+mostlyclean-recursive clean-recursive distclean-recursive \
+maintainer-clean-recursive:
+ @set fnord $(MAKEFLAGS); amf=$$2; \
+ dot_seen=no; \
+ rev=''; list='$(SUBDIRS)'; for subdir in $$list; do \
+ rev="$$subdir $$rev"; \
+ test "$$subdir" = "." && dot_seen=yes; \
+ done; \
+ test "$$dot_seen" = "no" && rev=". $$rev"; \
+ target=`echo $@ | sed s/-recursive//`; \
+ for subdir in $$rev; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \
+ done && test -z "$$fail"
+tags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
+ done
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP)
+ list='$(SOURCES) $(HEADERS)'; \
+ unique=`for i in $$list; do echo $$i; done | \
+ awk ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ here=`pwd` && cd $(srcdir) \
+ && mkid -f$$here/ID $$unique $(LISP)
+
+TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test -f $$subdir/TAGS && tags="$$tags -i $$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ list='$(SOURCES) $(HEADERS)'; \
+ unique=`for i in $$list; do echo $$i; done | \
+ awk ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
+ || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS)
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+ -rm -f TAGS ID
+
+maintainer-clean-tags:
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = lib
+
+distdir: $(DISTFILES)
+ @for file in $(DISTFILES); do \
+ d=$(srcdir); \
+ if test -d $$d/$$file; then \
+ cp -pr $$d/$$file $(distdir)/$$file; \
+ else \
+ test -f $(distdir)/$$file \
+ || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+ || cp -p $$d/$$file $(distdir)/$$file || :; \
+ fi; \
+ done
+ for subdir in $(SUBDIRS); do \
+ if test "$$subdir" = .; then :; else \
+ test -d $(distdir)/$$subdir \
+ || mkdir $(distdir)/$$subdir \
+ || exit 1; \
+ chmod 777 $(distdir)/$$subdir; \
+ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir=../$(top_distdir) distdir=../$(distdir)/$$subdir distdir) \
+ || exit 1; \
+ fi; \
+ done
+ $(MAKE) $(AM_MAKEFLAGS) top_distdir="$(top_distdir)" distdir="$(distdir)" dist-hook
+address.o: address.cc ../config.h canonicalize.h mystring/mystring.h \
+ mystring/rep.h mystring/iter.h mystring/join.h list.h
+canonicalize.o: canonicalize.cc ../config.h mystring/mystring.h \
+ mystring/rep.h mystring/iter.h mystring/join.h canonicalize.h
+config_read.o: config_read.cc ../config.h defines.h configio.h \
+ mystring/mystring.h mystring/rep.h mystring/iter.h \
+ mystring/join.h list.h fdbuf/fdbuf.h fdbuf/fdibuf.h \
+ fdbuf/fdobuf.h
+config_readint.o: config_readint.cc ../config.h defines.h configio.h \
+ mystring/mystring.h mystring/rep.h mystring/iter.h \
+ mystring/join.h list.h fdbuf/fdbuf.h fdbuf/fdibuf.h \
+ fdbuf/fdobuf.h
+config_readlist.o: config_readlist.cc ../config.h defines.h configio.h \
+ mystring/mystring.h mystring/rep.h mystring/iter.h \
+ mystring/join.h list.h fdbuf/fdbuf.h fdbuf/fdibuf.h \
+ fdbuf/fdobuf.h
+defines.o: defines.cc
+errcodes.o: errcodes.cc errcodes.h
+hostname.o: hostname.cc ../config.h mystring/mystring.h mystring/rep.h \
+ mystring/iter.h mystring/join.h
+itoa.o: itoa.cc itoa.h
+makefield.o: makefield.cc ../config.h defines.h itoa.h \
+ mystring/mystring.h mystring/rep.h mystring/iter.h \
+ mystring/join.h
+netstring.o: netstring.cc ../config.h netstring.h mystring/mystring.h \
+ mystring/rep.h mystring/iter.h mystring/join.h itoa.h
+tcpconnect.o: tcpconnect.cc ../config.h errcodes.h connect.h \
+ mystring/mystring.h mystring/rep.h mystring/iter.h \
+ mystring/join.h
+
+info-am:
+info: info-recursive
+dvi-am:
+dvi: dvi-recursive
+check-am: all-am
+check: check-recursive
+installcheck-am:
+installcheck: installcheck-recursive
+install-exec-am:
+install-exec: install-exec-recursive
+
+install-data-am:
+install-data: install-data-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-recursive
+uninstall-am:
+uninstall: uninstall-recursive
+all-am: Makefile $(LIBRARIES) $(HEADERS)
+all-redirect: all-recursive
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_STRIP_FLAG=-s install
+installdirs: installdirs-recursive
+installdirs-am:
+
+
+mostlyclean-generic:
+
+clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -rm -f Makefile $(CONFIG_CLEAN_FILES)
+ -rm -f config.cache config.log stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+mostlyclean-am: mostlyclean-noinstLIBRARIES mostlyclean-compile \
+ mostlyclean-tags mostlyclean-generic
+
+mostlyclean: mostlyclean-recursive
+
+clean-am: clean-noinstLIBRARIES clean-compile clean-tags clean-generic \
+ mostlyclean-am
+
+clean: clean-recursive
+
+distclean-am: distclean-noinstLIBRARIES distclean-compile \
+ distclean-tags distclean-generic clean-am
+
+distclean: distclean-recursive
+
+maintainer-clean-am: maintainer-clean-noinstLIBRARIES \
+ maintainer-clean-compile maintainer-clean-tags \
+ maintainer-clean-generic distclean-am
+ @echo "This command is intended for maintainers to use;"
+ @echo "it deletes files that may require special tools to rebuild."
+
+maintainer-clean: maintainer-clean-recursive
+
+.PHONY: mostlyclean-noinstLIBRARIES distclean-noinstLIBRARIES \
+clean-noinstLIBRARIES maintainer-clean-noinstLIBRARIES \
+mostlyclean-compile distclean-compile clean-compile \
+maintainer-clean-compile install-data-recursive \
+uninstall-data-recursive install-exec-recursive \
+uninstall-exec-recursive installdirs-recursive uninstalldirs-recursive \
+all-recursive check-recursive installcheck-recursive info-recursive \
+dvi-recursive mostlyclean-recursive distclean-recursive clean-recursive \
+maintainer-clean-recursive tags tags-recursive mostlyclean-tags \
+distclean-tags clean-tags maintainer-clean-tags distdir info-am info \
+dvi-am dvi check check-am installcheck-am installcheck install-exec-am \
+install-exec install-data-am install-data install-am install \
+uninstall-am uninstall all-redirect all-am all installdirs-am \
+installdirs mostlyclean-generic distclean-generic clean-generic \
+maintainer-clean-generic clean mostlyclean distclean maintainer-clean
+
+libnullmailer.a: mergelib.sh libmisc.a fdbuf/libfdbuf.a \
+ mystring/libmystring.a Makefile
+ $(RM) -f libnullmailer.a
+ sh mergelib.sh libnullmailer.a \
+ libmisc.a \
+ fdbuf/libfdbuf.a \
+ mystring/libmystring.a
+
+defines.cc: Makefile.am make_defines.sh
+ @echo Creating defines.cc
+ @sh make_defines.sh \
+ @localstatedir@/nullmailer \
+ @sysconfdir@/nullmailer \
+ @libexecdir@/nullmailer \
+ @bindir@ \
+ @sbindir@
+
+dist-hook:
+ $(RM) -f $(distdir)/defines.cc
+ cp -dP `find ac -name CVS -prune -o -type f -print` $(distdir)
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/lib/ac/dirent.h b/lib/ac/dirent.h
new file mode 100644
index 0000000..5b0f191
--- /dev/null
+++ b/lib/ac/dirent.h
@@ -0,0 +1,17 @@
+#include <sys/types.h>
+#if HAVE_DIRENT_H
+# include <dirent.h>
+# define NAMLEN(dirent) strlen((dirent)->d_name)
+#else
+# define dirent direct
+# define NAMLEN(dirent) (dirent)->d_namlen
+# if HAVE_SYS_NDIR_H
+# include <sys/ndir.h>
+# endif
+# if HAVE_SYS_DIR_H
+# include <sys/dir.h>
+# endif
+# if HAVE_NDIR_H
+# include <ndir.h>
+# endif
+#endif
diff --git a/lib/ac/time.h b/lib/ac/time.h
new file mode 100644
index 0000000..10d1136
--- /dev/null
+++ b/lib/ac/time.h
@@ -0,0 +1,10 @@
+#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
diff --git a/lib/ac/wait.h b/lib/ac/wait.h
new file mode 100644
index 0000000..665ced5
--- /dev/null
+++ b/lib/ac/wait.h
@@ -0,0 +1,10 @@
+#include <sys/types.h>
+#if HAVE_SYS_WAIT_H
+# include <sys/wait.h>
+#endif
+#ifndef WEXITSTATUS
+# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
+#endif
+#ifndef WIFEXITED
+# define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
+#endif
diff --git a/lib/address.cc b/lib/address.cc
new file mode 100644
index 0000000..da69ef4
--- /dev/null
+++ b/lib/address.cc
@@ -0,0 +1,644 @@
+// nullmailer -- a simple relay-only MTA
+// Copyright (C) 1999,2000 Bruce Guenter <bruceg@em.ca>
+//
+// 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
+//
+// You can contact me at <bruceg@em.ca>. There is also a mailing list
+// available to discuss this package. To subscribe, send an email to
+// <nullmailer-subscribe@lists.em.ca>.
+
+#include "config.h"
+#include <ctype.h>
+#include "canonicalize.h"
+#include "mystring/mystring.h"
+#include "list.h"
+
+#define LSQBRACKET '['
+#define RSQBRACKET ']'
+#define QUOTE '"'
+#define CR '\n'
+#define LPAREN '('
+#define RPAREN ')'
+
+enum node_type {
+ EMPTY = 0,
+ // Full tokens, with string content:
+ ATOM = 'A',
+ QUOTED_STRING = 'Q',
+ DOMAIN_LITERAL = 'D',
+ COMMENT = 'C',
+ // Special characters, no content:
+ LABRACKET = '<',
+ RABRACKET = '>',
+ AT = '@',
+ COMMA = ',',
+ SEMICOLON = ';',
+ COLON = ':',
+ ESCAPE = '\\',
+ PERIOD = '.',
+ // End of tokens
+ EOT = '$',
+};
+
+struct token
+{
+ const node_type type;
+ const mystring str;
+
+ token(node_type);
+ token(node_type, mystring);
+};
+
+token::token(node_type t)
+ : type(t)
+{
+}
+
+token::token(node_type t, mystring s)
+ : type(t), str(s)
+{
+}
+
+struct anode : public token
+{
+ anode* next;
+ anode(node_type);
+ anode(node_type, const char*, const char*);
+ anode(node_type, mystring);
+};
+
+anode::anode(node_type t)
+ : token(t), next(0)
+{
+}
+
+anode::anode(node_type t, const char* start, const char* end)
+ : token(t, mystring(start, end-start)), next(0)
+{
+}
+
+anode::anode(node_type t, mystring s)
+ : token(t, s), next(0)
+{
+}
+
+struct result
+{
+ anode* next;
+ mystring str;
+ mystring comment;
+ mystring addr;
+
+ result(const result&);
+ result(anode* = 0);
+ result(anode*, const mystring&, const mystring&, const mystring&);
+ bool operator!() const
+ {
+ return !next;
+ }
+ operator bool() const
+ {
+ return next;
+ }
+};
+
+result::result(anode* n)
+ : next(n)
+{
+}
+
+result::result(anode* n, const mystring& s,
+ const mystring& c, const mystring& l)
+ : next(n), str(s), comment(c), addr(l)
+{
+}
+
+result::result(const result& r)
+ : next(r.next), str(r.str), comment(r.comment), addr(r.addr)
+{
+}
+
+#ifndef TRACE
+#define ENTER(R)
+#define FAIL(MSG) return result()
+#define RETURNR(R) return R
+#define RETURN(N,S,C,L) return result(N,S,C,L)
+#else
+#include "fdbuf/fdbuf.h"
+static const char indentstr[] = " ";
+static const char* indent = indentstr + sizeof indentstr - 1;
+#define ENTER(R) do{ fout << indent-- << __FUNCTION__ << ": " << node->str << ": " << R << endl; }while(0)
+#define FAIL(MSG) do{ fout << ++indent << __FUNCTION__ << ": failed: " << MSG << endl; return result(); }while(0)
+#define RETURNR(R) do{ fout << ++indent << __FUNCTION__ << ": succeded str=" << R.str << " comment=" << R.comment << " addr=" << R.addr << endl; return (R); }while(0)
+#define RETURN(N,S,C,L) do{ result r(N,S,C,L); RETURNR(r); }while(0)
+#endif
+
+#define RULE(X) static result match_##X(anode* node)
+#define MATCHTOKEN(X) do{ if(node->type != X) FAIL("node is not type " #X); else node = node->next; }while(0)
+#define MATCHRULE(V,R) result V = match_##R(node); if(!V) FAIL("did not match " #R);
+#define OR_RULE(ALT1,ALT2) { result r=match_##ALT1(node); if(r) RETURNR(r); }{ result r=match_##ALT2(node); if(r) RETURNR(r); } FAIL("did not match " #ALT1 " OR " #ALT2);
+
+static bool issymbol(char c)
+{
+ switch(c) {
+ case LPAREN: case RPAREN:
+ case LABRACKET: case RABRACKET:
+ case LSQBRACKET: case RSQBRACKET:
+ case AT: case COMMA:
+ case SEMICOLON: case COLON:
+ case ESCAPE: case QUOTE: case PERIOD:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool isctl(char c)
+{
+ return (c >= 0 && c <= 31) || (c == 127);
+}
+
+static bool isqtext(char c)
+{
+ return c && c != QUOTE && c != ESCAPE && c != CR;
+}
+
+static bool isdtext(char c)
+{
+ return c && c != LSQBRACKET && c != RSQBRACKET &&
+ c != ESCAPE && c != CR;
+}
+
+// quoted-pair = ESCAPE CHAR
+static bool isqpair(const char* ptr)
+{
+ return *ptr && *ptr == ESCAPE &&
+ *(ptr+1);
+}
+
+static bool isatom(char ch)
+{
+ return !(isspace(ch) || issymbol(ch) || isctl(ch));
+}
+
+static anode* tokenize_atom(const char* &ptr)
+{
+ if(!isatom(*ptr)) return 0;
+ const char* start = ptr;
+ do {
+ ++ptr;
+ } while(isatom(*ptr));
+ return new anode(ATOM, start, ptr);
+}
+
+static anode* tokenize_comment(const char* &ptr)
+{
+ if(*ptr != LPAREN) return 0;
+ unsigned count = 0;
+ const char* start = ptr;
+ char ch = *ptr;
+ while(ch) {
+ if(isqpair(ptr))
+ ++ptr;
+ else if(ch == LPAREN)
+ ++count;
+ else if(ch == RPAREN) {
+ --count;
+ if(!count)
+ return new anode(COMMENT, start, ++ptr);
+ }
+ else if(ch == CR)
+ return 0; // ERROR
+ ++ptr;
+ ch = *ptr;
+ }
+ return 0; // ERROR
+}
+
+static anode* tokenize_domain_literal(const char* &ptr)
+{
+ if(*ptr != LSQBRACKET) return 0;
+ const char* start = ptr;
+ ++ptr;
+ while(isspace(*ptr)) ++ptr;
+ for(; *ptr; ++ptr) {
+ if(isdtext(*ptr))
+ continue;
+ else if(isqpair(ptr))
+ ++ptr;
+ else
+ break;
+ }
+ while(isspace(*ptr)) ++ptr;
+ if(*ptr != RSQBRACKET)
+ return 0; // ERROR
+ return new anode(DOMAIN_LITERAL, start, ptr);
+}
+
+static anode* tokenize_quoted_string(const char* &ptr)
+{
+ if(*ptr != QUOTE) return 0;
+ const char* start = ptr;
+ for(++ptr; *ptr; ++ptr) {
+ if(isqtext(*ptr))
+ continue;
+ else if(isqpair(ptr))
+ ++ptr;
+ else
+ break;
+ }
+ if(*ptr != QUOTE) return 0;
+ ++ptr;
+ return new anode(QUOTED_STRING, start, ptr);
+}
+
+static anode* tokenize(const char* &ptr)
+{
+ while(isspace(*ptr)) ++ptr;
+ char ch = *ptr;
+ switch(ch) {
+ case 0:
+ return new anode(EOT);
+ case LABRACKET:
+ case RABRACKET:
+ case AT:
+ case COMMA:
+ case SEMICOLON:
+ case COLON:
+ case ESCAPE:
+ case PERIOD:
+ ++ptr;
+ return new anode((node_type)ch);
+ case LPAREN:
+ return tokenize_comment(ptr);
+ case LSQBRACKET:
+ return tokenize_domain_literal(ptr);
+ case QUOTE:
+ return tokenize_quoted_string(ptr);
+ default:
+ return tokenize_atom(ptr);
+ }
+}
+
+anode* tokenize(const mystring str)
+{
+ anode* head = new anode(EMPTY);
+ anode* tail = head;
+ anode* tmp;
+ const char* ptr = str.c_str();
+ while((tmp = tokenize(ptr)) != 0) {
+ tail = tail->next = tmp;
+ if(tmp->type == EOT) {
+ tail = head->next;
+ delete head;
+ return tail;
+ }
+ }
+ return 0;
+}
+
+static mystring quote(const mystring& in)
+{
+ unsigned length = in.length();
+ // The result will never be more than double the length of the input plus 2
+ char out[length*2 + 2 + 1];
+ char* ptrout = out;
+ const char* ptrin = in.c_str();
+ bool quoted = false;
+ for(; length; ++ptrin, ++ptrout, --length) {
+ if(issymbol(*ptrin)) {
+ *ptrout++ = ESCAPE;
+ quoted = true;
+ }
+ *ptrout = *ptrin;
+ }
+ *ptrout = 0;
+ if(quoted)
+ return mystringjoin("\"") + out + "\"";
+ else
+ return in;
+}
+
+static mystring unquote(const mystring& in)
+{
+ unsigned length = in.length();
+ // The result will never be more than the length of the input
+ char out[length+1];
+ bool modified = false;
+ const char* ptrin = in.c_str();
+ char* ptrout = out;
+ if(in[0] == QUOTE && in[length-1] == QUOTE) {
+ length -= 2;
+ ptrin++;
+ modified = true;
+ }
+ for(; length; ++ptrin, ++ptrout, --length) {
+ if(isqpair(ptrin)) {
+ ++ptrin;
+ --length;
+ modified = true;
+ }
+ *ptrout = *ptrin;
+ }
+ *ptrout = 0;
+ if(modified)
+ return out;
+ else
+ return in;
+}
+
+anode* skipcomment(anode* node, mystring& comment)
+{
+ while(node->type == COMMENT) {
+ comment = comment + " " + node->str;
+ node = node->next;
+ }
+ return node;
+}
+
+RULE(sub_domain)
+{
+ // Note atom <= domain-ref
+ ENTER("atom / domain-literal");
+ mystring comment;
+ node = skipcomment(node, comment);
+ if(node->type == ATOM || node->type == DOMAIN_LITERAL)
+ RETURN(node->next, node->str, comment, node->str);
+ FAIL("did not match ATOM or DOMAIN-LITERAL");
+}
+
+RULE(domain)
+{
+ ENTER("sub-domain *(PERIOD sub-domain) [PERIOD]");
+ MATCHRULE(r, sub_domain);
+ if(!r) FAIL("did not match sub-domain");
+ mystring comment;
+ for(;;) {
+ node = r.next = skipcomment(r.next, comment);
+ if(node->type != PERIOD)
+ break;
+ node = node->next;
+ result r1 = match_sub_domain(node);
+ if(r1) {
+ r.next = r1.next;
+ r.str += PERIOD;
+ r.str += r1.str;
+ comment += r1.comment;
+ r.addr += PERIOD;
+ r.addr += r1.addr;
+ }
+ else {
+ r.next = node;
+ }
+ }
+ r.comment += comment;
+ RETURNR(r);
+}
+
+RULE(route)
+{
+ ENTER("1#(AT domain) COLON");
+ unsigned count=0;
+ mystring str;
+ mystring comment;
+ for(;;) {
+ if(node->type != AT) break;
+ node = node->next;
+ MATCHRULE(r, domain);
+ str += "@";
+ str += r.str;
+ comment += r.comment;
+ ++count;
+ node = r.next;
+ }
+ if(count == 0)
+ FAIL("matched no domains");
+ node = skipcomment(node, comment);
+ MATCHTOKEN(COLON);
+ RETURN(node, str, comment, "");
+}
+
+RULE(word)
+{
+ ENTER("atom / quoted-string");
+ mystring comment;
+ node = skipcomment(node, comment);
+ if(node->type == ATOM)
+ RETURN(node->next, node->str, comment, node->str);
+ else if(node->type == QUOTED_STRING) {
+ mystring addr = unquote(node->str);
+ RETURN(node->next, quote(addr), comment, addr);
+ }
+ FAIL("did not match ATOM or QUOTED-STRING");
+}
+
+RULE(local_part)
+{
+ ENTER("word *(PERIOD word)");
+ MATCHRULE(r, word);
+ for(;;) {
+ node = r.next = skipcomment(r.next, r.comment);
+ if(node->type != PERIOD)
+ break;
+ node = node->next;
+ result r1 = match_word(node);
+ if(!r1)
+ break;
+ r.next = r1.next;
+ r.str += ".";
+ r.str += r1.str;
+ r.comment += r1.comment;
+ r.addr += ".";
+ r.addr += r1.addr;
+ }
+ RETURNR(r);
+}
+
+RULE(addr_spec)
+{
+ ENTER("local-part *( AT domain )");
+ MATCHRULE(r, local_part);
+ mystring domain;
+ for(;;) {
+ node = r.next = skipcomment(r.next, r.comment);
+ if(node->type != AT)
+ break;
+ node = node->next;
+ result r2 = match_domain(node);
+ if(!r2) break;
+ if(!!domain) {
+ r.str += "@";
+ r.str += domain;
+ r.addr += "@";
+ r.addr += domain;
+ }
+ domain = r2.addr;
+ r.comment += r2.comment;
+ r.next = r2.next;
+ }
+ canonicalize(domain);
+ RETURN(r.next, r.str + "@" + domain, r.comment,
+ r.addr + "@" + domain + "\n");
+}
+
+RULE(route_addr)
+{
+ ENTER("LABRACKET [route] addr-spec RABRACKET");
+ mystring comment;
+ node = skipcomment(node, comment);
+ MATCHTOKEN(LABRACKET);
+ result r1 = match_route(node);
+ if(r1) node = r1.next;
+ comment += r1.comment;
+ MATCHRULE(r2, addr_spec);
+ node = r2.next;
+ comment += r2.comment;
+ node = skipcomment(node, comment);
+ MATCHTOKEN(RABRACKET);
+ RETURN(node, "<" + r2.str + ">" + comment, "", r2.addr);
+}
+
+RULE(phrase)
+{
+ ENTER("word *word");
+ MATCHRULE(r1, word);
+ for(;;) {
+ result r2 = match_word(r1.next);
+ if(!r2)
+ break;
+ r1.str += " ";
+ r1.str += r2.str;
+ r1.comment += r2.comment;
+ r1.next = r2.next;
+ }
+ RETURNR(r1);
+}
+
+RULE(route_spec)
+{
+ ENTER("[phrase] route-addr");
+ result r1 = match_phrase(node);
+ if(r1)
+ node = r1.next;
+ MATCHRULE(r2, route_addr);
+ if(!r1)
+ RETURNR(r2);
+ r2.str = r1.str + r1.comment + " " + r2.str + r2.comment;
+ RETURNR(r2);
+}
+
+RULE(mailbox)
+{
+ ENTER("route-spec / addr-spec");
+ OR_RULE(route_spec, addr_spec);
+}
+
+RULE(mailboxes)
+{
+ ENTER("mailbox *(*(COMMA) mailbox)");
+ MATCHRULE(r1, mailbox);
+ r1.str += r1.comment;
+ r1.comment = "";
+ for(;;) {
+ node = r1.next;
+ for(;;) {
+ node = skipcomment(node, r1.str);
+ if(node->type == COMMA) node = node->next;
+ else break;
+ }
+ if(node->type == EOT)
+ break;
+ result r2 = match_mailbox(node);
+ if(!r2) break;
+ r1.next = r2.next;
+ r1.str = r1.str + ", " + r2.str + r2.comment;
+ r1.addr += r2.addr;
+ }
+ node = skipcomment(node, r1.str);
+ r1.next = node;
+ RETURNR(r1);
+}
+
+RULE(group)
+{
+ ENTER("phrase COLON [#mailboxes] SEMICOLON");
+ MATCHRULE(r1, phrase);
+ node = r1.next;
+ MATCHTOKEN(COLON);
+ result r2 = match_mailboxes(node);
+ if(r2) node = r2.next;
+ mystring comment;
+ node = skipcomment(node, comment);
+ MATCHTOKEN(SEMICOLON);
+ RETURN(node, r1.str + ": " + r2.str + r2.comment + comment + ";",
+ "", r2.addr);
+}
+
+RULE(address)
+{
+ ENTER("group / mailbox");
+ OR_RULE(group, mailbox);
+}
+
+RULE(addresses)
+{
+ ENTER("address *(*(COMMA) address) EOF");
+ MATCHRULE(r1, address);
+ r1.str += r1.comment;
+ r1.comment = "";
+ for(;;) {
+ node = r1.next;
+ for(;;) {
+ node = skipcomment(node, r1.str);
+ if(node->type == COMMA) node = node->next;
+ else break;
+ }
+ if(node->type == EOT)
+ break;
+ result r2 = match_address(node);
+ if(!r2) break;
+ r1.next = r2.next;
+ r1.str = r1.str + ", " + r2.str + r2.comment;
+ r1.addr += r2.addr;
+ }
+ node = skipcomment(node, r1.str);
+ if(node->next) FAIL("Rule ended before EOF");
+ RETURNR(r1);
+}
+
+static void del_tokens(anode* node)
+{
+ while(node) {
+ anode* tmp = node->next;
+ delete node;
+ node = tmp;
+ }
+}
+
+bool parse_addresses(mystring& line, mystring& list)
+{
+ anode* tokenlist = tokenize(line.c_str());
+ if(!tokenlist)
+ return false;
+ result r = match_addresses(tokenlist);
+ del_tokens(tokenlist);
+ if(r) {
+ line = r.str;
+ list = r.addr;
+ return true;
+ }
+ else
+ return false;
+}
diff --git a/lib/address.h b/lib/address.h
new file mode 100644
index 0000000..ca0f93a
--- /dev/null
+++ b/lib/address.h
@@ -0,0 +1,8 @@
+#ifndef NULLMAILER__ADDRESS__H__
+#define NULLMAILER__ADDRESS__H__
+
+#include "mystring/mystring.h"
+
+bool parse_addresses(mystring& line, mystring& list);
+
+#endif // NULLMAILER__ADDRESS__H__
diff --git a/lib/canonicalize.cc b/lib/canonicalize.cc
new file mode 100644
index 0000000..a5d734a
--- /dev/null
+++ b/lib/canonicalize.cc
@@ -0,0 +1,40 @@
+// nullmailer -- a simple relay-only MTA
+// Copyright (C) 1999,2000 Bruce Guenter <bruceg@em.ca>
+//
+// 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
+//
+// You can contact me at <bruceg@em.ca>. There is also a mailing list
+// available to discuss this package. To subscribe, send an email to
+// <nullmailer-subscribe@lists.em.ca>.
+
+#include "config.h"
+#include "mystring/mystring.h"
+#include "canonicalize.h"
+
+extern mystring defaultdomain;
+extern mystring defaulthost;
+
+void canonicalize(mystring& domain)
+{
+ if(!domain)
+ domain = defaulthost;
+ if(domain.find_first('.') < 0) {
+ if(!!defaultdomain) {
+ domain += ".";
+ domain += defaultdomain;
+ }
+ }
+}
+
diff --git a/lib/canonicalize.h b/lib/canonicalize.h
new file mode 100644
index 0000000..f046aec
--- /dev/null
+++ b/lib/canonicalize.h
@@ -0,0 +1,7 @@
+#ifndef NULLMAILER__CANONICALIZE__H__
+#define NULLMAILER__CANONICALIZE__H__
+
+#include "mystring/mystring.h"
+void canonicalize(mystring& domain);
+
+#endif // NULLMAILER__CANONICALIZE__H__
diff --git a/lib/cli/ChangeLog b/lib/cli/ChangeLog
new file mode 100644
index 0000000..8fb73e7
--- /dev/null
+++ b/lib/cli/ChangeLog
@@ -0,0 +1,119 @@
+2000-10-25 Bruce Guenter <bruce@bruce-guenter.dyndns.org>
+
+ * cli2pod.pl (parse_options): Ignore {0,} as well as {0}.
+
+2000-08-15 Bruce Guenter <bruce@bruce-guenter.dyndns.org>
+
+ * cli2pod.pl: Replaced the CLI documentation programs with this
+ script which outputs POD, which can be translated to man pages or
+ HTML (or LaTeX, or text, or FM).
+
+2000-08-14 Bruce Guenter <bruce@bruce-guenter.dyndns.org>
+
+ * cli_parse.pl (parse_header_line): Rewrote the parsing to deal
+ with multi-line strings.
+
+ * cli2man.pl (synopsis): Add usage string.
+
+ * cli2html.pl (synopsis): Add usage string.
+
+2000-08-12 Bruce Guenter <bruce@bruce-guenter.dyndns.org>
+
+ * cli_parse.pl, cli2html.pl, cli2man.pl: Created these programs.
+
+2000-08-01 Bruce Guenter <bruce@bruce-guenter.dyndns.org>
+
+ * main.cc (show_option): Fixed several width glitches.
+
+2000-07-18 Bruce Guenter <bruce@bruce-guenter.dyndns.org>
+
+ * cli.h (struct cli_option): Added new uinteger type.
+
+ * main.cc (fill): Removed use of mystring.
+
+2000-07-13 Bruce Guenter <bruce@bruce-guenter.dyndns.org>
+
+ * Removed include of mystring.
+
+2000-01-09 Bruce Guenter <bruceg@daedalus.bfsmedia.com>
+
+ * main.cc (parse_short): Modified the logic here to treat a string
+ value immediately following a string option as the value for that
+ option rather than as more flags. This makes it behave much more
+ like the standard getopt library.
+
+1999-09-30 Bruce Guenter <bguenter@mikhail.qcc.sk.ca>
+
+ * main.cc (show_option): Changed stringlist option string from
+ "=LIST" to "=ITEM".
+
+1999-09-29 Bruce Guenter <bguenter@mikhail.qcc.sk.ca>
+
+ * main.cc (cli_option::set): Fixed problem with setting a string
+ list option.
+
+1999-09-11 Bruce Guenter <bguenter@mikhail.qcc.sk.ca>
+
+ * main.cc (show_help): Split off two parts of this routine into
+ calc_max_width and show_option.
+ (show_option): Add "=INT" for integer options, and don't add extra
+ space for non-value long options.
+ (set): Use strtol instead of atoi to parse the integer string, to
+ allow for error checking.
+ (show_option): Fixed handling of string lists.
+
+1999-08-14 Bruce Guenter <bguenter@mikhail.qcc.sk.ca>
+
+ * main.cc (set_argv0): Sets argv0 to the complete value of
+ argv[0], argv0dir to the part of argv[0] up to and including the
+ last '/' (or blank if there is none), and argv0base to the
+ remainder of argv[0]. This is for use in programs that determine
+ what to do based on the value of the program name.
+
+1999-07-14 Bruce Guenter <bguenter@mikhail.qcc.sk.ca>
+
+ * main.cc (parse_long_eq): Fixed to account for "counter" flag
+ type.
+ (parse_long_noeq): Fixed to account for "counter" flag type.
+ (parse_long_eq): set() will return one, but this shouldn't return
+ one, so subtract one from its result.
+ (show_help): Added a mechanism to display default values on a
+ second line.
+ (show_help): Output a blank line before the "--help" option line.
+
+1999-07-04 Bruce Guenter <bguenter@mikhail.qcc.sk.ca>
+
+ * main.cc (show_help): Only show a "=VALUE" for string and integer
+ option types.
+
+1999-06-30 Bruce Guenter <bguenter@mikhail.qcc.sk.ca>
+
+ * messages.cc (cli_error): Moved this routine into a separate
+ module, and added a "cli_warning" routine.
+
+1999-06-25 Bruce Guenter <bguenter@mikhail.qcc.sk.ca>
+
+ * main.cc (set): Added handling for two new option types: string
+ list and counters. A stringlist maintains a linked list of all
+ the given option arguments. A counter adds the flag_value to the
+ dataptr each time it is encountered.
+ (parse_short): Fixed faulty logic regarding options with values.
+ Need to merge parts into cli_option::set().
+
+1999-06-24 Bruce Guenter <bguenter@mikhail.qcc.sk.ca>
+
+ * main.cc: Rewrote the "help" option handling to stop it being a
+ special case, by making an internal option list that includes a
+ "help" option at the end of it.
+ (show_help): Cleaned up the option formatting to produce more
+ correct output.
+ (build_options): Removed the need to count the options. Note
+ that this breaks compatibility with previous versions.
+ (cli_error): Added this convenience function for the CLI program
+ to report errors and optionally exit.
+ (set): Added functionality to call functions when an option is
+ parsed, and moved some of the option parsing into class methods
+ from the structure.
+ (main): Moved the test for showing the usage information before
+ the test for counting command-line arguments.
+
diff --git a/lib/cli/Makefile.am b/lib/cli/Makefile.am
new file mode 100644
index 0000000..492e8a2
--- /dev/null
+++ b/lib/cli/Makefile.am
@@ -0,0 +1,9 @@
+noinst_LIBRARIES = libcli.a
+EXTRA_DIST = clitest.cc cli2pod.pl
+
+INCLUDES = -I..
+#LIBS = @LIBS@ -L. -lcli -L../lib -lvmailmgr
+
+libcli_a_SOURCES = cli.h main.cc messages.cc
+#clitest_SOURCES = clitest.cc
+
diff --git a/lib/cli/Makefile.in b/lib/cli/Makefile.in
new file mode 100644
index 0000000..c2d29bf
--- /dev/null
+++ b/lib/cli/Makefile.in
@@ -0,0 +1,277 @@
+# Makefile.in generated automatically by automake 1.4a from Makefile.am
+
+# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DESTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ../..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_FLAG =
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+CC = @CC@
+CXX = @CXX@
+MAKEINFO = @MAKEINFO@
+MKDIR = @MKDIR@
+PACKAGE = @PACKAGE@
+RANLIB = @RANLIB@
+RM = @RM@
+STRIP = @STRIP@
+VERSION = @VERSION@
+
+noinst_LIBRARIES = libcli.a
+EXTRA_DIST = clitest.cc cli2pod.pl
+
+INCLUDES = -I..
+#LIBS = @LIBS@ -L. -lcli -L../lib -lvmailmgr
+
+libcli_a_SOURCES = cli.h main.cc messages.cc
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = ../../config.h
+CONFIG_CLEAN_FILES =
+LIBRARIES = $(noinst_LIBRARIES)
+
+
+DEFS = @DEFS@ -I. -I$(srcdir) -I../..
+CPPFLAGS = @CPPFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+libcli_a_LIBADD =
+libcli_a_OBJECTS = main.o messages.o
+AR = ar
+CXXFLAGS = @CXXFLAGS@
+CXXCOMPILE = $(CXX) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+CXXLD = $(CXX)
+CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(LDFLAGS) -o $@
+CFLAGS = @CFLAGS@
+COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@
+DIST_COMMON = ChangeLog Makefile.am Makefile.in
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = gtar
+GZIP_ENV = --best
+SOURCES = $(libcli_a_SOURCES)
+OBJECTS = $(libcli_a_OBJECTS)
+
+all: all-redirect
+.SUFFIXES:
+.SUFFIXES: .S .c .cc .o .s
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
+ cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps lib/cli/Makefile
+
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ cd $(top_builddir) \
+ && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+
+mostlyclean-noinstLIBRARIES:
+
+clean-noinstLIBRARIES:
+ -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
+
+distclean-noinstLIBRARIES:
+
+maintainer-clean-noinstLIBRARIES:
+
+.c.o:
+ $(COMPILE) -c $<
+
+.s.o:
+ $(COMPILE) -c $<
+
+.S.o:
+ $(COMPILE) -c $<
+
+mostlyclean-compile:
+ -rm -f *.o core *.core
+
+clean-compile:
+
+distclean-compile:
+ -rm -f *.tab.c
+
+maintainer-clean-compile:
+
+libcli.a: $(libcli_a_OBJECTS) $(libcli_a_DEPENDENCIES)
+ -rm -f libcli.a
+ $(AR) cru libcli.a $(libcli_a_OBJECTS) $(libcli_a_LIBADD)
+ $(RANLIB) libcli.a
+.cc.o:
+ $(CXXCOMPILE) -c $<
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP)
+ list='$(SOURCES) $(HEADERS)'; \
+ unique=`for i in $$list; do echo $$i; done | \
+ awk ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ here=`pwd` && cd $(srcdir) \
+ && mkid -f$$here/ID $$unique $(LISP)
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS)'; \
+ unique=`for i in $$list; do echo $$i; done | \
+ awk ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
+ || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS)
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+ -rm -f TAGS ID
+
+maintainer-clean-tags:
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = lib/cli
+
+distdir: $(DISTFILES)
+ @for file in $(DISTFILES); do \
+ d=$(srcdir); \
+ if test -d $$d/$$file; then \
+ cp -pr $$d/$$file $(distdir)/$$file; \
+ else \
+ test -f $(distdir)/$$file \
+ || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+ || cp -p $$d/$$file $(distdir)/$$file || :; \
+ fi; \
+ done
+main.o: main.cc ../../config.h ../ac/time.h ../fdbuf/fdbuf.h \
+ ../fdbuf/fdibuf.h ../fdbuf/fdobuf.h cli.h
+messages.o: messages.cc ../../config.h ../fdbuf/fdbuf.h \
+ ../fdbuf/fdibuf.h ../fdbuf/fdobuf.h cli.h
+
+info-am:
+info: info-am
+dvi-am:
+dvi: dvi-am
+check-am: all-am
+check: check-am
+installcheck-am:
+installcheck: installcheck-am
+install-exec-am:
+install-exec: install-exec-am
+
+install-data-am:
+install-data: install-data-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-am
+uninstall-am:
+uninstall: uninstall-am
+all-am: Makefile $(LIBRARIES)
+all-redirect: all-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_STRIP_FLAG=-s install
+installdirs:
+
+
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -rm -f Makefile $(CONFIG_CLEAN_FILES)
+ -rm -f config.cache config.log stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+mostlyclean-am: mostlyclean-noinstLIBRARIES mostlyclean-compile \
+ mostlyclean-tags mostlyclean-generic
+
+mostlyclean: mostlyclean-am
+
+clean-am: clean-noinstLIBRARIES clean-compile clean-tags clean-generic \
+ mostlyclean-am
+
+clean: clean-am
+
+distclean-am: distclean-noinstLIBRARIES distclean-compile \
+ distclean-tags distclean-generic clean-am
+
+distclean: distclean-am
+
+maintainer-clean-am: maintainer-clean-noinstLIBRARIES \
+ maintainer-clean-compile maintainer-clean-tags \
+ maintainer-clean-generic distclean-am
+ @echo "This command is intended for maintainers to use;"
+ @echo "it deletes files that may require special tools to rebuild."
+
+maintainer-clean: maintainer-clean-am
+
+.PHONY: mostlyclean-noinstLIBRARIES distclean-noinstLIBRARIES \
+clean-noinstLIBRARIES maintainer-clean-noinstLIBRARIES \
+mostlyclean-compile distclean-compile clean-compile \
+maintainer-clean-compile tags mostlyclean-tags distclean-tags \
+clean-tags maintainer-clean-tags distdir info-am info dvi-am dvi check \
+check-am installcheck-am installcheck install-exec-am install-exec \
+install-data-am install-data install-am install uninstall-am uninstall \
+all-redirect all-am all installdirs mostlyclean-generic \
+distclean-generic clean-generic maintainer-clean-generic clean \
+mostlyclean distclean maintainer-clean
+
+#clitest_SOURCES = clitest.cc
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/lib/cli/cli.h b/lib/cli/cli.h
new file mode 100644
index 0000000..8a183e1
--- /dev/null
+++ b/lib/cli/cli.h
@@ -0,0 +1,59 @@
+#ifndef VMAILMGR__CLI__CLI__H__
+#define VMAILMGR__CLI__CLI__H__
+
+typedef bool (*cli_funcptr)(void*);
+
+struct cli_stringlist
+{
+ const char* string;
+ cli_stringlist* next;
+
+ cli_stringlist(const char* s)
+ : string(s), next(0)
+ {
+ }
+};
+
+struct cli_option
+{
+ char ch;
+ const char* name;
+ enum { flag, counter, integer, string, stringlist, uinteger } type;
+ int flag_value;
+ void* dataptr;
+ const char* helpstr;
+ const char* defaultstr;
+
+ int set(const char* arg);
+ int parse_long_eq(const char* arg);
+ int parse_long_noeq(const char* arg);
+};
+
+/* The following are required from the CLI program */
+extern const char* cli_program;
+extern const char* cli_help_prefix;
+extern const char* cli_help_suffix;
+extern const char* cli_args_usage;
+extern const int cli_args_min;
+extern const int cli_args_max;
+extern cli_option cli_options[];
+extern int cli_main(int argc, char* argv[]);
+
+/* The following are provided to the CLI program */
+extern const char* argv0;
+extern const char* argv0base;
+extern const char* argv0dir;
+extern void usage(int exit_value, const char* errorstr = 0);
+
+extern void cli_error(int exit_value,
+ const char*,
+ const char* = 0,
+ const char* = 0,
+ const char* = 0);
+
+extern void cli_warning(const char*,
+ const char* = 0,
+ const char* = 0,
+ const char* = 0);
+
+#endif // VMAILMGR__CLI__CLI__H__
diff --git a/lib/cli/cli2pod.pl b/lib/cli/cli2pod.pl
new file mode 100644
index 0000000..6327c70
--- /dev/null
+++ b/lib/cli/cli2pod.pl
@@ -0,0 +1,213 @@
+#!/usr/bin/perl
+
+sub cstr2pod {
+ local($_) = shift;
+ s/\\"/"/go;
+ s/"([^\"]*)"/"C<$1>"/go;
+ $_;
+}
+
+$section = 1;
+
+@section_order = (
+ 'NAME',
+ 'SYNOPSIS',
+ 'DESCRIPTION',
+ 'OPTIONS',
+ 'RETURN VALUE',
+ 'ERRORS',
+ 'EXAMPLES',
+ 'ENVIRONMENT',
+ 'FILES',
+ 'SEE ALSO',
+ 'NOTES',
+ 'CAVEATS',
+ 'WARNINGS',
+ 'DIAGNOSTICS',
+ 'BUGS',
+ 'RESTRICTIONS',
+ 'AUTHOR',
+ 'AUTHORS',
+ 'HISTORY'
+ );
+
+sub type2word {
+ my($type) = shift;
+ return 'INT' if $type eq 'integer';
+ return 'UINT' if $type eq 'uinteger';
+ return 'STR' if $type eq 'string' || $type eq 'stringlist';
+ return '' if $type eq 'flag' || $type eq 'counter';
+ die "Invalid cli option type '$type'";
+}
+
+sub add_option {
+ my($short, $long, $type, $desc) = @_;
+
+ my $s = '[B<';
+ my $o = '=item B<';
+ if($short) {
+ $s .= "-$short";
+ $o .= "-$short";
+ if($type) {
+ $s .= " $type";
+ $o .= " $type";
+ }
+ }
+ if($short && $long) {
+ $s .= ">]\n[B<";
+ $o .= ">, B<";
+ }
+ if($long) {
+ $s .= "--$long";
+ $o .= "--$long";
+ if($type) {
+ $s .= "=$type";
+ $o .= "=$type";
+ }
+ }
+ $s .= ">]\n";
+ $o .= ">\n\n$desc\n\n";
+
+ $synopsis .= $s;
+ $options = "=over 8\n\n" unless $options;
+ $options .= $o;
+}
+
+sub parse_option {
+ local($_) = shift;
+ s/^\s*\{\s*//o;
+ s/\s*\},?\s*/ /o;
+
+ my $short = $1 if s/^'([^\'])',\s*//o;
+ die "Invalid cli option" unless $short || s/^0,\s*//o;
+
+ my $long = $1 if s/^"([^\"]+)",\s*//o;
+ die "Invalid cli_option" unless $long || s/^0,\s*//o;
+
+ my $type = $1 if s/^cli_option::(\S+),\s*//o;
+ die "Invalid cli_option" unless $type;
+ $type = &type2word($type);
+
+ my $val = $1 if s/^([^,]+),\s*//o;
+ my $var = $1 if s/^&([^,]+),\s*//o;
+
+ my $desc = cstr2pod($1) if s/^"([^,]+)",\s*//o;
+ die "Invalid cli_option" unless $desc;
+ $desc =~ s/\.?$/./o if $desc;
+
+ my $default = $1 if s/^"([^\"]+)"\s+//o;
+ die "Invalid cli_option" unless $default || s/^0\s+//o;
+ $desc .= " Defaults to $default." if $default;
+
+ s/\s*\/\/\s*/ /go;
+ s/^\s*//o;
+
+ add_option($short, $long, $type, $_ || $desc);
+}
+
+sub parse_options {
+ $synopsis = "B<$program>\n";
+
+ my $line;
+ while(<>) {
+ s/^\s+//o;
+ s/\s+$//o;
+ if($line && /^\{/o) {
+ &parse_option($line);
+ $line = "";
+ }
+ next if /^\{\s*0\s*\},?/o;
+ next if /^\{\s*0\s*,\s*\},?/o;
+ last if /^\s*\};/o;
+ $line =~ s/$/ $_/;
+ }
+ &parse_option($line) if $line;
+
+ $synopsis .= "I<$usage>" if $usage;
+ $options .= "=back" if $options;
+ $sections{'SYNOPSIS'} = $synopsis;
+ $sections{'OPTIONS'} = $options;
+}
+
+sub parse_notes {
+ my $section;
+ my $title;
+ while(<>) {
+ chomp;
+ last unless /^$/o || s/^\/\/\s*//o;
+ if(/^[\sA-Z]+$/o) {
+ $sections{$title} = $section if $title && $section;
+ undef $section;
+ $title = $_;
+ } else {
+ $section .= "$_\n";
+ }
+ }
+ $sections{$title} = $section if $title && $section;
+}
+
+sub parse_header_line {
+ local($_, $comment) = @_;
+ if(s/^\s*const\s+char\s*\*\s*cli_(\S+)\s*=\s*//o) {
+ my $name = $1;
+ s/;\s*$//o;
+ s/^\"//;
+ s/\"$//o;
+ s/\\n$//o;
+ s/\\n""/\n/go;
+ $program = $_ if $name eq 'program';
+ $prefix = $_ if $name eq 'help_prefix';
+ $usage = $_ if $name eq 'args_usage';
+ $suffix = $_ if $name eq 'help_suffix';
+ }
+}
+
+sub parse_header {
+ my $comment = '';
+ my $line = '';
+ while(<>) {
+ s/^\s+//o;
+ s/\s+$//o;
+ if(s/^.*Copyright\s*\(C\)\s*[\d,]+\s*//o) {
+ $author = $_;
+ } else {
+ last if ($program && $prefix && /^$/o);
+ next if /^#/o;
+ $comment .= "$1\n" if s|\s*//\s*(.*)$||o;
+ $line =~ s/$/\n$_/;
+ if(/;$/o) {
+ &parse_header_line($line, $comment);
+ undef $line;
+ undef $comment;
+ }
+ }
+ }
+}
+
+sub parse_description {
+ while(<>) {
+ s/^\s+//o;
+ s/\s+$//o;
+ last if / cli_options\[\]\s*=\s*\{/o;
+ next unless s/^\/\/\s*//o;
+ $description .= "$_\n";
+ }
+}
+
+&parse_header;
+&parse_description;
+&parse_options;
+&parse_notes;
+
+$description .= "\n\n$suffix\n" if $suffix;
+
+$sections{'NAME'} = "$program - $prefix";
+$sections{'DESCRIPTION'} = $description;
+$sections{'AUTHORS'} = $author if $author;
+
+foreach $section (@section_order) {
+ print "=head1 $section\n\n$sections{$section}\n\n"
+ if $sections{$section};
+}
+
+1;
diff --git a/lib/cli/clitest.cc b/lib/cli/clitest.cc
new file mode 100644
index 0000000..ae4fcd0
--- /dev/null
+++ b/lib/cli/clitest.cc
@@ -0,0 +1,47 @@
+// Copyright (C) 1999,2000 Bruce Guenter <bruceg@em.ca>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+#include <config.h>
+#include "cli.h"
+#include "fdbuf/fdbuf.h"
+
+const char* cli_program = "clitest";
+const char* cli_help_prefix = "Does nothing but set flags\n";
+const char* cli_help_suffix = "";
+const char* cli_args_usage = "";
+const int cli_args_min = 0;
+const int cli_args_max = -1;
+int o_flag = 0;
+int o_int = 0;
+char* o_string = "nostring";
+cli_option cli_options[] = {
+ { 'f', "flag", cli_option::flag, 1, &o_flag, "Sets a flag", 0 },
+ { 'i', "int", cli_option::integer, 0, &o_int, "Sets an integer", 0 },
+ { 's', "str", cli_option::string, 0, &o_string, "Sets a string", 0},
+ {0} };
+
+int cli_main(int argc, char* argv[])
+{
+ fout << "argv0=" << argv0 << endl
+ << " argv0dir=" << argv0dir << endl
+ << " argv0base=" << argv0base << endl;
+ fout << "The flag is set to " << o_flag << endl;
+ fout << "The integer is set to " << o_int << endl;
+ fout << "The string is set to " << o_string << endl;
+ for(int i = 0; i < argc; i++)
+ fout << "argv[" << i << "] = '" << argv[i] << "'\n";
+ return 0;
+}
diff --git a/lib/cli/main.cc b/lib/cli/main.cc
new file mode 100644
index 0000000..fa9da91
--- /dev/null
+++ b/lib/cli/main.cc
@@ -0,0 +1,342 @@
+// Copyright (C) 1999,2000 Bruce Guenter <bruceg@em.ca>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+#include <config.h>
+#include "ac/time.h"
+#include "fdbuf/fdbuf.h"
+#include <stdlib.h>
+#include <string.h>
+#include "cli.h"
+
+#ifndef HAVE_SRANDOM
+void srandom(unsigned int seed);
+#endif
+
+static bool do_show_usage = false;
+const char* argv0;
+const char* argv0base;
+const char* argv0dir;
+
+static cli_option help_option = { 'h', "help", cli_option::flag,
+ true, &do_show_usage,
+ "Display this help and exit", 0 };
+
+static cli_option** options;
+static unsigned optionc;
+
+static void build_options()
+{
+ for(optionc = 0;
+ cli_options[optionc].ch || cli_options[optionc].name;
+ optionc++) ;
+ optionc++;
+ options = new cli_option*[optionc];
+ for(unsigned i = 0; i < optionc-1; i++)
+ options[i] = &cli_options[i];
+ options[optionc-1] = &help_option;
+}
+
+static inline unsigned max(unsigned a, unsigned b)
+{
+ return (a>b) ? a : b;
+}
+
+static const char* fill(unsigned i)
+{
+ static unsigned lastlen = 0;
+ static char* buf = 0;
+ if(i > lastlen) {
+ delete[] buf;
+ buf = new char[i+1];
+ lastlen = i;
+ }
+ memset(buf, ' ', i);
+ buf[i] = 0;
+ return buf;
+}
+
+static void show_usage()
+{
+ fout << "usage: " << cli_program << " [flags] " << cli_args_usage << endl;
+}
+
+static unsigned calc_max_width()
+{
+ // maxwidth is the maximum width of the long argument
+ unsigned maxwidth = 0;
+ for(unsigned i = 0; i < optionc; i++) {
+ unsigned width = 0;
+ cli_option* o = options[i];
+ if(o->name) {
+ width += strlen(o->name);
+ switch(o->type) {
+ case cli_option::string: width += 6; break;
+ case cli_option::integer: width += 4; break;
+ case cli_option::uinteger: width += 4; break;
+ case cli_option::stringlist: width += 5; break;
+ case cli_option::flag: break;
+ case cli_option::counter: break;
+ }
+ }
+ if(width > maxwidth)
+ maxwidth = width;
+ }
+ return maxwidth;
+}
+
+static void show_option(cli_option* o, unsigned maxwidth)
+{
+ if(o == &help_option)
+ fout << '\n';
+ if(o->ch)
+ fout << " -" << o->ch;
+ else
+ fout << " ";
+ fout << (o->ch && o->name ? ", " : " ");
+ if(o->name) {
+ const char* extra = "";
+ switch(o->type) {
+ case cli_option::string: extra = "=VALUE"; break;
+ case cli_option::integer: extra = "=INT"; break;
+ case cli_option::uinteger: extra = "=UNS"; break;
+ case cli_option::stringlist: extra = "=ITEM"; break;
+ case cli_option::flag: break;
+ case cli_option::counter: break;
+ }
+ fout << "--" << o->name << extra
+ << fill(maxwidth - strlen(o->name) - strlen(extra) + 2);
+ }
+ else
+ fout << fill(maxwidth+4);
+ fout << o->helpstr << '\n';
+ if(o->defaultstr)
+ fout << fill(maxwidth+10) << "(Defaults to " << o->defaultstr << ")\n";
+}
+
+static void show_help()
+{
+ if(cli_help_prefix)
+ fout << cli_help_prefix;
+ unsigned maxwidth = calc_max_width();
+ for(unsigned i = 0; i < optionc; i++)
+ show_option(options[i], maxwidth);
+ if(cli_help_suffix)
+ fout << cli_help_suffix;
+}
+
+void usage(int exit_value, const char* errorstr)
+{
+ if(errorstr)
+ ferr << cli_program << ": " << errorstr << endl;
+ show_usage();
+ show_help();
+ exit(exit_value);
+}
+
+cli_stringlist* stringlist_append(cli_stringlist* node, const char* newstr)
+{
+ cli_stringlist* newnode = new cli_stringlist(newstr);
+ if(node) {
+ cli_stringlist* head = node;
+ while(node->next)
+ node = node->next;
+ node->next = newnode;
+ return head;
+ }
+ else
+ return newnode;
+}
+
+int cli_option::set(const char* arg)
+{
+ char* endptr;
+ switch(type) {
+ case flag:
+ *(int*)dataptr = flag_value;
+ return 0;
+ case counter:
+ *(int*)dataptr += flag_value;
+ return 0;
+ case integer:
+ *(int*)dataptr = strtol(arg, &endptr, 10);
+ if(*endptr) {
+ ferr << argv0 << ": invalid integer: " << arg << endl;
+ return -1;
+ }
+ return 1;
+ case uinteger:
+ *(unsigned*)dataptr = strtoul(arg, &endptr, 10);
+ if(*endptr) {
+ ferr << argv0 << ": invalid unsigned integer: " << arg << endl;
+ return -1;
+ }
+ return 1;
+ case stringlist:
+ *(cli_stringlist**)dataptr =
+ stringlist_append(*(cli_stringlist**)dataptr, arg);
+ return 1;
+ default: // string
+ *(const char**)dataptr = arg;
+ return 1;
+ }
+}
+
+static int parse_short(int argc, char* argv[])
+{
+ int end = strlen(argv[0]) - 1;
+ for(int i = 1; i <= end; i++) {
+ int ch = argv[0][i];
+ unsigned j;
+ for(j = 0; j < optionc; j++) {
+ cli_option* o = options[j];
+ if(o->ch == ch) {
+ if(o->type != cli_option::flag &&
+ o->type != cli_option::counter) {
+ if(i < end) {
+ if(o->set(argv[0]+i+1) != -1)
+ return 0;
+ }
+ else if(argc <= 1) {
+ ferr << argv0 << ": option -" << o->ch
+ << " requires a value." << endl;
+ }
+ else
+ if(o->set(argv[1]) != -1)
+ return 1;
+ }
+ else if(o->set(0) != -1)
+ break;
+ return -1;
+ }
+ }
+ if(j >= optionc) {
+ ferr << argv0 << ": unknown option letter -" << argv[0][i] << endl;
+ return -1;
+ }
+ }
+ return 0;
+}
+
+int cli_option::parse_long_eq(const char* arg)
+{
+ if(type == flag || type == counter) {
+ ferr << argv0 << ": option --" << name
+ << " does not take a value." << endl;
+ return -1;
+ }
+ else
+ return set(arg)-1;
+}
+
+int cli_option::parse_long_noeq(const char* arg)
+{
+ if(type == flag || type == counter)
+ return set(0);
+ else if(arg)
+ return set(arg);
+ else {
+ ferr << argv0 << ": option --" << name
+ << " requires a value." << endl;
+ return -1;
+ }
+}
+
+static int parse_long(int, char* argv[])
+{
+ const char* arg = argv[0]+2;
+ for(unsigned j = 0; j < optionc; j++) {
+ cli_option* o = options[j];
+ if(o->name) {
+ size_t len = strlen(o->name);
+ if(!memcmp(arg, o->name, len)) {
+ if(arg[len] == '\0')
+ return o->parse_long_noeq(argv[1]);
+ else if(arg[len] == '=')
+ return o->parse_long_eq(arg+len+1);
+ }
+ }
+ }
+ ferr << argv0 << ": unknown option string: '--" << arg << "'" << endl;
+ return -1;
+}
+
+static int parse_args(int argc, char* argv[])
+{
+ build_options();
+ int i;
+ for(i = 1; i < argc; i++) {
+ const char* arg = argv[i];
+ // Stop at the first non-option argument
+ if(arg[0] != '-')
+ break;
+ // Stop after the first "-" or "--"
+ if(arg[1] == '\0' ||
+ (arg[1] == '-' && arg[2] == '\0')) {
+ i++;
+ break;
+ }
+ int j = (arg[1] != '-') ?
+ parse_short(argc-i, argv+i) :
+ parse_long(argc-i, argv+i);
+ if(j < 0)
+ usage(1);
+ else
+ i += j;
+ }
+ return i;
+}
+
+static void set_argv0(const char* p)
+{
+ argv0 = p;
+ static const char* empty = "";
+ const char* s = strrchr(p, '/');
+ if(s) {
+ ++s;
+ argv0base = s;
+ size_t length = s-p;
+ char* tmp = new char[length+1];
+ memcpy(tmp, p, length);
+ tmp[length] = 0;
+ argv0dir = tmp;
+ }
+ else {
+ argv0base = p;
+ argv0dir = empty;
+ }
+}
+
+int main(int argc, char* argv[])
+{
+ struct timeval tv;
+ gettimeofday(&tv, 0);
+ srandom(tv.tv_usec ^ tv.tv_sec);
+
+ set_argv0(argv[0]);
+ int lastarg = parse_args(argc, argv);
+
+ if(do_show_usage)
+ usage(0);
+
+ argc -= lastarg;
+ argv += lastarg;
+ if(argc < cli_args_min)
+ usage(1, "Too few command-line arguments");
+ if(cli_args_max >= cli_args_min && argc > cli_args_max)
+ usage(1, "Too many command-line arguments");
+
+ return cli_main(argc, argv);
+}
diff --git a/lib/cli/messages.cc b/lib/cli/messages.cc
new file mode 100644
index 0000000..2810c8a
--- /dev/null
+++ b/lib/cli/messages.cc
@@ -0,0 +1,44 @@
+// Copyright (C) 1999,2000 Bruce Guenter <bruceg@em.ca>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+#include <config.h>
+#include "fdbuf/fdbuf.h"
+#include <stdlib.h>
+#include "cli.h"
+
+extern const char* argv0;
+
+void cli_error(int exit_value,
+ const char* a,
+ const char* b,
+ const char* c,
+ const char* d)
+{
+ cli_warning(a,b,c,d);
+ exit(exit_value);
+}
+
+void cli_warning(const char* a,
+ const char* b,
+ const char* c,
+ const char* d)
+{
+ ferr << cli_program << ": " << a;
+ if(b) ferr << b;
+ if(c) ferr << c;
+ if(d) ferr << d;
+ ferr << endl;
+}
diff --git a/lib/config_read.cc b/lib/config_read.cc
new file mode 100644
index 0000000..094c659
--- /dev/null
+++ b/lib/config_read.cc
@@ -0,0 +1,36 @@
+// nullmailer -- a simple relay-only MTA
+// Copyright (C) 1999,2000 Bruce Guenter <bruceg@em.ca>
+//
+// 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
+//
+// You can contact me at <bruceg@em.ca>. There is also a mailing list
+// available to discuss this package. To subscribe, send an email to
+// <nullmailer-subscribe@lists.em.ca>.
+
+#include "config.h"
+#include "defines.h"
+#include "configio.h"
+#include "fdbuf/fdbuf.h"
+
+bool config_read(const char* filename, mystring& result)
+{
+ mystring fullname = CONFIG_DIR;
+ fullname += filename;
+ fdibuf in(fullname.c_str());
+ if(!in.getline(result))
+ return false;
+ result = result.strip();
+ return result.length() > 0;
+}
diff --git a/lib/config_readint.cc b/lib/config_readint.cc
new file mode 100644
index 0000000..fdcbe4d
--- /dev/null
+++ b/lib/config_readint.cc
@@ -0,0 +1,36 @@
+// nullmailer -- a simple relay-only MTA
+// Copyright (C) 1999,2000 Bruce Guenter <bruceg@em.ca>
+//
+// 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
+//
+// You can contact me at <bruceg@em.ca>. There is also a mailing list
+// available to discuss this package. To subscribe, send an email to
+// <nullmailer-subscribe@lists.em.ca>.
+
+#include "config.h"
+#include <stdlib.h>
+#include "defines.h"
+#include "configio.h"
+#include "fdbuf/fdbuf.h"
+
+bool config_readint(const char* filename, int& result)
+{
+ mystring tmp;
+ if(!config_read(filename, tmp))
+ return false;
+ char* endptr;
+ result = strtol(tmp.c_str(), &endptr, 10);
+ return endptr > tmp.c_str();
+}
diff --git a/lib/config_readlist.cc b/lib/config_readlist.cc
new file mode 100644
index 0000000..89069d4
--- /dev/null
+++ b/lib/config_readlist.cc
@@ -0,0 +1,44 @@
+// nullmailer -- a simple relay-only MTA
+// Copyright (C) 1999,2000 Bruce Guenter <bruceg@em.ca>
+//
+// 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
+//
+// You can contact me at <bruceg@em.ca>. There is also a mailing list
+// available to discuss this package. To subscribe, send an email to
+// <nullmailer-subscribe@lists.em.ca>.
+
+#include "config.h"
+#include "defines.h"
+#include "configio.h"
+#include "fdbuf/fdbuf.h"
+
+bool config_readlist(const char* filename, list<mystring>& result)
+{
+ mystring fullname = CONFIG_DIR;
+ fullname += filename;
+ fdibuf in(fullname.c_str());
+ if(!in)
+ return false;
+ mystring tmp;
+ bool nonempty = false;
+ while(in.getline(tmp)) {
+ tmp = tmp.strip();
+ if(tmp[0] != '#' && tmp.length() > 0) {
+ result.append(tmp);
+ nonempty = true;
+ }
+ }
+ return nonempty;
+}
diff --git a/lib/configio.h b/lib/configio.h
new file mode 100644
index 0000000..54319cc
--- /dev/null
+++ b/lib/configio.h
@@ -0,0 +1,11 @@
+#ifndef NULLMAILER__CONFIGIO__H__
+#define NULLMAILER__CONFIGIO__H__
+
+#include "mystring/mystring.h"
+#include "list.h"
+
+bool config_read(const char* filename, mystring& result);
+bool config_readlist(const char* filename, list<mystring>& result);
+bool config_readint(const char* filename, int& result);
+
+#endif // NULLMAILER__CONFIGIO__H__
diff --git a/lib/connect.h b/lib/connect.h
new file mode 100644
index 0000000..0f2af85
--- /dev/null
+++ b/lib/connect.h
@@ -0,0 +1,8 @@
+#ifndef NULLMAILER_CONNECT__H__
+#define NULLMAILER_CONNECT__H__
+
+#include "mystring/mystring.h"
+
+extern int tcpconnect(const mystring& hostname, int port);
+
+#endif // NULLMAILER_CONNECT__H__
diff --git a/lib/defines.h b/lib/defines.h
new file mode 100644
index 0000000..0017e19
--- /dev/null
+++ b/lib/defines.h
@@ -0,0 +1,13 @@
+#ifndef NULLMAILER__DEFINES__H__
+#define NULLMAILER__DEFINES__H__
+
+extern const char* QUEUE_DIR;
+extern const char* QUEUE_TMP_DIR;
+extern const char* QUEUE_MSG_DIR;
+extern const char* QUEUE_TRIGGER;
+extern const char* CONFIG_DIR;
+extern const char* PROTOCOL_DIR;
+extern const char* BIN_DIR;
+extern const char* SBIN_DIR;
+
+#endif /* NULLMAILER__DEFINES__H__ */
diff --git a/lib/errcodes.cc b/lib/errcodes.cc
new file mode 100644
index 0000000..834a531
--- /dev/null
+++ b/lib/errcodes.cc
@@ -0,0 +1,45 @@
+// nullmailer -- a simple relay-only MTA
+// Copyright (C) 1999,2000 Bruce Guenter <bruceg@em.ca>
+//
+// 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
+//
+// You can contact me at <bruceg@em.ca>. There is also a mailing list
+// available to discuss this package. To subscribe, send an email to
+// <nullmailer-subscribe@lists.em.ca>.
+
+#include "errcodes.h"
+
+const char* const errorstr[] = {
+ "No error",
+ "Unspecified error",
+ "Host not found",
+ "Host has no address",
+ "Fatal error in gethostbyname",
+ "Temporary error in gethostbyname",
+ "Socket failed",
+ "Connection refused",
+ "Connection timed out",
+ "Host or network unreachable",
+ "Connection failed",
+ "Protocol error",
+ "Could not open message",
+ "Could not read message",
+ "Could not write message",
+ "Could not exec program",
+ "Server refused the message",
+ "Temporary error in sending the message",
+ "Permanent error in sending the message",
+ "Command-line usage error",
+};
diff --git a/lib/errcodes.h b/lib/errcodes.h
new file mode 100644
index 0000000..c2b70eb
--- /dev/null
+++ b/lib/errcodes.h
@@ -0,0 +1,26 @@
+#ifndef NULLMAILER__ERRCODES__H__
+#define NULLMAILER__ERRCODES__H__
+
+#define ERR_USAGE 1 // Invalid command-line arguments
+#define ERR_HOST_NOT_FOUND 2 // gethostbyname failed with HOST_NOT_FOUND
+#define ERR_NO_ADDRESS 3 // gethostbyname failed with NO_ADDRESS
+#define ERR_GHBN_FATAL 4 // gethostbyname failed with NO_RECOVERY
+#define ERR_GHBN_TEMP 5 // gethostbyname failed with TRY_AGAIN
+#define ERR_SOCKET 6 // socket failed
+#define ERR_CONN_REFUSED 7 // connect failed with ECONNREFUSED
+#define ERR_CONN_TIMEDOUT 8 // connect failed with ETIMEDOUT
+#define ERR_CONN_UNREACHABLE 9 // connect failed with ENETUNREACH
+#define ERR_CONN_FAILED 10 // connect failed
+#define ERR_PROTO 11 // unexpected result from server
+#define ERR_MSG_OPEN 12 // could not open the message
+#define ERR_MSG_READ 13 // reading the message failed
+#define ERR_MSG_WRITE 14 // writing the message failed
+#define ERR_EXEC_FAILED 15 // executing a program failed
+#define ERR_MSG_REFUSED 16 // server refused the message
+#define ERR_MSG_TEMPFAIL 17 // server temporarily failed to receive
+#define ERR_MSG_PERMFAIL 18 // server permanently failed to receive
+#define ERR_UNKNOWN 19 // Arbitrary error code
+
+extern const char* const errorstr[];
+
+#endif // NULLMAILER__ERRCODES__H__
diff --git a/lib/fdbuf/ChangeLog b/lib/fdbuf/ChangeLog
new file mode 100644
index 0000000..ba96ad5
--- /dev/null
+++ b/lib/fdbuf/ChangeLog
@@ -0,0 +1,161 @@
+2000-08-22 Bruce Guenter <bruce@bruce-guenter.dyndns.org>
+
+ * Added the missing accessor for the internal "errnum" data member
+ to the fdibuf and fdobuf classes.
+
+2000-08-10 Bruce Guenter <bruce@bruce-guenter.dyndns.org>
+
+ * fdibuf.cc (read_large): Fixed a bug in the increment of data.
+
+ * fdibuf_mystring.cc (getline): Reduced some of the expressions
+ into variables.
+
+2000-04-08 Bruce Guenter <bguenter@bguenter.pointsnorth.com>
+
+ * fdibuf.cc (read_large): Fixed bug: count needed to be
+ incremented after reading data in.
+
+2000-04-07 Bruce Guenter <bguenter@bguenter.pointsnorth.com>
+
+ * fdobuf_signed.cc (operator<<): Immediately output a '-' for
+ negative numbers rather than storing a negative flag for later.
+
+ * fdobuf_unsigned.cc (operator<<): Moved the integer versions of
+ this operator into their own modules.
+
+ * fdobuf_seek.cc (seek): Moved this routine out of fdobuf.cc
+
+ * fdibuf.cc (read_large): Added this routine to read in a chunk of
+ data larger than the size of the buffer.
+
+2000-04-06 Bruce Guenter <bguenter@bguenter.pointsnorth.com>
+
+ * fdibuf_netstring.cc (getnetstring): Moved this routine into its
+ own source file.
+
+ * fdobuf.cc (write_large): Added this routine to write out a chunk
+ of data larger than the size of the buffer, to avoid doing extra
+ copies.
+ (write): Removed an extraneous code segment.
+
+ * fdobuf.h: Moved the fdobuf declarations here.
+
+ * fdibuf.h: Moved the fdibuf declarations here.
+
+ * fdbuf.h: Removed extraneous fdobuf declaration.
+
+1999-07-08 Bruce Guenter <bguenter@mikhail.qcc.sk.ca>
+
+ * fdobuf.cc (write): Optimized this routine better for the case
+ where the amount of data to be written will fit inside the buffer.
+
+1999-07-05 Bruce Guenter <bguenter@mikhail.qcc.sk.ca>
+
+ * fdbuf.h (fdobuf,fdibuf): Made some of the routines here virtual
+ in order to extend it properly.
+ Added "tell()" operations to both fdibuf and fdobuf to indicate
+ the current logical read/write point.
+
+1999-07-04 Bruce Guenter <bguenter@mikhail.qcc.sk.ca>
+
+ * fdobuf_chownmod.cc: Added two new routines chown and chmod,
+ which operate directly on the open fd.
+
+1999-06-30 Bruce Guenter <bguenter@mikhail.qcc.sk.ca>
+
+ * fdibuf_mystring.cc (getline): Make this routine return the
+ number of bytes actually read, including the delimiter, even
+ though the delimiter is not added to the returned string.
+
+1999-06-29 Bruce Guenter <bguenter@mikhail.qcc.sk.ca>
+
+ * fdibuf.cc (fdibuf): Added a 'seekfwd' function to seek forwards
+ "o" bytes.
+
+ * fdibuf_mystring.cc (getline): Added locking and set the count
+ properly.
+
+1999-06-28 Bruce Guenter <bguenter@mikhail.qcc.sk.ca>
+
+ * fdibuf.cc (get): Make sure count is set for get.
+
+1999-06-06 Bruce Guenter <bguenter@mikhail.qcc.sk.ca>
+
+ * fdbuf.cc (fdbuf): Fixed long-standing bug -- I forgot to delete
+ the buffer in the destructor.
+ (close): Modified the code to ensure that the fd is not closed
+ twice (as would happen when destructing the fdbuf).
+
+1999-05-31 Bruce Guenter <bguenter@mikhail.qcc.sk.ca>
+
+ * fdobuf.cc: Redefined flush as nflush; added sync code to nflush;
+ made flush and sync call nflush; added mutex lock calls to all
+ public methods.
+
+ * fdibuf.cc: Added mutex lock calls to all public methods.
+
+ * fdbuf.cc: Added debugging implementations of lock() and unlock()
+ mutex operators (to be removed before real use).
+
+1999-05-28 Bruce Guenter <bguenter@mikhail.qcc.sk.ca>
+
+ * fdobuf.cc (fdobuf): Fixed missing initialization of bufpos in
+ one of the two constructors.
+
+1999-05-01 Bruce Guenter <bguenter@mikhail.qcc.sk.ca>
+
+ * fdobuf.cc (fdobuf): Added an optional "mode" parameter which
+ defaults to 0666, which is the permissions for the new file.
+ (sync): Wrote this function to fsync the file descriptor.
+
+1999-04-27 Bruce Guenter <bguenter@mikhail.qcc.sk.ca>
+
+ * fdbuf.h (fdobuf): Removed definition for sync and nonblock mode,
+ as they won't be handled correctly in the writing code.
+
+1999-04-03 Bruce Guenter <bguenter@mikhail.qcc.sk.ca>
+
+ * fdobuf.cc (operator<<): Wrote an operator for signed and
+ unsigned longs, with overloaded functions for ints and shorts that
+ promote the parameters to longs.
+ (write): Wrote a write routine specifically for a single
+ character.
+
+1999-04-01 Bruce Guenter <bguenter@mikhail.qcc.sk.ca>
+
+ * fdobuf.cc: Fixed handling of seek by adding a "bufpos" indicator
+ that points to the current position in the buffer at which writes
+ should go. buflength is effectively the maximum value of bufpos
+ between flushes.
+
+ * fdibuf.cc (get): Renamed getchar to get (to be potentially
+ overloaded with other types).
+
+ * fdbuf.h (fdbuf): Removed a bunch of write methods and replaced
+ them with "operator<<", with similar capability to iostreams
+ methods of the same names.
+
+ * fdobuf.cc (endl): Wrote this manipulator to write an end-of-line
+ and flush the buffer.
+
+1999-03-31 Bruce Guenter <bguenter@mikhail.qcc.sk.ca>
+
+ * fdobuf_mystring.cc: Moved all the mystring-specific code from
+ fdobuf.cc into this module to lessen link problems.
+
+ * fdibuf_mystring.cc: Moved all the mystring-specific code from
+ fdibuf.cc into this module to lessen link problems.
+
+ * fdobuf.cc (seek): Wrote this seek routine to allow movement in
+ an output file buffer.
+
+ * fdibuf.cc (seek): Generalized the rewind routine to allow
+ arbitrary seeks. It also checks to see if the seek point is
+ within the current buffer and if so just repositions its
+ pointers.
+
+ * fdbuf.h: If BUFSIZE is not defined, set it here to 4096.
+ (class fdbuf ): Rename length, start, and size to buflength,
+ bufstart, and bufsize. Add a new field "offset" to indicate the
+ current file seek offset.
+
diff --git a/lib/fdbuf/Makefile.am b/lib/fdbuf/Makefile.am
new file mode 100644
index 0000000..85a4259
--- /dev/null
+++ b/lib/fdbuf/Makefile.am
@@ -0,0 +1,22 @@
+noinst_LIBRARIES = libfdbuf.a
+INCLUDES = -I..
+
+if FDBUF_NO_MYSTRING
+mystring_sources =
+else
+mystring_sources = fdibuf_mystring.cc fdibuf_netstring.cc
+endif
+
+libfdbuf_a_SOURCES = \
+ fdbuf.h \
+ fdbuf.cc \
+ fdbuf_copy.cc \
+ fdibuf.h \
+ fdibuf.cc \
+ fdobuf.h \
+ fdobuf.cc \
+ fdobuf_chownmod.cc \
+ fdobuf_seek.cc \
+ fdobuf_signed.cc \
+ fdobuf_unsigned.cc \
+ $(mystring_sources)
diff --git a/lib/fdbuf/Makefile.in b/lib/fdbuf/Makefile.in
new file mode 100644
index 0000000..f85834e
--- /dev/null
+++ b/lib/fdbuf/Makefile.in
@@ -0,0 +1,301 @@
+# Makefile.in generated automatically by automake 1.4a from Makefile.am
+
+# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DESTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ../..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_FLAG =
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+CC = @CC@
+CXX = @CXX@
+MAKEINFO = @MAKEINFO@
+MKDIR = @MKDIR@
+PACKAGE = @PACKAGE@
+RANLIB = @RANLIB@
+RM = @RM@
+STRIP = @STRIP@
+VERSION = @VERSION@
+
+noinst_LIBRARIES = libfdbuf.a
+INCLUDES = -I..
+@FDBUF_NO_MYSTRING_TRUE@mystring_sources =
+@FDBUF_NO_MYSTRING_FALSE@mystring_sources = fdibuf_mystring.cc fdibuf_netstring.cc
+
+libfdbuf_a_SOURCES = fdbuf.h fdbuf.cc fdbuf_copy.cc fdibuf.h fdibuf.cc fdobuf.h fdobuf.cc fdobuf_chownmod.cc fdobuf_seek.cc fdobuf_signed.cc fdobuf_unsigned.cc $(mystring_sources)
+
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = ../../config.h
+CONFIG_CLEAN_FILES =
+LIBRARIES = $(noinst_LIBRARIES)
+
+
+DEFS = @DEFS@ -I. -I$(srcdir) -I../..
+CPPFLAGS = @CPPFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+libfdbuf_a_LIBADD =
+@FDBUF_NO_MYSTRING_FALSE@libfdbuf_a_OBJECTS = fdbuf.o fdbuf_copy.o \
+@FDBUF_NO_MYSTRING_FALSE@fdibuf.o fdobuf.o fdobuf_chownmod.o \
+@FDBUF_NO_MYSTRING_FALSE@fdobuf_seek.o fdobuf_signed.o \
+@FDBUF_NO_MYSTRING_FALSE@fdobuf_unsigned.o fdibuf_mystring.o \
+@FDBUF_NO_MYSTRING_FALSE@fdibuf_netstring.o
+@FDBUF_NO_MYSTRING_TRUE@libfdbuf_a_OBJECTS = fdbuf.o fdbuf_copy.o \
+@FDBUF_NO_MYSTRING_TRUE@fdibuf.o fdobuf.o fdobuf_chownmod.o \
+@FDBUF_NO_MYSTRING_TRUE@fdobuf_seek.o fdobuf_signed.o fdobuf_unsigned.o
+AR = ar
+CXXFLAGS = @CXXFLAGS@
+CXXCOMPILE = $(CXX) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+CXXLD = $(CXX)
+CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(LDFLAGS) -o $@
+CFLAGS = @CFLAGS@
+COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@
+DIST_COMMON = ChangeLog Makefile.am Makefile.in
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = gtar
+GZIP_ENV = --best
+SOURCES = $(libfdbuf_a_SOURCES)
+OBJECTS = $(libfdbuf_a_OBJECTS)
+
+all: all-redirect
+.SUFFIXES:
+.SUFFIXES: .S .c .cc .o .s
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
+ cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps lib/fdbuf/Makefile
+
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ cd $(top_builddir) \
+ && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+
+mostlyclean-noinstLIBRARIES:
+
+clean-noinstLIBRARIES:
+ -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
+
+distclean-noinstLIBRARIES:
+
+maintainer-clean-noinstLIBRARIES:
+
+.c.o:
+ $(COMPILE) -c $<
+
+.s.o:
+ $(COMPILE) -c $<
+
+.S.o:
+ $(COMPILE) -c $<
+
+mostlyclean-compile:
+ -rm -f *.o core *.core
+
+clean-compile:
+
+distclean-compile:
+ -rm -f *.tab.c
+
+maintainer-clean-compile:
+
+libfdbuf.a: $(libfdbuf_a_OBJECTS) $(libfdbuf_a_DEPENDENCIES)
+ -rm -f libfdbuf.a
+ $(AR) cru libfdbuf.a $(libfdbuf_a_OBJECTS) $(libfdbuf_a_LIBADD)
+ $(RANLIB) libfdbuf.a
+.cc.o:
+ $(CXXCOMPILE) -c $<
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP)
+ list='$(SOURCES) $(HEADERS)'; \
+ unique=`for i in $$list; do echo $$i; done | \
+ awk ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ here=`pwd` && cd $(srcdir) \
+ && mkid -f$$here/ID $$unique $(LISP)
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS)'; \
+ unique=`for i in $$list; do echo $$i; done | \
+ awk ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
+ || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS)
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+ -rm -f TAGS ID
+
+maintainer-clean-tags:
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = lib/fdbuf
+
+distdir: $(DISTFILES)
+ @for file in $(DISTFILES); do \
+ d=$(srcdir); \
+ if test -d $$d/$$file; then \
+ cp -pr $$d/$$file $(distdir)/$$file; \
+ else \
+ test -f $(distdir)/$$file \
+ || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+ || cp -p $$d/$$file $(distdir)/$$file || :; \
+ fi; \
+ done
+fdbuf.o: fdbuf.cc fdbuf.h ../../config.h ../fdbuf/fdibuf.h \
+ ../fdbuf/fdobuf.h
+fdbuf_copy.o: fdbuf_copy.cc fdbuf.h ../../config.h ../fdbuf/fdibuf.h \
+ ../fdbuf/fdobuf.h
+fdibuf.o: fdibuf.cc fdbuf.h ../../config.h ../fdbuf/fdibuf.h \
+ ../fdbuf/fdobuf.h
+fdibuf_mystring.o: fdibuf_mystring.cc fdbuf.h ../../config.h \
+ ../fdbuf/fdibuf.h ../fdbuf/fdobuf.h ../mystring/mystring.h \
+ ../mystring/rep.h ../mystring/iter.h ../mystring/join.h
+fdibuf_netstring.o: fdibuf_netstring.cc fdbuf.h ../../config.h \
+ ../fdbuf/fdibuf.h ../fdbuf/fdobuf.h ../mystring/mystring.h \
+ ../mystring/rep.h ../mystring/iter.h ../mystring/join.h
+fdobuf.o: fdobuf.cc fdbuf.h ../../config.h ../fdbuf/fdibuf.h \
+ ../fdbuf/fdobuf.h
+fdobuf_chownmod.o: fdobuf_chownmod.cc fdbuf.h ../../config.h \
+ ../fdbuf/fdibuf.h ../fdbuf/fdobuf.h
+fdobuf_seek.o: fdobuf_seek.cc fdbuf.h ../../config.h ../fdbuf/fdibuf.h \
+ ../fdbuf/fdobuf.h
+fdobuf_signed.o: fdobuf_signed.cc fdbuf.h ../../config.h \
+ ../fdbuf/fdibuf.h ../fdbuf/fdobuf.h
+fdobuf_unsigned.o: fdobuf_unsigned.cc fdbuf.h ../../config.h \
+ ../fdbuf/fdibuf.h ../fdbuf/fdobuf.h
+
+info-am:
+info: info-am
+dvi-am:
+dvi: dvi-am
+check-am: all-am
+check: check-am
+installcheck-am:
+installcheck: installcheck-am
+install-exec-am:
+install-exec: install-exec-am
+
+install-data-am:
+install-data: install-data-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-am
+uninstall-am:
+uninstall: uninstall-am
+all-am: Makefile $(LIBRARIES)
+all-redirect: all-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_STRIP_FLAG=-s install
+installdirs:
+
+
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -rm -f Makefile $(CONFIG_CLEAN_FILES)
+ -rm -f config.cache config.log stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+mostlyclean-am: mostlyclean-noinstLIBRARIES mostlyclean-compile \
+ mostlyclean-tags mostlyclean-generic
+
+mostlyclean: mostlyclean-am
+
+clean-am: clean-noinstLIBRARIES clean-compile clean-tags clean-generic \
+ mostlyclean-am
+
+clean: clean-am
+
+distclean-am: distclean-noinstLIBRARIES distclean-compile \
+ distclean-tags distclean-generic clean-am
+
+distclean: distclean-am
+
+maintainer-clean-am: maintainer-clean-noinstLIBRARIES \
+ maintainer-clean-compile maintainer-clean-tags \
+ maintainer-clean-generic distclean-am
+ @echo "This command is intended for maintainers to use;"
+ @echo "it deletes files that may require special tools to rebuild."
+
+maintainer-clean: maintainer-clean-am
+
+.PHONY: mostlyclean-noinstLIBRARIES distclean-noinstLIBRARIES \
+clean-noinstLIBRARIES maintainer-clean-noinstLIBRARIES \
+mostlyclean-compile distclean-compile clean-compile \
+maintainer-clean-compile tags mostlyclean-tags distclean-tags \
+clean-tags maintainer-clean-tags distdir info-am info dvi-am dvi check \
+check-am installcheck-am installcheck install-exec-am install-exec \
+install-data-am install-data install-am install uninstall-am uninstall \
+all-redirect all-am all installdirs mostlyclean-generic \
+distclean-generic clean-generic maintainer-clean-generic clean \
+mostlyclean distclean maintainer-clean
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/lib/fdbuf/fdbuf.cc b/lib/fdbuf/fdbuf.cc
new file mode 100644
index 0000000..7b545d5
--- /dev/null
+++ b/lib/fdbuf/fdbuf.cc
@@ -0,0 +1,107 @@
+// Copyright (C) 1999,2000 Bruce Guenter <bruceg@em.ca>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+#include "fdbuf.h"
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+
+///////////////////////////////////////////////////////////////////////////////
+// Class fdbuf
+///////////////////////////////////////////////////////////////////////////////
+fdbuf::fdbuf(int fdesc, bool dc, unsigned bufsz)
+ : buf(new char[bufsz]),
+ buflength(0),
+ bufstart(0),
+ offset(0),
+ errnum(0),
+ flags(0),
+ bufsize(bufsz),
+ fd(fdesc),
+ do_close(dc)
+{
+ if(!buf) {
+ flags = flag_error;
+ errnum = errno;
+ }
+ if(fdesc < 0)
+ flags |= flag_closed;
+#ifdef _REENTRANT
+ pthread_mutex_t tmp = PTHREAD_MUTEX_INITIALIZER;
+ mutex = tmp;
+ pthread_mutex_init(&mutex, 0);
+#else
+#ifdef FDBUF_MUTEX_DEBUG
+ mutex_count = 0;
+#endif
+#endif
+}
+
+fdbuf::~fdbuf()
+{
+ close();
+#ifdef _REENTRANT
+ pthread_mutex_destroy(&mutex);
+#endif
+ delete buf;
+}
+
+bool fdbuf::error() const
+{
+ return flags & flag_error;
+}
+
+bool fdbuf::closed() const
+{
+ return flags & flag_closed;
+}
+
+bool fdbuf::close()
+{
+ if(do_close && fd >= 0 && !(flags & flag_closed)) {
+ if(::close(fd) == -1) {
+ errnum = errno;
+ flags |= flag_error;
+ return false;
+ }
+ flags |= flag_closed;
+ }
+ return true;
+}
+
+#if defined(FDBUF_MUTEX_DEBUG) && !defined(_REENTRANT)
+{
+ int* null = 0;
+ (*null)++;
+ kill(getpid(), 9);
+}
+
+// Debugging code
+void fdbuf::lock()
+{
+ if(mutex)
+ abort();
+ ++mutex;
+}
+
+void fdbuf::unlock()
+{
+ if(mutex != 1)
+ abort();
+ --mutex;
+}
+#endif
diff --git a/lib/fdbuf/fdbuf.h b/lib/fdbuf/fdbuf.h
new file mode 100644
index 0000000..34b8de9
--- /dev/null
+++ b/lib/fdbuf/fdbuf.h
@@ -0,0 +1,82 @@
+// Copyright (C) 1999,2000 Bruce Guenter <bruceg@em.ca>
+//
+// 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
+
+#ifndef FDBUF__H__
+#define FDBUF__H__
+
+#include "config.h"
+#include <string.h>
+#include <fcntl.h>
+
+#ifdef _REENTRANT
+#include <pthread.h>
+#endif
+
+#ifndef FDBUF_SIZE
+#define FDBUF_SIZE 4096
+#endif
+
+class mystring;
+
+class fdbuf
+{
+public:
+ enum flagbits { flag_eof=1, flag_error=2, flag_closed=4 };
+
+ fdbuf(int fdesc, bool dc, unsigned bufsz = FDBUF_SIZE);
+ ~fdbuf();
+ bool error() const;
+ bool closed() const;
+ bool close();
+#ifdef _REENTRANT
+ void lock() { pthread_mutex_lock(&mutex); }
+ void unlock() { pthread_mutex_unlock(&mutex); }
+#else
+#ifdef FDBUF_MUTEX_DEBUG
+ void lock();
+ void unlock();
+#else
+ void lock() { }
+ void unlock() { }
+#endif
+#endif
+protected:
+ char* const buf;
+ unsigned buflength; // Length of the data in the buffer
+ unsigned bufstart; // Start of the data in the buffer
+ unsigned offset; // Current file read/write offset
+ int errnum; // Saved error flag
+ unsigned flags; // Status flags
+
+ const unsigned bufsize; // Total buffer size
+ const int fd;
+ const bool do_close; // True to close on destructor
+
+#ifdef _REENTRANT
+ pthread_mutex_t mutex;
+#else
+#ifdef FDBUF_MUTEX_DEBUG
+ unsigned mutex;
+#endif
+#endif
+};
+
+#include "fdbuf/fdibuf.h"
+#include "fdbuf/fdobuf.h"
+
+bool fdbuf_copy(fdibuf&, fdobuf&, bool noflush = false);
+
+#endif // FDBUF__H__
diff --git a/lib/fdbuf/fdbuf_copy.cc b/lib/fdbuf/fdbuf_copy.cc
new file mode 100644
index 0000000..a76d733
--- /dev/null
+++ b/lib/fdbuf/fdbuf_copy.cc
@@ -0,0 +1,38 @@
+// Copyright (C) 1999,2000 Bruce Guenter <bruceg@em.ca>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+#include "fdbuf.h"
+
+///////////////////////////////////////////////////////////////////////////////
+// Other routines
+///////////////////////////////////////////////////////////////////////////////
+bool fdbuf_copy(fdibuf& in, fdobuf& out, bool noflush)
+{
+ if(in.eof())
+ return true;
+ if(!in || !out)
+ return false;
+ do {
+ char buf[FDBUF_SIZE];
+ if(!in.read(buf, FDBUF_SIZE) && in.last_count() == 0)
+ break;
+ if(!out.write(buf, in.last_count()) && out.last_count() < in.last_count())
+ return false;
+ } while(!in.eof());
+ if(!noflush && !out.flush())
+ return false;
+ return in.eof();
+}
diff --git a/lib/fdbuf/fdibuf.cc b/lib/fdbuf/fdibuf.cc
new file mode 100644
index 0000000..84ab288
--- /dev/null
+++ b/lib/fdbuf/fdibuf.cc
@@ -0,0 +1,192 @@
+// Copyright (C) 1999,2000 Bruce Guenter <bruceg@em.ca>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+#include "fdbuf.h"
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+
+///////////////////////////////////////////////////////////////////////////////
+// Class fdibuf
+///////////////////////////////////////////////////////////////////////////////
+fdibuf::fdibuf(int fdesc, bool dc, unsigned bufsz)
+ : fdbuf(fdesc, dc, bufsz)
+{
+}
+
+fdibuf::fdibuf(const char* filename, unsigned bufsz)
+ : fdbuf(open(filename, O_RDONLY), true, bufsz)
+{
+ if(fd == -1) {
+ flags = flag_error;
+ errnum = errno;
+ }
+}
+
+fdibuf::~fdibuf()
+{
+}
+
+bool fdibuf::eof() const
+{
+ return (flags & flag_eof) && (bufstart >= buflength);
+}
+
+bool fdibuf::operator!() const
+{
+ return eof() || error() || closed();
+}
+
+// refill is protected -- no locking
+bool fdibuf::refill()
+{
+ if(flags)
+ return false;
+ if(bufstart != 0) {
+ if(bufstart < buflength) {
+ buflength -= bufstart;
+ memcpy(buf, buf+bufstart, buflength);
+ } else
+ buflength = 0;
+ bufstart = 0;
+ }
+ unsigned oldbuflength = buflength;
+ if(buflength < bufsize) {
+ ssize_t red = ::read(fd, buf+buflength, bufsize-buflength);
+ if(red == -1) {
+ errnum = errno;
+ flags |= flag_error;
+ }
+ else if(red == 0)
+ flags |= flag_eof;
+ else {
+ buflength += red;
+ offset += red;
+ }
+ }
+ return buflength > oldbuflength;
+}
+
+bool fdibuf::get(char& ch)
+{
+ lock();
+ count = 0;
+ if(bufstart >= buflength)
+ refill();
+ bool r = true;
+ if(eof() || error())
+ r = false;
+ else {
+ ch = buf[bufstart++];
+ count = 1;
+ }
+ unlock();
+ return r;
+}
+
+bool fdibuf::read_large(char* data, unsigned datalen)
+{
+ lock();
+ count = 0;
+
+ // If there's any content in the buffer, memcpy it out first.
+ unsigned len = buflength - bufstart;
+ if(len > datalen)
+ len = datalen;
+ memcpy(data, buf+bufstart, len);
+ data += len;
+ datalen -= len;
+ bufstart += len;
+ count += len;
+
+ // After the buffer is empty and there's still data to read,
+ // read it straight from the fd instead of copying it through the buffer.
+ while(datalen > 0) {
+ ssize_t red = ::read(fd, data, datalen);
+ if(red == -1) {
+ errnum = errno;
+ flags |= flag_error;
+ break;
+ }
+ else if(red == 0) {
+ flags |= flag_eof;
+ break;
+ }
+ data += red;
+ datalen -= red;
+ offset += red;
+ count += red;
+ }
+ unlock();
+ return datalen == 0;
+}
+
+bool fdibuf::read(char* data, unsigned datalen)
+{
+ if(datalen >= bufsize)
+ return read_large(data, datalen);
+ lock();
+ count = 0;
+ char* ptr = data;
+ while(datalen && !eof()) {
+ if(bufstart >= buflength)
+ refill();
+ unsigned len = buflength-bufstart;
+ if(len > datalen)
+ len = datalen;
+ memcpy(ptr, buf+bufstart, len);
+ bufstart += len;
+ datalen -= len;
+ ptr += len;
+ count += len;
+ }
+ unlock();
+ return !datalen;
+}
+
+bool fdibuf::seek(unsigned o)
+{
+ lock();
+ unsigned buf_start = offset - buflength;
+ if(o >= buf_start && o < offset) {
+ bufstart = o - buf_start;
+ }
+ else {
+ if(lseek(fd, o, SEEK_SET) != (off_t)o) {
+ errnum = errno;
+ flags |= flag_error;
+ unlock();
+ return false;
+ }
+ offset = o;
+ buflength = bufstart = 0;
+ }
+ count = 0;
+ flags &= ~flag_eof;
+ unlock();
+ return true;
+}
+
+bool fdibuf::seekfwd(unsigned o)
+{
+ return seek(tell() + o);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Globals
+///////////////////////////////////////////////////////////////////////////////
+fdibuf fin(0);
diff --git a/lib/fdbuf/fdibuf.h b/lib/fdbuf/fdibuf.h
new file mode 100644
index 0000000..92681b0
--- /dev/null
+++ b/lib/fdbuf/fdibuf.h
@@ -0,0 +1,50 @@
+// Copyright (C) 1999,2000 Bruce Guenter <bruceg@em.ca>
+//
+// 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
+
+#ifndef FDBUF__FDIBUF__H__
+#define FDBUF__FDIBUF__H__
+
+class fdibuf : protected fdbuf
+{
+public:
+ fdibuf(const char* filename, unsigned bufsz = FDBUF_SIZE);
+ fdibuf(int fdesc, bool dc = false, unsigned bufsz = FDBUF_SIZE);
+ virtual ~fdibuf();
+ bool close() { lock(); bool r = fdbuf::close(); unlock(); return r; }
+ bool eof() const;
+ bool operator!() const ;
+ operator bool() const { return !operator!(); }
+ virtual bool get(char& ch);
+ virtual bool getline(mystring& out, char terminator = '\n');
+ virtual bool getnetstring(mystring& out);
+ virtual bool read(char*, unsigned);
+ virtual bool read_large(char*, unsigned);
+ bool read(unsigned char* b, unsigned l) { return read((char*)b, l); }
+ bool read(signed char* b, unsigned l) { return read((char*)b, l); }
+ unsigned last_count() { return count; }
+ bool seek(unsigned o);
+ bool seekfwd(unsigned o);
+ bool rewind() { return seek(0); }
+ unsigned tell() const { return offset-buflength+bufstart; }
+ int error_number() const { return errnum; }
+protected:
+ unsigned count; // Number of bytes read by last operation
+ bool refill();
+};
+
+extern fdibuf fin;
+
+#endif // FDBUF__FDIBUF__H__
diff --git a/lib/fdbuf/fdibuf_mystring.cc b/lib/fdbuf/fdibuf_mystring.cc
new file mode 100644
index 0000000..0434be1
--- /dev/null
+++ b/lib/fdbuf/fdibuf_mystring.cc
@@ -0,0 +1,52 @@
+// Copyright (C) 1999,2000 Bruce Guenter <bruceg@em.ca>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+#include <string.h>
+#include "fdbuf.h"
+#include "mystring/mystring.h"
+
+bool fdibuf::getline(mystring& out, char terminator)
+{
+ lock();
+ count = 0;
+ if(bufstart >= buflength)
+ refill();
+ if(eof() || error()) {
+ unlock();
+ return false;
+ }
+ out = "";
+ while(!eof() && !error()) {
+ char* ptr = buf+bufstart;
+ unsigned bufleft = buflength - bufstart;
+ const char* end = (const char*)memchr(ptr, terminator, bufleft);
+ if(!end) {
+ out += mystring(ptr, bufleft);
+ bufstart = buflength;
+ count += bufleft;
+ refill();
+ }
+ else {
+ unsigned copylen = end - ptr;
+ out += mystring(ptr, copylen);
+ bufstart += copylen+1;
+ count += copylen+1;
+ break;
+ }
+ }
+ unlock();
+ return true;
+}
diff --git a/lib/fdbuf/fdibuf_netstring.cc b/lib/fdbuf/fdibuf_netstring.cc
new file mode 100644
index 0000000..1d4b317
--- /dev/null
+++ b/lib/fdbuf/fdibuf_netstring.cc
@@ -0,0 +1,41 @@
+// Copyright (C) 1999,2000 Bruce Guenter <bruceg@em.ca>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+#include <string.h>
+#include "fdbuf.h"
+#include "mystring/mystring.h"
+
+bool fdibuf::getnetstring(mystring& out)
+{
+ // Read in the size
+ char ch;
+ unsigned long size = 0;
+ for(;;) {
+ if(!get(ch))
+ return false;
+ if(ch == ':')
+ break;
+ else if(ch >= '0' && ch <= '9')
+ size = size*10 + (ch-'0');
+ else
+ return false;
+ }
+ char tmp[size];
+ if(!read(tmp, size) || !get(ch) || ch != ',')
+ return false;
+ out = mystring(tmp, size);
+ return true;
+}
diff --git a/lib/fdbuf/fdobuf.cc b/lib/fdbuf/fdobuf.cc
new file mode 100644
index 0000000..97177e3
--- /dev/null
+++ b/lib/fdbuf/fdobuf.cc
@@ -0,0 +1,209 @@
+// Copyright (C) 1999,2000 Bruce Guenter <bruceg@em.ca>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+#include "fdbuf.h"
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+
+///////////////////////////////////////////////////////////////////////////////
+// Globals
+///////////////////////////////////////////////////////////////////////////////
+fdobuf fout(1);
+fdobuf ferr(2);
+
+///////////////////////////////////////////////////////////////////////////////
+// Class fdobuf
+///////////////////////////////////////////////////////////////////////////////
+fdobuf::fdobuf(int fdesc, bool dc, unsigned bufsz)
+ : fdbuf(fdesc, dc, bufsz),
+ bufpos(0)
+{
+}
+
+fdobuf::fdobuf(const char* filename, int f, int mode, unsigned bufsz)
+ : fdbuf(open(filename, O_WRONLY | f, mode), true, bufsz),
+ bufpos(0)
+{
+ if(fd == -1) {
+ flags = flag_error;
+ errnum = errno;
+ }
+}
+
+fdobuf::~fdobuf()
+{
+ flush();
+}
+
+bool fdobuf::close()
+{
+ if(!flush())
+ return false;
+ lock();
+ bool r = fdbuf::close();
+ unlock();
+ return r;
+}
+
+bool fdobuf::operator!() const
+{
+ return error() || closed();
+}
+
+bool fdobuf::nflush(bool withsync)
+{
+ if(flags)
+ return false;
+ while(bufstart < buflength) {
+ ssize_t written = ::write(fd, buf+bufstart, buflength-bufstart);
+ if(written == -1) {
+ flags |= flag_error;
+ errnum = errno;
+ return false;
+ }
+ else {
+ bufstart += written;
+ offset += written;
+ }
+ }
+ buflength = 0;
+ bufstart = 0;
+ bufpos = 0;
+ if(withsync && (fsync(fd) == -1)) {
+ flags |= flag_error;
+ errnum = errno;
+ return false;
+ }
+ return true;
+}
+
+bool fdobuf::flush()
+{
+ lock();
+ bool r = nflush(false);
+ unlock();
+ return r;
+}
+
+bool fdobuf::sync()
+{
+ lock();
+ bool r = nflush(true);
+ unlock();
+ return r;
+}
+
+bool fdobuf::write(char ch)
+{
+ if(flags)
+ return false;
+
+ lock();
+ count = 0;
+ buf[bufpos++] = ch;
+ //if(buflength >= bufsize && !nflush(false)) {
+ // unlock();
+ // return false;
+ //}
+ if(bufpos >= buflength)
+ buflength = bufpos;
+ if(buflength >= bufsize && !nflush(false)) {
+ unlock();
+ return false;
+ }
+ count = 1;
+ unlock();
+ return true;
+}
+
+bool fdobuf::write_large(const char* data, unsigned datalen)
+{
+ if(flags)
+ return false;
+
+ lock();
+ count = 0;
+
+ if(!nflush(false)) {
+ unlock();
+ return false;
+ }
+
+ while(datalen > 0) {
+ ssize_t written = ::write(fd, data, datalen);
+ if(written == -1) {
+ flags |= flag_error;
+ errnum = errno;
+ unlock();
+ return false;
+ }
+ datalen -= written;
+ data += written;
+ offset += written;
+ count += written;
+ }
+ unlock();
+ return true;
+}
+
+bool fdobuf::write(const char* data, unsigned datalen)
+{
+ if(datalen >= bufsize)
+ return write_large(data, datalen);
+
+ if(flags)
+ return false;
+
+ lock();
+ const char* ptr = data;
+ count = 0;
+ // Amount is the number of bytes available in the buffer
+ unsigned amount = bufsize-bufpos;
+ while(datalen >= amount) {
+ // If we get here, this copy will completely fill the buffer,
+ // requiring a flush
+ memcpy(buf+bufpos, ptr, amount);
+ bufpos = bufsize;
+ buflength = bufsize;
+ datalen -= amount;
+ ptr += amount;
+ if(!nflush(false)) {
+ unlock();
+ return false;
+ }
+ count += amount;
+ amount = bufsize-bufpos;
+ }
+ // At this point, the remaining data will fit into the buffer
+ memcpy(buf+bufpos, ptr, datalen);
+ count += datalen;
+ bufpos += datalen;
+ if(bufpos > buflength) buflength = bufpos;
+ unlock();
+ return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Manipulators
+///////////////////////////////////////////////////////////////////////////////
+fdobuf& endl(fdobuf& fd)
+{
+ fd.write("\n", 1);
+ fd.flush();
+ return fd;
+}
diff --git a/lib/fdbuf/fdobuf.h b/lib/fdbuf/fdobuf.h
new file mode 100644
index 0000000..aba0d49
--- /dev/null
+++ b/lib/fdbuf/fdobuf.h
@@ -0,0 +1,89 @@
+// Copyright (C) 1999,2000 Bruce Guenter <bruceg@em.ca>
+//
+// 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
+
+#ifndef FDBUF__FDOBUF__H__
+#define FDBUF__FDOBUF__H__
+
+class fdobuf : protected fdbuf
+{
+public:
+ enum openflags { create=O_CREAT,
+ excl=O_EXCL,
+ trunc=O_TRUNC,
+ append=O_APPEND };
+
+ fdobuf(const char* filename, int, int mode = 0666,
+ unsigned bufsz = FDBUF_SIZE);
+ fdobuf(int fdesc, bool dc=false, unsigned bufsz = FDBUF_SIZE);
+ virtual ~fdobuf();
+ bool close();
+ bool operator!() const;
+ operator bool() const
+ {
+ return !operator!();
+ }
+ bool flush();
+ bool sync();
+ virtual bool write(char);
+ bool write(unsigned char c) { return write((char)c); }
+ bool write(signed char c) { return write((char)c); }
+ virtual bool write(const char*, unsigned);
+ bool write(const unsigned char* b, unsigned l) { return write((char*)b, l); }
+ bool write(const signed char* b, unsigned l) { return write((char*)b, l); }
+ virtual bool write_large(const char*, unsigned);
+ unsigned last_count() { return count; }
+ bool seek(unsigned o);
+ bool rewind() { return seek(0); }
+ unsigned tell() const { return offset + bufpos; }
+
+ bool chown(uid_t, gid_t) const;
+ bool chmod(mode_t) const;
+
+ fdobuf& operator<<(const char* str)
+ {
+ write(str, strlen(str));
+ return *this;
+ }
+ fdobuf& operator<<(char ch)
+ {
+ write(ch);
+ return *this;
+ }
+ fdobuf& operator<<(fdobuf& (*manip)(fdobuf&))
+ {
+ return manip(*this);
+ }
+ fdobuf& operator<<(unsigned long);
+ fdobuf& operator<<(signed long);
+ fdobuf& operator<<(unsigned i) { return operator<<((unsigned long)i); }
+ fdobuf& operator<<(signed i) { return operator<<((signed long)i); }
+ fdobuf& operator<<(unsigned short i) { return operator<<((unsigned long)i); }
+ fdobuf& operator<<(signed short i) { return operator<<((signed long)i); }
+
+ int error_number() const { return errnum; }
+protected:
+ virtual bool nflush(bool withsync);
+
+ unsigned bufpos; // Current write position in the buffer
+ unsigned count; // Number of bytes written by last operation
+};
+
+fdobuf& endl(fdobuf& fd);
+
+extern fdobuf fout;
+extern fdobuf ferr;
+
+#endif // FDBUF__FDOBUF__H__
diff --git a/lib/fdbuf/fdobuf_chownmod.cc b/lib/fdbuf/fdobuf_chownmod.cc
new file mode 100644
index 0000000..7c2e340
--- /dev/null
+++ b/lib/fdbuf/fdobuf_chownmod.cc
@@ -0,0 +1,34 @@
+// Copyright (C) 1999,2000 Bruce Guenter <bruceg@em.ca>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+#include <string.h>
+#include "fdbuf.h"
+#include <sys/stat.h>
+#include <unistd.h>
+
+bool fdobuf::chown(uid_t uid, gid_t gid) const
+{
+ if(error())
+ return false;
+ return fchown(fd, uid, gid) != -1;
+}
+
+bool fdobuf::chmod(mode_t mode) const
+{
+ if(error())
+ return false;
+ return fchmod(fd, mode) != -1;
+}
diff --git a/lib/fdbuf/fdobuf_seek.cc b/lib/fdbuf/fdobuf_seek.cc
new file mode 100644
index 0000000..0aaa5ec
--- /dev/null
+++ b/lib/fdbuf/fdobuf_seek.cc
@@ -0,0 +1,48 @@
+// Copyright (C) 1999,2000 Bruce Guenter <bruceg@em.ca>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+#include "fdbuf.h"
+#include <errno.h>
+#include <unistd.h>
+
+bool fdobuf::seek(unsigned o)
+{
+ if(flags)
+ return false;
+
+ lock();
+ unsigned buf_start = offset;
+ unsigned buf_end = offset + buflength;
+ if(o >= buf_start && o < buf_end) {
+ bufpos = o - buf_start;
+ }
+ else {
+ if(!nflush(false)) {
+ unlock();
+ return false;
+ }
+ if(lseek(fd, o, SEEK_SET) != (off_t)o) {
+ errnum = errno;
+ flags |= flag_error;
+ unlock();
+ return false;
+ }
+ offset = o;
+ }
+ count = 0;
+ unlock();
+ return true;
+}
diff --git a/lib/fdbuf/fdobuf_signed.cc b/lib/fdbuf/fdobuf_signed.cc
new file mode 100644
index 0000000..27424d2
--- /dev/null
+++ b/lib/fdbuf/fdobuf_signed.cc
@@ -0,0 +1,38 @@
+// Copyright (C) 1999,2000 Bruce Guenter <bruceg@em.ca>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+#include "fdbuf.h"
+#include <limits.h>
+
+#define MAXSTRLEN ((sizeof(signed long)*CHAR_BIT)/3)
+
+fdobuf& fdobuf::operator<<(signed long i)
+{
+ if(i == 0)
+ return operator<<('0');
+ if(i < 0) {
+ operator<<('-');
+ i = -i;
+ }
+ char buf[MAXSTRLEN+1];
+ char* ptr = buf+MAXSTRLEN;
+ *ptr-- = 0;
+ while(i) {
+ *ptr-- = i % 10 + '0';
+ i /= 10;
+ }
+ return operator<<(ptr+1);
+}
diff --git a/lib/fdbuf/fdobuf_unsigned.cc b/lib/fdbuf/fdobuf_unsigned.cc
new file mode 100644
index 0000000..b0f9c47
--- /dev/null
+++ b/lib/fdbuf/fdobuf_unsigned.cc
@@ -0,0 +1,34 @@
+// Copyright (C) 1999,2000 Bruce Guenter <bruceg@em.ca>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+#include "fdbuf.h"
+#include <limits.h>
+
+#define MAXSTRLEN ((sizeof(signed long)*CHAR_BIT)/3)
+
+fdobuf& fdobuf::operator<<(unsigned long i)
+{
+ if(i == 0)
+ return operator<<('0');
+ char buf[MAXSTRLEN+1];
+ char* ptr = buf+MAXSTRLEN;
+ *ptr-- = 0;
+ while(i) {
+ *ptr-- = i % 10 + '0';
+ i /= 10;
+ }
+ return operator<<(ptr+1);
+}
diff --git a/lib/hostname.cc b/lib/hostname.cc
new file mode 100644
index 0000000..87848e2
--- /dev/null
+++ b/lib/hostname.cc
@@ -0,0 +1,85 @@
+// nullmailer -- a simple relay-only MTA
+// Copyright (C) 1999,2000 Bruce Guenter <bruceg@em.ca>
+//
+// 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
+//
+// You can contact me at <bruceg@em.ca>. There is also a mailing list
+// available to discuss this package. To subscribe, send an email to
+// <nullmailer-subscribe@lists.em.ca>.
+
+#include "config.h"
+#include "mystring/mystring.h"
+#include <unistd.h>
+#include <sys/utsname.h>
+
+static mystring* hostname_cache = 0;
+static mystring* domainname_cache = 0;
+
+#ifdef HAVE_GETDOMAINNAME
+// Re-declare the prototype here, as some systems don't declare it
+// in a predictable header file.
+extern "C" int getdomainname();
+#endif
+
+static void getnames()
+{
+ if(hostname_cache)
+ return;
+ struct utsname buf;
+ uname(&buf);
+ hostname_cache = new mystring(buf.nodename);
+
+#ifdef UTSNAME_HAS_DOMAINNAME
+ domainname_cache = new mystring(buf.UTSNAME_HAS_DOMAINNAME);
+#else
+#ifdef HAVE_GETDOMAINNAME
+ char hbuf[256];
+ getdomainname(hbuf, 255);
+ domainname_cache = new mystring(hbuf);
+#else
+ domainname_cache = new mystring;
+#endif // HAVE_GETDOMAINNAME
+#endif // UTSNAME_HAS_DOMAINNAME
+
+ // Tricky logic: if the node name does not contains the domain name
+ // as a proper suffix, paste them together.
+ char* nodename_end = buf.nodename + hostname_cache->length() -
+ domainname_cache->length() - 1;
+ if(domainname_cache->length() > 0) {
+ if(nodename_end <= buf.nodename ||
+ strcmp(nodename_end + 1, domainname_cache->c_str()) ||
+ *nodename_end != '.')
+ *hostname_cache = *hostname_cache + "." + *domainname_cache;
+ }
+ // Otherwise, the domain name is empty, try to determine it from
+ // the host name.
+ else {
+ int i = hostname_cache->find_first('.');
+ if(i != -1)
+ *domainname_cache = hostname_cache->right(i+1);
+ }
+}
+
+mystring hostname()
+{
+ getnames();
+ return *hostname_cache;
+}
+
+mystring domainname()
+{
+ getnames();
+ return *domainname_cache;
+}
diff --git a/lib/hostname.h b/lib/hostname.h
new file mode 100644
index 0000000..5dbb6e1
--- /dev/null
+++ b/lib/hostname.h
@@ -0,0 +1,7 @@
+#ifndef NULLMAILER__HOSTNAME__H__
+#define NULLMAILER__HOSTNAME__H__
+
+mystring hostname();
+mystring domainname();
+
+#endif
diff --git a/lib/itoa.cc b/lib/itoa.cc
new file mode 100644
index 0000000..54c927d
--- /dev/null
+++ b/lib/itoa.cc
@@ -0,0 +1,23 @@
+#include "itoa.h"
+
+const char *itoa(long v, int digits)
+{
+ static char buf[INTLENGTH];
+ bool neg = false;
+ if(v < 0) {
+ v = -v;
+ neg = true;
+ }
+ char* ptr = buf + INTLENGTH;
+ *--ptr = '\0';
+ do {
+ *--ptr = (v % 10) + '0';
+ v /= 10;
+ --digits;
+ } while(v != 0);
+ while(digits > 0 && ptr > buf-1)
+ *--ptr = '0', --digits;
+ if(neg)
+ *--ptr = '-';
+ return ptr;
+}
diff --git a/lib/itoa.h b/lib/itoa.h
new file mode 100644
index 0000000..8458805
--- /dev/null
+++ b/lib/itoa.h
@@ -0,0 +1,11 @@
+#ifndef ITOA__H__
+#define ITOA__H__
+
+#ifndef INTLENGTH
+#define INTLENGTH 64
+/* 40 digits is long enough to handle unsigned 128-bit numbers */
+#endif
+
+const char *itoa(long, int = 0);
+
+#endif
diff --git a/lib/list.h b/lib/list.h
new file mode 100644
index 0000000..9ed5988
--- /dev/null
+++ b/lib/list.h
@@ -0,0 +1,196 @@
+#ifndef LIST__H__
+#define LIST__H__
+
+template<class T> struct list_node
+{
+ list_node* next;
+ T data;
+ list_node(T d, list_node* n = 0) : next(n), data(d) { }
+ ~list_node() { }
+};
+
+template<class T> class list_iterator;
+template<class T> class const_list_iterator;
+
+template<class T> class list
+{
+public:
+ typedef list_node<T> node;
+ typedef list_iterator<T> iter;
+ typedef const_list_iterator<T> const_iter;
+ friend class iter;
+ friend class const_iter;
+
+ list()
+ : head(0), tail(0), cnt(0)
+ {
+ }
+ list(const list&);
+
+ ~list()
+ {
+ empty();
+ }
+
+ unsigned count() const
+ {
+ return cnt;
+ }
+
+ void empty()
+ {
+ while(head) {
+ node* next = head->next;
+ delete head;
+ head = next;
+ }
+ tail = 0;
+ cnt = 0;
+ }
+
+ bool append(T data)
+ {
+ node* n = new node(data);
+ if(tail)
+ tail->next = n;
+ else
+ head = n;
+ tail = n;
+ ++cnt;
+ return true;
+ }
+ bool prepend(T data)
+ {
+ head = new node(data, head);
+ if(!tail)
+ tail = head;
+ ++cnt;
+ return true;
+ }
+ bool remove(iter&);
+private:
+ node* head;
+ node* tail;
+ unsigned cnt;
+};
+
+template<class T> class const_list_iterator
+{
+ friend class list<T>;
+private:
+ inline void go_next()
+ {
+ prev = curr;
+ if(curr)
+ curr = curr->next;
+ }
+public:
+ const_list_iterator(const list<T>& l)
+ : lst(l), prev(0), curr(l.head)
+ {
+ }
+ void operator++()
+ {
+ go_next();
+ }
+ void operator++(int)
+ {
+ go_next();
+ }
+ T operator*() const
+ {
+ return curr->data;
+ }
+ bool operator!() const
+ {
+ return curr == 0;
+ }
+ operator bool() const
+ {
+ return !operator!();
+ }
+private:
+ const list<T>& lst;
+ const list<T>::node* prev;
+ const list<T>::node* curr;
+};
+
+template<class T>
+list<T>::list(const list<T>& that)
+ : head(0), tail(0), cnt(0)
+{
+ for(const_iter i = that; i; ++i)
+ append(*i);
+}
+
+template<class T> class list_iterator
+{
+ friend class list<T>;
+private:
+ inline void go_next()
+ {
+ prev = curr;
+ if(curr)
+ curr = curr->next;
+ }
+public:
+ list_iterator(list<T>& l)
+ : lst(l), prev(0), curr(l.head)
+ {
+ }
+ void operator++()
+ {
+ go_next();
+ }
+ void operator++(int)
+ {
+ go_next();
+ }
+ T operator*() const
+ {
+ return curr->data;
+ }
+ T& operator*()
+ {
+ return curr->data;
+ }
+ bool operator!() const
+ {
+ return curr == 0;
+ }
+ operator bool() const
+ {
+ return !operator!();
+ }
+private:
+ list<T>& lst;
+ list<T>::node* prev;
+ list<T>::node* curr;
+};
+
+template<class T>
+bool list<T>::remove(list<T>::iter& iter)
+{
+ if(this != &iter.lst)
+ return false;
+ if(!iter.curr)
+ return false;
+ if(iter.prev) {
+ iter.prev->next = iter.curr->next;
+ if(iter.curr == tail)
+ tail = iter.prev;
+ delete iter.curr;
+ iter.curr = iter.prev->next;
+ }
+ else {
+ head = iter.curr->next;
+ if(!head)
+ tail = 0;
+ delete iter.curr;
+ iter.curr = head;
+ }
+ --cnt;
+ return true;
+}
+
+#endif // LIST__H__
diff --git a/lib/listtest.cc b/lib/listtest.cc
new file mode 100644
index 0000000..fc10c71
--- /dev/null
+++ b/lib/listtest.cc
@@ -0,0 +1,50 @@
+#include <iostream.h>
+#include "list.h"
+
+typedef list<int> ilist;
+typedef ilist::iter iiter;
+
+void test_remove_first()
+{
+ ilist l;
+ l.append(1);
+ l.append(2);
+ iiter i(l);
+ l.remove(i);
+ if(!i) cout << "After removing first, iter no longer valid\n";
+ else if(*i != 2) cout << "After removing first, iter is wrong\n";
+ if(l.count() != 1) cout << "After removing first, count is wrong\n";
+}
+
+void test_remove_mid()
+{
+ ilist l;
+ l.append(1);
+ l.append(2);
+ l.append(3);
+ iiter i(l);
+ i++;
+ l.remove(i);
+ if(!i) cout << "After removing middle, iter no longer valid\n";
+ else if(*i != 3) cout << "After removing middle, iter is wrong\n";
+ if(l.count() != 2) cout << "After removing middle, count is wrong\n";
+}
+
+void test_remove_last()
+{
+ ilist l;
+ l.append(1);
+ l.append(2);
+ iiter i(l);
+ i++;
+ l.remove(i);
+ if(i) cout << "After removing last, iter is still valid\n";
+ if(l.count() != 1) cout << "After removing last, count is wrong\n";
+}
+
+int main() {
+ test_remove_first();
+ test_remove_mid();
+ test_remove_last();
+ return 0;
+}
diff --git a/lib/make_defines.sh b/lib/make_defines.sh
new file mode 100644
index 0000000..5be1231
--- /dev/null
+++ b/lib/make_defines.sh
@@ -0,0 +1,9 @@
+#!/bin/sh
+echo "const char* QUEUE_DIR=\"$1/\";" >defines.cc
+echo "const char* QUEUE_TMP_DIR=\"$1/tmp/\";" >>defines.cc
+echo "const char* QUEUE_MSG_DIR=\"$1/queue/\";" >>defines.cc
+echo "const char* QUEUE_TRIGGER=\"$1/trigger\";" >>defines.cc
+echo "const char* CONFIG_DIR=\"$2/\";" >>defines.cc
+echo "const char* PROTOCOL_DIR=\"$3/\";" >>defines.cc
+echo "const char* BIN_DIR=\"$4/\";" >>defines.cc
+echo "const char* SBIN_DIR=\"$5/\";" >>defines.cc
diff --git a/lib/makefield.cc b/lib/makefield.cc
new file mode 100644
index 0000000..750b0d4
--- /dev/null
+++ b/lib/makefield.cc
@@ -0,0 +1,71 @@
+// nullmailer -- a simple relay-only MTA
+// Copyright (C) 1999,2000 Bruce Guenter <bruceg@em.ca>
+//
+// 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
+//
+// You can contact me at <bruceg@em.ca>. There is also a mailing list
+// available to discuss this package. To subscribe, send an email to
+// <nullmailer-subscribe@lists.em.ca>.
+
+#include "config.h"
+#include "defines.h"
+#include <sys/time.h>
+#include <unistd.h>
+#include "itoa.h"
+#include "mystring/mystring.h"
+
+mystring make_date()
+{
+ char buf[256];
+ time_t t = time(0);
+ struct tm* l = localtime(&t);
+ strftime(buf, 256, "%a, %d %b %Y %H:%M:%S ", l);
+#ifdef TM_HAS_GMTOFF
+ long tznum = l->TM_HAS_GMTOFF/60;
+#else
+ long tznum = -timezone/60;
+#if TM_HAS_ISDST
+ int daylight = l->TM_HAS_ISDST;
+#endif // TM_HAS_ISDST
+ if(daylight)
+ tznum += 60;
+#endif // TM_HAS_GMTOFF
+ char tz[6];
+ tz[0] = '+';
+ if(tznum < 0) {
+ tznum = -tznum;
+ tz[0] = '-';
+ }
+ long tzhours = tznum / 60;
+ tz[1] = (tzhours/10)%10 + '0';
+ tz[2] = tzhours%10 + '0';
+ long tzmins = tznum % 60;
+ tz[3] = (tzmins/10)%10 + '0';
+ tz[4] = tzmins%10 + '0';
+ tz[5] = 0;
+ return mystringjoin(buf) + tz;
+}
+
+extern mystring idhost;
+
+// Message ID strings have the form SECONDS.USEC.PID.nullmailer@HOST
+mystring make_messageid()
+{
+ struct timeval tv;
+ gettimeofday(&tv, 0);
+ mystring tmp = mystringjoin("<") + itoa(tv.tv_sec) + ".";
+ tmp = tmp + itoa(tv.tv_usec, 6) + ".";
+ return tmp + itoa(getpid()) + ".nullmailer@" + idhost + ">";
+}
diff --git a/lib/mergelib.sh b/lib/mergelib.sh
new file mode 100644
index 0000000..88dba1a
--- /dev/null
+++ b/lib/mergelib.sh
@@ -0,0 +1,16 @@
+set -e
+archive="$1"
+shift
+tmpdir=".libmerge.$archive.$$.$RANDOM.$USER"
+mkdir "$tmpdir"
+cd "$tmpdir"
+trap 'cd ..; rm -rf "$tmpdir"' EXIT
+for input in "$@"; do
+ dir="`basename "$input"`"
+ mkdir "$dir"
+ cd "$dir"
+ ar x ../../"$input"
+ cd ..
+done
+ar rc ../"$archive" */*
+ranlib ../"$archive"
diff --git a/lib/mystring/ChangeLog b/lib/mystring/ChangeLog
new file mode 100644
index 0000000..458067b
--- /dev/null
+++ b/lib/mystring/ChangeLog
@@ -0,0 +1,116 @@
+2000-04-09 Bruce Guenter <bguenter@bguenter.pointsnorth.com>
+
+ * count.cc (count): Added this routine to count the number of
+ instances of a single character in a string.
+
+2000-04-06 Bruce Guenter <bguenter@bguenter.pointsnorth.com>
+
+ * fdobuf.cc (operator<<): Moved this routine out of an inline
+ declaration.
+
+ * iter.h: Moved the mystring_iter declarations into this file.
+
+ * rep.h: Moved the mystringrep declarations into this file.
+
+ * join.h: Moved the mystringjoin declarations into this file.
+
+ * mystring.h (class mystring): Renamed the "find_first" and
+ "find_last" routines that scan for items in a set to
+ "find_first_of" and "find_last_of".
+
+1999-08-15 Bruce Guenter <bguenter@mikhail.qcc.sk.ca>
+
+ * mystring.h (class mystring_iter): Changed the default seperator
+ for strings to '\0'
+ (class mystring): Added a NUL constant (single 0 byte string).
+
+1999-07-26 Bruce Guenter <bguenter@mikhail.qcc.sk.ca>
+
+ * mystring.h (class mystring_iter): Added this new iterator class,
+ taken from code used in vmailmgr. It is used to iterate over
+ essentially a token-delimited string.
+
+1999-07-14 Bruce Guenter <bguenter@mikhail.qcc.sk.ca>
+
+ * Removed all vestiges of mystringtmp support from this library.
+
+1999-07-13 Bruce Guenter <bguenter@mikhail.qcc.sk.ca>
+
+ * append.cc: Fixed same bug as below in append.
+
+ * assign.cc: Fixed bug in assign and dup where NULL pointers
+ caused a crash.
+
+ * append.cc, assign.cc: removed the mystringtmp versions of the
+ append, assign, and dup operations. mystringtmp now only exists
+ in the cons[2-7].cc files and tmp.cc
+
+ * find.cc: Split this file into find_first, find_first_of,
+ find_last, and find_last_of.
+
+1999-07-12 Bruce Guenter <bguenter@mikhail.qcc.sk.ca>
+
+ * join.cc (traverse): This routine traverses the linked list and
+ builds a mystringrep out of it.
+
+ * mystring.h: Renamed TRACE to MYSTRING_TRACE.
+ Added a new mystringjoin class. This class is used to turn a list
+ of calls to "operator+" into a single constructor by building a
+ linked list on the stack. This will replace mystringtmp.
+
+ * rep.cc (struct _rep_stats): Fixed the percentage function to not
+ do divide-by-zero; modified the "slack" reporting to report a
+ percentage of the requested length.
+
+ * assign.cc: Re-added dup and assign functions for "char*" type,
+ moving the constructors and assignment operators inline.
+
+ * append.cc: Re-added append functions for "char*" type.
+
+1999-07-08 Bruce Guenter <bguenter@mikhail.qcc.sk.ca>
+
+ * mystring.h (class mystring): Eliminated the "mystring" return
+ value for the assign and append operators, since this return value
+ is never used and causes extra operations.
+
+ * operator_plus.cc: Created this new file containing the
+ "operator+" routine.
+
+ * operator_pleq.cc: Created this new file containing all the
+ "operator+=" routines.
+
+ * assign.cc: Created this new file containing all the assign and
+ dup primitives.
+
+ * mystring.h (class mystring): Removed the += operator taking
+ "mystringtmp" parameter, and replaced it with two routines, one
+ for "const mystring&", and one for "const char*". This results in
+ a net code shrinkage.
+
+ * rep.cc (struct _rep_stats): Added this optional statistics
+ gathering class to determine the effectiveness of the slack space
+ and string appending.
+
+ * append.cc (append): Use the new rep->append routine.
+
+ * rep.cc (alloc): Allocate an amount of "slack" space when
+ allocating a string, to allow for later appends.
+ (append): This new routine appends a string to the current rep if
+ and only if the current rep has a single reference and the new
+ length of the string will fit within the current size. If not, it
+ makes a dup of this+str and returns a pointer to it.
+
+1999-06-07 Bruce Guenter <bguenter@mikhail.qcc.sk.ca>
+
+ * tmp.cc: Removed the contents of checkstr, and moved the
+ necessary parts into the constructors. This makes the code more
+ efficient, as the constructors are adequately specific to omit
+ some of the branches in the comparisons. It also ensures that len
+ is always initialized, allowing many of the simple functions to be
+ moved inline to the header file.
+
+1999-04-01 Bruce Guenter <bguenter@mikhail.qcc.sk.ca>
+
+ * cons7.cc (mystring): Wrote this constructor to build a string
+ from 7 inputs.
+
diff --git a/lib/mystring/Makefile.am b/lib/mystring/Makefile.am
new file mode 100644
index 0000000..5b6a0d7
--- /dev/null
+++ b/lib/mystring/Makefile.am
@@ -0,0 +1,25 @@
+noinst_LIBRARIES = libmystring.a
+EXTRA_DIST = ChangeLog iter.h join.h mystring.h rep.h trace.h
+
+INCLUDES = -I..
+
+libmystring_a_SOURCES = \
+ append.cc \
+ assign.cc \
+ count.cc \
+ fdobuf.cc \
+ find_first_ch.cc \
+ find_first_of.cc \
+ find_last_ch.cc \
+ find_last_of.cc \
+ iter.cc \
+ join.cc \
+ lower.cc \
+ lstrip.cc \
+ mystring.cc \
+ rep.cc \
+ rstrip.cc \
+ sub.cc \
+ subst.cc \
+ strip.cc \
+ upper.cc
diff --git a/lib/mystring/Makefile.in b/lib/mystring/Makefile.in
new file mode 100644
index 0000000..0466674
--- /dev/null
+++ b/lib/mystring/Makefile.in
@@ -0,0 +1,310 @@
+# Makefile.in generated automatically by automake 1.4a from Makefile.am
+
+# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DESTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ../..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_FLAG =
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+CC = @CC@
+CXX = @CXX@
+MAKEINFO = @MAKEINFO@
+MKDIR = @MKDIR@
+PACKAGE = @PACKAGE@
+RANLIB = @RANLIB@
+RM = @RM@
+STRIP = @STRIP@
+VERSION = @VERSION@
+
+noinst_LIBRARIES = libmystring.a
+EXTRA_DIST = ChangeLog iter.h join.h mystring.h rep.h trace.h
+
+INCLUDES = -I..
+
+libmystring_a_SOURCES = append.cc assign.cc count.cc fdobuf.cc find_first_ch.cc find_first_of.cc find_last_ch.cc find_last_of.cc iter.cc join.cc lower.cc lstrip.cc mystring.cc rep.cc rstrip.cc sub.cc subst.cc strip.cc upper.cc
+
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = ../../config.h
+CONFIG_CLEAN_FILES =
+LIBRARIES = $(noinst_LIBRARIES)
+
+
+DEFS = @DEFS@ -I. -I$(srcdir) -I../..
+CPPFLAGS = @CPPFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+libmystring_a_LIBADD =
+libmystring_a_OBJECTS = append.o assign.o count.o fdobuf.o \
+find_first_ch.o find_first_of.o find_last_ch.o find_last_of.o iter.o \
+join.o lower.o lstrip.o mystring.o rep.o rstrip.o sub.o subst.o strip.o \
+upper.o
+AR = ar
+CXXFLAGS = @CXXFLAGS@
+CXXCOMPILE = $(CXX) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+CXXLD = $(CXX)
+CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(LDFLAGS) -o $@
+DIST_COMMON = ChangeLog Makefile.am Makefile.in
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = gtar
+GZIP_ENV = --best
+SOURCES = $(libmystring_a_SOURCES)
+OBJECTS = $(libmystring_a_OBJECTS)
+
+all: all-redirect
+.SUFFIXES:
+.SUFFIXES: .S .c .cc .o .s
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
+ cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps lib/mystring/Makefile
+
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ cd $(top_builddir) \
+ && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+
+mostlyclean-noinstLIBRARIES:
+
+clean-noinstLIBRARIES:
+ -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
+
+distclean-noinstLIBRARIES:
+
+maintainer-clean-noinstLIBRARIES:
+
+.c.o:
+ $(COMPILE) -c $<
+
+.s.o:
+ $(COMPILE) -c $<
+
+.S.o:
+ $(COMPILE) -c $<
+
+mostlyclean-compile:
+ -rm -f *.o core *.core
+
+clean-compile:
+
+distclean-compile:
+ -rm -f *.tab.c
+
+maintainer-clean-compile:
+
+libmystring.a: $(libmystring_a_OBJECTS) $(libmystring_a_DEPENDENCIES)
+ -rm -f libmystring.a
+ $(AR) cru libmystring.a $(libmystring_a_OBJECTS) $(libmystring_a_LIBADD)
+ $(RANLIB) libmystring.a
+.cc.o:
+ $(CXXCOMPILE) -c $<
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP)
+ list='$(SOURCES) $(HEADERS)'; \
+ unique=`for i in $$list; do echo $$i; done | \
+ awk ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ here=`pwd` && cd $(srcdir) \
+ && mkid -f$$here/ID $$unique $(LISP)
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS)'; \
+ unique=`for i in $$list; do echo $$i; done | \
+ awk ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
+ || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS)
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+ -rm -f TAGS ID
+
+maintainer-clean-tags:
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = lib/mystring
+
+distdir: $(DISTFILES)
+ @for file in $(DISTFILES); do \
+ d=$(srcdir); \
+ if test -d $$d/$$file; then \
+ cp -pr $$d/$$file $(distdir)/$$file; \
+ else \
+ test -f $(distdir)/$$file \
+ || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+ || cp -p $$d/$$file $(distdir)/$$file || :; \
+ fi; \
+ done
+append.o: append.cc mystring.h ../mystring/rep.h ../mystring/iter.h \
+ ../mystring/join.h trace.h
+assign.o: assign.cc mystring.h ../mystring/rep.h ../mystring/iter.h \
+ ../mystring/join.h trace.h
+count.o: count.cc mystring.h ../mystring/rep.h ../mystring/iter.h \
+ ../mystring/join.h
+fdobuf.o: fdobuf.cc mystring.h ../mystring/rep.h ../mystring/iter.h \
+ ../mystring/join.h ../fdbuf/fdbuf.h ../../config.h \
+ ../fdbuf/fdibuf.h ../fdbuf/fdobuf.h
+find_first_ch.o: find_first_ch.cc mystring.h ../mystring/rep.h \
+ ../mystring/iter.h ../mystring/join.h
+find_first_of.o: find_first_of.cc mystring.h ../mystring/rep.h \
+ ../mystring/iter.h ../mystring/join.h
+find_last_ch.o: find_last_ch.cc mystring.h ../mystring/rep.h \
+ ../mystring/iter.h ../mystring/join.h
+find_last_of.o: find_last_of.cc mystring.h ../mystring/rep.h \
+ ../mystring/iter.h ../mystring/join.h
+iter.o: iter.cc mystring.h ../mystring/rep.h ../mystring/iter.h \
+ ../mystring/join.h
+join.o: join.cc mystring.h ../mystring/rep.h ../mystring/iter.h \
+ ../mystring/join.h
+lower.o: lower.cc mystring.h ../mystring/rep.h ../mystring/iter.h \
+ ../mystring/join.h
+lstrip.o: lstrip.cc mystring.h ../mystring/rep.h ../mystring/iter.h \
+ ../mystring/join.h
+mystring.o: mystring.cc mystring.h ../mystring/rep.h ../mystring/iter.h \
+ ../mystring/join.h trace.h
+rep.o: rep.cc mystring.h ../mystring/rep.h ../mystring/iter.h \
+ ../mystring/join.h trace.h
+rstrip.o: rstrip.cc mystring.h ../mystring/rep.h ../mystring/iter.h \
+ ../mystring/join.h
+strip.o: strip.cc mystring.h ../mystring/rep.h ../mystring/iter.h \
+ ../mystring/join.h
+sub.o: sub.cc mystring.h ../mystring/rep.h ../mystring/iter.h \
+ ../mystring/join.h
+subst.o: subst.cc mystring.h ../mystring/rep.h ../mystring/iter.h \
+ ../mystring/join.h
+upper.o: upper.cc mystring.h ../mystring/rep.h ../mystring/iter.h \
+ ../mystring/join.h
+
+info-am:
+info: info-am
+dvi-am:
+dvi: dvi-am
+check-am: all-am
+check: check-am
+installcheck-am:
+installcheck: installcheck-am
+install-exec-am:
+install-exec: install-exec-am
+
+install-data-am:
+install-data: install-data-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-am
+uninstall-am:
+uninstall: uninstall-am
+all-am: Makefile $(LIBRARIES)
+all-redirect: all-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_STRIP_FLAG=-s install
+installdirs:
+
+
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -rm -f Makefile $(CONFIG_CLEAN_FILES)
+ -rm -f config.cache config.log stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+mostlyclean-am: mostlyclean-noinstLIBRARIES mostlyclean-compile \
+ mostlyclean-tags mostlyclean-generic
+
+mostlyclean: mostlyclean-am
+
+clean-am: clean-noinstLIBRARIES clean-compile clean-tags clean-generic \
+ mostlyclean-am
+
+clean: clean-am
+
+distclean-am: distclean-noinstLIBRARIES distclean-compile \
+ distclean-tags distclean-generic clean-am
+
+distclean: distclean-am
+
+maintainer-clean-am: maintainer-clean-noinstLIBRARIES \
+ maintainer-clean-compile maintainer-clean-tags \
+ maintainer-clean-generic distclean-am
+ @echo "This command is intended for maintainers to use;"
+ @echo "it deletes files that may require special tools to rebuild."
+
+maintainer-clean: maintainer-clean-am
+
+.PHONY: mostlyclean-noinstLIBRARIES distclean-noinstLIBRARIES \
+clean-noinstLIBRARIES maintainer-clean-noinstLIBRARIES \
+mostlyclean-compile distclean-compile clean-compile \
+maintainer-clean-compile tags mostlyclean-tags distclean-tags \
+clean-tags maintainer-clean-tags distdir info-am info dvi-am dvi check \
+check-am installcheck-am installcheck install-exec-am install-exec \
+install-data-am install-data install-am install uninstall-am uninstall \
+all-redirect all-am all installdirs mostlyclean-generic \
+distclean-generic clean-generic maintainer-clean-generic clean \
+mostlyclean distclean maintainer-clean
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/lib/mystring/append.cc b/lib/mystring/append.cc
new file mode 100644
index 0000000..d0120a5
--- /dev/null
+++ b/lib/mystring/append.cc
@@ -0,0 +1,19 @@
+#include <string.h>
+#include "mystring.h"
+#include "trace.h"
+
+void mystring::append(const char* str, size_t len)
+{
+ if(!str || !len)
+ return;
+ if(!*this)
+ assign(str, len);
+ else
+ rep = rep->append(str, len);
+}
+
+void mystring::append(const char* in)
+{
+ if(in)
+ append(in, strlen(in));
+}
diff --git a/lib/mystring/assign.cc b/lib/mystring/assign.cc
new file mode 100644
index 0000000..5a7b6a7
--- /dev/null
+++ b/lib/mystring/assign.cc
@@ -0,0 +1,55 @@
+#include "mystring.h"
+#include "trace.h"
+#include <ctype.h>
+#include <string.h>
+
+void mystring::dupnil()
+{
+ trace("");
+ rep = &nil;
+ rep->attach();
+}
+
+void mystring::assign(const char* in)
+{
+ if(in)
+ assign(in, strlen(in));
+ else {
+ mystringrep* tmp = rep;
+ dupnil();
+ tmp->detach();
+ }
+}
+
+void mystring::assign(const char* in, size_t len)
+{
+ trace("in='" << in << "'");
+ if(in != rep->buf) {
+ mystringrep* tmp = rep;
+ dup(in, len);
+ tmp->detach();
+ }
+}
+
+void mystring::dup(const char* in, size_t len)
+{
+ trace("in='" << in << "'");
+ rep = mystringrep::dup(in, len);
+ rep->attach();
+}
+
+void mystring::dup(const char* in)
+{
+ if(in)
+ dup(in, strlen(in));
+ else
+ dupnil();
+}
+
+void mystring::operator=(const mystringjoin& in)
+{
+ mystringrep* tmp = rep;
+ rep = in.traverse();
+ rep->attach();
+ tmp->detach();
+}
diff --git a/lib/mystring/count.cc b/lib/mystring/count.cc
new file mode 100644
index 0000000..7837375
--- /dev/null
+++ b/lib/mystring/count.cc
@@ -0,0 +1,25 @@
+// Copyright (C) 1999,2000 Bruce Guenter <bruceg@em.ca>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+#include "mystring.h"
+
+unsigned mystring::count(char ch) const
+{
+ unsigned c = 0;
+ for(int pos = find_first(ch); pos > 0; pos = find_first(ch, pos+1))
+ ++c;
+ return c;
+}
diff --git a/lib/mystring/fdobuf.cc b/lib/mystring/fdobuf.cc
new file mode 100644
index 0000000..ff967e6
--- /dev/null
+++ b/lib/mystring/fdobuf.cc
@@ -0,0 +1,9 @@
+#include "mystring.h"
+#include "fdbuf/fdbuf.h"
+
+fdobuf& operator<<(fdobuf& out, const mystring& str)
+{
+ out.write(str.c_str(), str.length());
+ return out;
+}
+
diff --git a/lib/mystring/find_first_ch.cc b/lib/mystring/find_first_ch.cc
new file mode 100644
index 0000000..0a652d0
--- /dev/null
+++ b/lib/mystring/find_first_ch.cc
@@ -0,0 +1,11 @@
+#include "mystring.h"
+#include <string.h>
+
+int mystring::find_first(char ch, size_t offset) const
+{
+ if(offset >= rep->length)
+ return -1;
+ char* ptr = strchr(rep->buf+offset, ch);
+ return ptr ? ptr-rep->buf : -1;
+}
+
diff --git a/lib/mystring/find_first_of.cc b/lib/mystring/find_first_of.cc
new file mode 100644
index 0000000..f23e7f4
--- /dev/null
+++ b/lib/mystring/find_first_of.cc
@@ -0,0 +1,22 @@
+#include "mystring.h"
+#include <string.h>
+
+int mystring::find_first_of(const char* setstr, size_t setlen,
+ size_t offset) const
+{
+ for(; offset < rep->length; offset++) {
+ if(memchr(setstr, rep->buf[offset], setlen))
+ return offset;
+ }
+ return -1;
+}
+
+int mystring::find_first_of(const char* setstr, size_t offset) const
+{
+ return find_first_of(setstr, strlen(setstr), offset);
+}
+
+int mystring::find_first_of(const mystring& setstr, size_t offset) const
+{
+ return find_first_of(setstr.rep->buf, setstr.rep->length, offset);
+}
diff --git a/lib/mystring/find_last_ch.cc b/lib/mystring/find_last_ch.cc
new file mode 100644
index 0000000..20d620a
--- /dev/null
+++ b/lib/mystring/find_last_ch.cc
@@ -0,0 +1,14 @@
+#include "mystring.h"
+
+int mystring::find_last(char ch, size_t offset) const
+{
+ if(offset == (size_t)-1)
+ offset = rep->length-1;
+ const char* ptr = rep->buf + offset;
+ while(ptr >= rep->buf) {
+ if(*ptr == ch)
+ return ptr - rep->buf;
+ --ptr;
+ }
+ return -1;
+}
diff --git a/lib/mystring/find_last_of.cc b/lib/mystring/find_last_of.cc
new file mode 100644
index 0000000..b8f8831
--- /dev/null
+++ b/lib/mystring/find_last_of.cc
@@ -0,0 +1,24 @@
+#include "mystring.h"
+#include <string.h>
+
+int mystring::find_last_of(const char* setstr, size_t setlen,
+ size_t offset) const
+{
+ if(offset == (size_t)-1)
+ offset = rep->length-1;
+ for(int i = offset; i >= 0; --i) {
+ if(memchr(setstr, rep->buf[i], setlen))
+ return i;
+ }
+ return -1;
+}
+
+int mystring::find_last_of(const char* setstr, size_t offset) const
+{
+ return find_last_of(setstr, strlen(setstr), offset);
+}
+
+int mystring::find_last_of(const mystring& setstr, size_t offset) const
+{
+ return find_last_of(setstr.rep->buf, setstr.rep->length, offset);
+}
diff --git a/lib/mystring/iter.cc b/lib/mystring/iter.cc
new file mode 100644
index 0000000..8ef122a
--- /dev/null
+++ b/lib/mystring/iter.cc
@@ -0,0 +1,48 @@
+// Copyright (C) 1999,2000 Bruce Guenter <bruceg@em.ca>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+#include "mystring.h"
+
+mystring_iter::mystring_iter(const mystring& s, char e)
+ : str(s), sep(e), pos(0)
+{
+ advance();
+}
+
+mystring_iter::~mystring_iter()
+{
+}
+
+void mystring_iter::advance()
+{
+ if(pos == -1)
+ return;
+ int i = str.find_first(sep, pos);
+ if(i == -1) {
+ if(pos >= 0 && pos < (int)str.length()) {
+ part = str.right(pos);
+ pos = str.length();
+ }
+ else {
+ part = "";
+ pos = -1;
+ }
+ }
+ else {
+ part = str.sub(pos, i-pos);
+ pos = i + 1;
+ }
+}
diff --git a/lib/mystring/iter.h b/lib/mystring/iter.h
new file mode 100644
index 0000000..e23bdf3
--- /dev/null
+++ b/lib/mystring/iter.h
@@ -0,0 +1,38 @@
+// Copyright (C) 1999,2000 Bruce Guenter <bruceg@em.ca>
+//
+// 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
+
+#ifndef MYSTRING__ITER__H__
+#define MYSTRING__ITER__H__
+
+class mystring_iter
+{
+ const mystring str;
+ const char sep;
+ int pos;
+ mystring part;
+
+ void advance();
+public:
+ mystring_iter(const mystring&, char = '\0');
+ ~mystring_iter();
+
+ operator bool() const { return pos >= 0; }
+ bool operator!() const { return pos < 0; }
+ mystring operator*() const { return part; }
+ void operator++() { advance(); }
+};
+
+#endif
diff --git a/lib/mystring/join.cc b/lib/mystring/join.cc
new file mode 100644
index 0000000..435765f
--- /dev/null
+++ b/lib/mystring/join.cc
@@ -0,0 +1,61 @@
+#include "mystring.h"
+#include <string.h>
+
+// This "join" class relies on one fairly obscure detail in the C++
+// standard: temporaries are destructed only after the entire
+// "full-expression" has completed. That is, if the sequence:
+// f(f(f(x))) creates three temporary objects, the inner objects are
+// destroyed only after the execution has completed. This allows us
+// to build a complete linked-list on the stack. Tricky, but efficient!
+
+struct tmpitem
+{
+ const char* str;
+ unsigned len;
+};
+
+mystringrep* mystringjoin::traverse() const
+{
+ // At first glance, a recursive implementation would be the most logical
+ // way of doing this, but it turned out to be a significant loss. This
+ // method traverses the pointer chain to first determine the length, and
+ // then to do the actual copying.
+
+ // Note the use of do/while loops to avoid a test at the head of the loop
+ // which will always succeed (there is always at least one node or item).
+ unsigned count = 0;
+ const mystringjoin* node = this;
+ do {
+ ++count;
+ } while((node = node->prev) != 0);
+
+ // The use of a temporary array avoids re-traversing the pointer
+ // chain, which is a slight performance win.
+ tmpitem items[count];
+
+ unsigned length = 0;
+ node = this;
+ tmpitem* item = items;
+ do {
+ unsigned l = node->rep ? node->rep->length : strlen(node->str);
+ length += l;
+ item->str = node->str;
+ item->len = l;
+ ++item;
+ } while((node = node->prev) != 0);
+
+ // Since the chain is constructed such that the last item is the
+ // first node, the string gets constructed in reverse order.
+ mystringrep* rep = mystringrep::alloc(length);
+ char* buf = rep->buf + length;
+ item = items;
+ do {
+ unsigned l = item->len;
+ buf -= l;
+ memcpy(buf, item->str, l);
+ ++item;
+ } while(--count != 0);
+
+ rep->buf[length] = 0;
+ return rep;
+}
diff --git a/lib/mystring/join.h b/lib/mystring/join.h
new file mode 100644
index 0000000..eae8962
--- /dev/null
+++ b/lib/mystring/join.h
@@ -0,0 +1,75 @@
+// Copyright (C) 1999,2000 Bruce Guenter <bruceg@em.ca>
+//
+// 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
+
+#ifndef MYSTRING__JOIN__H__
+#define MYSTRING__JOIN__H__
+
+class mystringjoin
+{
+private:
+ const mystringjoin* prev;
+ mystringrep* rep;
+ const char* str;
+
+ mystringjoin();
+public:
+ mystringjoin(const mystringjoin& j)
+ : prev(j.prev), rep(j.rep), str(j.str)
+ {
+ rep->attach();
+ }
+ mystringjoin(const mystring& s)
+ : prev(0), rep(s.rep), str(s.rep->buf)
+ {
+ rep->attach();
+ }
+ mystringjoin(const char* s)
+ : prev(0), rep(0), str(s)
+ {
+ }
+ mystringjoin(const mystringjoin& p, const mystring& s)
+ : prev(&p), rep(s.rep), str(s.rep->buf)
+ {
+ rep->attach();
+ }
+ mystringjoin(const mystringjoin& p, const char* s)
+ : prev(&p), rep(0), str(s)
+ {
+ }
+ ~mystringjoin()
+ {
+ if(rep) rep->detach();
+ }
+ mystringrep* traverse() const;
+};
+
+inline mystring::mystring(const mystringjoin& j)
+ : rep(j.traverse())
+{
+ rep->attach();
+}
+
+inline mystringjoin operator+(const mystringjoin& a, const mystring& b)
+{
+ return mystringjoin(a, b);
+}
+
+inline mystringjoin operator+(const mystringjoin& a, const char* b)
+{
+ return mystringjoin(a, b);
+}
+
+#endif
diff --git a/lib/mystring/lower.cc b/lib/mystring/lower.cc
new file mode 100644
index 0000000..b51b51d
--- /dev/null
+++ b/lib/mystring/lower.cc
@@ -0,0 +1,19 @@
+#include "mystring.h"
+#include <ctype.h>
+
+mystring mystring::lower() const
+{
+ const unsigned length = rep->length;
+ char buf[length+1];
+ const char* in = rep->buf + length;
+ bool changed = false;
+ for(char* out = buf+length; out >= buf; in--, out--)
+ if(isupper(*in))
+ *out = tolower(*in), changed = true;
+ else
+ *out = *in;
+ if(!changed)
+ return *this;
+ else
+ return mystring(buf, length);
+}
diff --git a/lib/mystring/lstrip.cc b/lib/mystring/lstrip.cc
new file mode 100644
index 0000000..66ee2d0
--- /dev/null
+++ b/lib/mystring/lstrip.cc
@@ -0,0 +1,10 @@
+#include "mystring.h"
+#include <ctype.h>
+
+mystring mystring::lstrip() const
+{
+ const char* ptr = rep->buf;
+ while(*ptr && isspace(*ptr))
+ ++ptr;
+ return ptr;
+}
diff --git a/lib/mystring/mystring.cc b/lib/mystring/mystring.cc
new file mode 100644
index 0000000..c04bf2f
--- /dev/null
+++ b/lib/mystring/mystring.cc
@@ -0,0 +1,28 @@
+#include "mystring.h"
+#include "trace.h"
+#include <ctype.h>
+#include <string.h>
+
+#ifdef MYSTRING_TRACE
+mystring::~mystring()
+{
+ trace("rep=" << (void*)rep);
+ rep->detach();
+}
+#endif
+
+int mystring::operator!=(const char* in) const
+{
+ if(rep->buf == in)
+ return 0;
+ return strcmp(rep->buf, in);
+}
+
+int mystring::operator!=(const mystring& in) const
+{
+ if(rep->buf == in.rep->buf)
+ return 0;
+ return strcmp(rep->buf, in.rep->buf);
+}
+
+const mystring mystring::NUL("", 1);
diff --git a/lib/mystring/mystring.h b/lib/mystring/mystring.h
new file mode 100644
index 0000000..85c7bfb
--- /dev/null
+++ b/lib/mystring/mystring.h
@@ -0,0 +1,125 @@
+// Copyright (C) 1999,2000 Bruce Guenter <bruceg@em.ca>
+//
+// 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
+
+#ifndef MYSTRING__H__
+#define MYSTRING__H__
+
+#include <sys/types.h>
+#include "mystring/rep.h"
+
+class mystringjoin;
+class mystring
+{
+ friend class mystringtmp;
+ friend class mystringjoin;
+private:
+ mystringrep* rep;
+
+protected:
+ void dupnil();
+ void dup(const char*, size_t);
+ void dup(const char*);
+ void append(const char*);
+ void append(const char*, size_t);
+ void assign(const char*);
+ void assign(const char*, size_t);
+public:
+ static const mystring NUL;
+
+ mystring() { dupnil(); }
+ mystring(const char* s) { dup(s); }
+ mystring(const mystring& s) { dup(s.rep->buf, s.rep->length); }
+ mystring(const char* str, size_t len) { dup(str, len); }
+ mystring(const mystringjoin&);
+ ~mystring();
+
+ const char* c_str() const { return rep->buf; }
+
+ bool operator!() const { return empty(); }
+
+ char operator[](size_t i) const { return rep->buf[i]; }
+
+ size_t length() const { return rep->length; }
+
+ bool empty() const { return rep->length == 0; }
+
+ int operator!=(const char* in) const;
+ int operator!=(const mystring& in) const;
+ bool operator==(const char* in) const
+ {
+ return !operator!=(in);
+ }
+ bool operator==(const mystring& in) const
+ {
+ return !operator!=(in);
+ }
+
+ void operator=(const char* in) { assign(in); }
+ void operator=(const mystring& in) { assign(in.rep->buf, in.rep->length); }
+ void operator=(const mystringjoin& in);
+
+ mystring subst(char from, char to) const;
+
+ mystring lower() const;
+ mystring upper() const;
+
+ int find_first(char, size_t = 0) const;
+ int find_first_of(const mystring&, size_t = 0) const;
+ int find_first_of(const char*, size_t = 0) const;
+ int find_first_of(const char*, size_t, size_t) const;
+
+ int find_last(char, size_t = (size_t)-1) const;
+ int find_last_of(const mystring&, size_t = (size_t)-1) const;
+ int find_last_of(const char*, size_t = 0) const;
+ int find_last_of(const char*, size_t, size_t) const;
+
+ mystring left(size_t) const;
+ mystring right(size_t) const;
+ mystring sub(size_t, size_t) const;
+
+ mystring lstrip() const;
+ mystring rstrip() const;
+ mystring strip() const;
+
+ unsigned count(char ch) const;
+
+ void operator+=(const mystring& str) {append(str.rep->buf, str.rep->length);}
+ void operator+=(const char* str) { append(str); }
+ void operator+=(char ch)
+ {
+ char str[2] = { ch, 0 };
+ append(str, 1);
+ }
+};
+
+#ifndef MYSTRING_TRACE
+inline mystring::~mystring()
+{
+ rep->detach();
+}
+#endif
+
+#include "mystring/iter.h"
+#include "mystring/join.h"
+
+class fdobuf;
+fdobuf& operator<<(fdobuf& out, const mystring& str);
+
+//istream& operator>>(istream& in, mystring& str);
+
+typedef mystring string;
+
+#endif
diff --git a/lib/mystring/rep.cc b/lib/mystring/rep.cc
new file mode 100644
index 0000000..bc939d7
--- /dev/null
+++ b/lib/mystring/rep.cc
@@ -0,0 +1,157 @@
+#include "mystring.h"
+#include "trace.h"
+#include <ctype.h>
+#include <string.h>
+
+mystringrep nil = { 0, 1, 1, "" };
+
+static const unsigned replength = sizeof(unsigned)*3;
+
+static const unsigned sizestep = sizeof(unsigned);
+static const unsigned slackdiv = 4;
+static const unsigned slackmax = 16;
+
+#ifdef MYSTRINGREP_STATS
+
+#include "fdbuf.h"
+
+struct _rep_stats
+{
+ unsigned allocs;
+ unsigned alloc_size;
+ unsigned alloc_len;
+
+ unsigned appends;
+ unsigned appends_dup;
+
+ _rep_stats()
+ : allocs(0)
+ {
+ }
+
+ void stat(const char* name, unsigned value)
+ {
+ ferr << "mystringrep: " << name << ": " << value << '\n';
+ }
+ void pcnt(const char* name, unsigned denom, unsigned divis)
+ {
+ ferr << "mystringrep: " << name << ": "
+ << denom << '/' << divis << '=';
+ if(divis) ferr << denom * 100 / divis << '%';
+ else ferr << "N/A";
+ ferr << '\n';
+ }
+
+ ~_rep_stats()
+ {
+ stat(" size step", sizestep);
+ stat(" slack divisor", slackdiv);
+ stat(" slack maximum", slackmax);
+ stat(" allocs", allocs);
+ stat(" alloc length", alloc_len);
+ stat(" alloc size", alloc_size);
+ pcnt(" alloc slack", alloc_size-alloc_len, alloc_len);
+ stat("alloc overhead", allocs*replength);
+ pcnt(" appends->dup", appends_dup, appends);
+ }
+};
+
+static _rep_stats stats;
+
+#define ACCOUNT(NAME,VALUE) stats. NAME += VALUE
+
+#else // MYSTRINGREP_STATS
+
+#define ACCOUNT(NAME,VALUE)
+
+#endif // MYSTRINGREP_STATS
+
+///////////////////////////////////////////////////////////////////////////////
+// class mystringrep
+///////////////////////////////////////////////////////////////////////////////
+mystringrep* mystringrep::alloc(unsigned length)
+{
+ ACCOUNT(allocs, 1);
+ trace_static("length=" << length);
+ if(length == 0)
+ return &nil;
+
+ ACCOUNT(alloc_len, length);
+ unsigned slack = length / slackdiv;
+ if(slack > slackmax)
+ slack = slackmax;
+ unsigned size = length+1 + sizestep-1 + slack;
+ size = size - size % sizestep;
+ ACCOUNT(alloc_size, size);
+
+ mystringrep* ptr = (mystringrep*)new char[size+replength];
+ ptr->length = length;
+ ptr->references = 0;
+ ptr->size = size;
+ return ptr;
+}
+
+mystringrep* mystringrep::dup(const char* str, unsigned length)
+{
+ trace_static("str=" << (void*)str << " length=" << length);
+ if(length == 0)
+ return &nil;
+ mystringrep* ptr = alloc(length);
+ memcpy(ptr->buf, str, length);
+ ptr->buf[length] = 0;
+ return ptr;
+}
+
+mystringrep* mystringrep::dup(const char* str1, unsigned length1,
+ const char* str2, unsigned length2)
+{
+ trace_static("");
+ if(length1+length2 == 0)
+ return &nil;
+ mystringrep* ptr = alloc(length1+length2);
+ memcpy(ptr->buf, str1, length1);
+ memcpy(ptr->buf+length1, str2, length2);
+ ptr->buf[length1+length2] = 0;
+ return ptr;
+}
+
+mystringrep* mystringrep::append(const char* str, unsigned len)
+{
+ ACCOUNT(appends, 1);
+ unsigned newlen = length + len;
+ // If there are more than one references, always make a duplicate
+ // Also, if this does not have enough space to add the new string, dup it
+ if(references > 1 || newlen >= size) {
+ ACCOUNT(appends_dup, 1);
+ mystringrep* tmp = dup(buf, length, str, len);
+ tmp->attach();
+ detach();
+ return tmp;
+ }
+ // Otherwise, just add the new string to the end of this
+ else {
+ memcpy(buf+length, str, len);
+ buf[newlen] = 0;
+ length = newlen;
+ return this;
+ }
+}
+
+#ifdef MYSTRING_TRACE
+void mystringrep::attach()
+{
+ trace("references=" << references);
+ ++references;
+}
+#endif
+
+void mystringrep::detach()
+{
+ trace("references=" << references);
+
+ --references;
+ if(!references) {
+ trace("deleting this");
+ delete this;
+ }
+}
diff --git a/lib/mystring/rep.h b/lib/mystring/rep.h
new file mode 100644
index 0000000..c397aee
--- /dev/null
+++ b/lib/mystring/rep.h
@@ -0,0 +1,46 @@
+// Copyright (C) 1999,2000 Bruce Guenter <bruceg@em.ca>
+//
+// 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
+
+#ifndef MYSTRING__REP__H__
+#define MYSTRING__REP__H__
+
+struct mystringrep
+{
+ unsigned length;
+ unsigned references;
+ unsigned size;
+ char buf[1];
+
+ void attach();
+ void detach();
+ mystringrep* append(const char*, unsigned);
+
+ static mystringrep* alloc(unsigned);
+ static mystringrep* dup(const char*, unsigned);
+ static mystringrep* dup(const char*, unsigned,
+ const char*, unsigned);
+};
+
+#ifndef MYSTRING_TRACE
+inline void mystringrep::attach()
+{
+ references++;
+}
+#endif
+
+extern mystringrep nil;
+
+#endif
diff --git a/lib/mystring/rstrip.cc b/lib/mystring/rstrip.cc
new file mode 100644
index 0000000..b66f8ce
--- /dev/null
+++ b/lib/mystring/rstrip.cc
@@ -0,0 +1,10 @@
+#include "mystring.h"
+#include <ctype.h>
+
+mystring mystring::rstrip() const
+{
+ const char* ptr = rep->buf + rep->length - 1;
+ while(ptr >= rep->buf && isspace(*ptr))
+ --ptr;
+ return mystring(rep->buf, ptr-rep->buf+1);
+}
diff --git a/lib/mystring/strip.cc b/lib/mystring/strip.cc
new file mode 100644
index 0000000..7ee251f
--- /dev/null
+++ b/lib/mystring/strip.cc
@@ -0,0 +1,13 @@
+#include "mystring.h"
+#include <ctype.h>
+
+mystring mystring::strip() const
+{
+ const char* start = rep->buf;
+ while(*start && isspace(*start))
+ ++start;
+ const char* end = rep->buf + rep->length - 1;
+ while(end >= start && isspace(*end))
+ --end;
+ return mystring(start, end-start+1);
+}
diff --git a/lib/mystring/sub.cc b/lib/mystring/sub.cc
new file mode 100644
index 0000000..c0918db
--- /dev/null
+++ b/lib/mystring/sub.cc
@@ -0,0 +1,37 @@
+#include "mystring.h"
+
+// return the sub-string ending at 'offset'
+mystring mystring::left(size_t offset) const
+{
+ if(offset > rep->length)
+ return *this;
+ else
+ return mystring(rep->buf, offset);
+}
+
+// return the sub-string starting at 'offset'
+mystring mystring::right(size_t offset) const
+{
+ if(offset >= rep->length)
+ return mystring();
+ else if(offset == 0)
+ return *this;
+ else
+ return mystring(rep->buf+offset, rep->length-offset);
+}
+
+// return the 'len' characters of the string starting at 'offset'
+mystring mystring::sub(size_t offset, size_t len) const
+{
+ // return right(offset).left(len);
+ if(len == 0)
+ return mystring();
+ else if(offset == 0 && len >= rep->length)
+ return *this;
+ else {
+ if(len+offset >= rep->length)
+ len = rep->length - offset;
+ return mystring(rep->buf+offset, len);
+ }
+}
+
diff --git a/lib/mystring/subst.cc b/lib/mystring/subst.cc
new file mode 100644
index 0000000..f5172cc
--- /dev/null
+++ b/lib/mystring/subst.cc
@@ -0,0 +1,18 @@
+#include "mystring.h"
+
+mystring mystring::subst(char from, char to) const
+{
+ const unsigned length = rep->length;
+ char buf[length+1];
+ const char* in = rep->buf + length;
+ bool changed = true;
+ for(char* out = buf+length; out >= buf; in--, out--)
+ if(*in == from)
+ *out = to, changed = true;
+ else
+ *out = *in;
+ if(!changed)
+ return *this;
+ else
+ return mystring(buf, length);
+}
diff --git a/lib/mystring/trace.h b/lib/mystring/trace.h
new file mode 100644
index 0000000..f5ef879
--- /dev/null
+++ b/lib/mystring/trace.h
@@ -0,0 +1,10 @@
+#include "mystring.h"
+
+#ifdef MYSTRING_TRACE
+ostream& operator<<(ostream& out, const mystringtmp& s);
+#define trace(X) cerr << (void*)this << "->" << __PRETTY_FUNCTION__ << X << endl
+#define trace_static(X) cerr << __PRETTY_FUNCTION__ << X << endl
+#else
+#define trace(X) do { } while(0)
+#define trace_static(X) do { } while(0)
+#endif
diff --git a/lib/mystring/upper.cc b/lib/mystring/upper.cc
new file mode 100644
index 0000000..0e7ca5b
--- /dev/null
+++ b/lib/mystring/upper.cc
@@ -0,0 +1,21 @@
+#include "mystring.h"
+#include <ctype.h>
+
+mystring mystring::upper() const
+{
+ const unsigned length = rep->length;
+ char buf[length+1];
+ const char* in = rep->buf + length;
+ bool changed = false;
+ for(char* out = buf+length; out >= buf; in--, out--)
+ if(isupper(*in)) {
+ *out = tolower(*in);
+ changed = true;
+ }
+ else
+ *out = *in;
+ if(!changed)
+ return *this;
+ else
+ return mystring(buf, length);
+}
diff --git a/lib/netstring.cc b/lib/netstring.cc
new file mode 100644
index 0000000..784d941
--- /dev/null
+++ b/lib/netstring.cc
@@ -0,0 +1,13 @@
+#include "config.h"
+#include "netstring.h"
+#include "itoa.h"
+
+mystring str2net(const mystring& s)
+{
+ return mystringjoin(itoa(s.length())) + ":" + s + ",";
+}
+
+mystring strnl2net(const mystring& s)
+{
+ return mystringjoin(itoa(s.length()+1)) + ":" + s + "\012,";
+}
diff --git a/lib/netstring.h b/lib/netstring.h
new file mode 100644
index 0000000..d5a1a19
--- /dev/null
+++ b/lib/netstring.h
@@ -0,0 +1,8 @@
+#ifndef NULLMAILER__NETSTRING__H__
+#define NULLMAILER__NETSTRING__H__
+
+#include "mystring/mystring.h"
+mystring str2net(const mystring&);
+mystring strnl2net(const mystring&);
+
+#endif // NULLMAILER__NETSTRING__H__
diff --git a/lib/tcpconnect.cc b/lib/tcpconnect.cc
new file mode 100644
index 0000000..f364648
--- /dev/null
+++ b/lib/tcpconnect.cc
@@ -0,0 +1,68 @@
+// nullmailer -- a simple relay-only MTA
+// Copyright (C) 1999,2000 Bruce Guenter <bruceg@em.ca>
+//
+// 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
+//
+// You can contact me at <bruceg@em.ca>. There is also a mailing list
+// available to discuss this package. To subscribe, send an email to
+// <nullmailer-subscribe@lists.em.ca>.
+
+#include "config.h"
+#include <errno.h>
+#include <netdb.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include "errcodes.h"
+#include "connect.h"
+
+static int sethostbyname(const mystring& hostname, struct sockaddr_in& sa)
+{
+ struct hostent *he = gethostbyname(hostname.c_str());
+ if(!he) {
+ switch(h_errno) {
+ case HOST_NOT_FOUND: return -ERR_HOST_NOT_FOUND;
+ case NO_ADDRESS: return -ERR_NO_ADDRESS;
+ case NO_RECOVERY: return -ERR_GHBN_FATAL;
+ case TRY_AGAIN: return -ERR_GHBN_TEMP;
+ default: return -ERR_GHBN_TEMP;
+ }
+ }
+ memcpy(&sa.sin_addr, he->h_addr, he->h_length);
+ return 0;
+}
+
+int tcpconnect(const mystring& hostname, int port)
+{
+ struct sockaddr_in sa;
+ memset(&sa, 0, sizeof(sa));
+ int e = sethostbyname(hostname, sa);
+ if(e) return e;
+ sa.sin_family = AF_INET;
+ sa.sin_port = htons(port);
+ int s = socket(PF_INET, SOCK_STREAM, 0);
+ if(s == -1)
+ return -ERR_SOCKET;
+ if(connect(s, (sockaddr*)&sa, sizeof(sa)) != 0) {
+ switch(errno) {
+ case ECONNREFUSED: return -ERR_CONN_REFUSED;
+ case ETIMEDOUT: return -ERR_CONN_TIMEDOUT;
+ case ENETUNREACH: return -ERR_CONN_UNREACHABLE;
+ default: return -ERR_CONN_FAILED;
+ }
+ }
+ return s;
+}
diff --git a/missing b/missing
new file mode 100755
index 0000000..7789652
--- /dev/null
+++ b/missing
@@ -0,0 +1,190 @@
+#! /bin/sh
+# Common stub for a few missing GNU programs while installing.
+# Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+# Franc,ois Pinard <pinard@iro.umontreal.ca>, 1996.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
+if test $# -eq 0; then
+ echo 1>&2 "Try \`$0 --help' for more information"
+ exit 1
+fi
+
+case "$1" in
+
+ -h|--h|--he|--hel|--help)
+ echo "\
+$0 [OPTION]... PROGRAM [ARGUMENT]...
+
+Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an
+error status if there is no known handling for PROGRAM.
+
+Options:
+ -h, --help display this help and exit
+ -v, --version output version information and exit
+
+Supported PROGRAM values:
+ aclocal touch file \`aclocal.m4'
+ autoconf touch file \`configure'
+ autoheader touch file \`config.h.in'
+ automake touch all \`Makefile.in' files
+ bison create \`y.tab.[ch]', if possible, from existing .[ch]
+ flex create \`lex.yy.c', if possible, from existing .c
+ lex create \`lex.yy.c', if possible, from existing .c
+ makeinfo touch the output file
+ yacc create \`y.tab.[ch]', if possible, from existing .[ch]"
+ ;;
+
+ -v|--v|--ve|--ver|--vers|--versi|--versio|--version)
+ echo "missing - GNU libit 0.0"
+ ;;
+
+ -*)
+ echo 1>&2 "$0: Unknown \`$1' option"
+ echo 1>&2 "Try \`$0 --help' for more information"
+ exit 1
+ ;;
+
+ aclocal)
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified \`acinclude.m4' or \`configure.in'. You might want
+ to install the \`Automake' and \`Perl' packages. Grab them from
+ any GNU archive site."
+ touch aclocal.m4
+ ;;
+
+ autoconf)
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified \`configure.in'. You might want to install the
+ \`Autoconf' and \`GNU m4' packages. Grab them from any GNU
+ archive site."
+ touch configure
+ ;;
+
+ autoheader)
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified \`acconfig.h' or \`configure.in'. You might want
+ to install the \`Autoconf' and \`GNU m4' packages. Grab them
+ from any GNU archive site."
+ files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' configure.in`
+ test -z "$files" && files="config.h"
+ touch_files=
+ for f in $files; do
+ case "$f" in
+ *:*) touch_files="$touch_files "`echo "$f" |
+ sed -e 's/^[^:]*://' -e 's/:.*//'`;;
+ *) touch_files="$touch_files $f.in";;
+ esac
+ done
+ touch $touch_files
+ ;;
+
+ automake)
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified \`Makefile.am', \`acinclude.m4' or \`configure.in'.
+ You might want to install the \`Automake' and \`Perl' packages.
+ Grab them from any GNU archive site."
+ find . -type f -name Makefile.am -print |
+ sed 's/\.am$/.in/' |
+ while read f; do touch "$f"; done
+ ;;
+
+ bison|yacc)
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified a \`.y' file. You may need the \`Bison' package
+ in order for those modifications to take effect. You can get
+ \`Bison' from any GNU archive site."
+ rm -f y.tab.c y.tab.h
+ if [ $# -ne 1 ]; then
+ eval LASTARG="\${$#}"
+ case "$LASTARG" in
+ *.y)
+ SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'`
+ if [ -f "$SRCFILE" ]; then
+ cp "$SRCFILE" y.tab.c
+ fi
+ SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'`
+ if [ -f "$SRCFILE" ]; then
+ cp "$SRCFILE" y.tab.h
+ fi
+ ;;
+ esac
+ fi
+ if [ ! -f y.tab.h ]; then
+ echo >y.tab.h
+ fi
+ if [ ! -f y.tab.c ]; then
+ echo 'main() { return 0; }' >y.tab.c
+ fi
+ ;;
+
+ lex|flex)
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified a \`.l' file. You may need the \`Flex' package
+ in order for those modifications to take effect. You can get
+ \`Flex' from any GNU archive site."
+ rm -f lex.yy.c
+ if [ $# -ne 1 ]; then
+ eval LASTARG="\${$#}"
+ case "$LASTARG" in
+ *.l)
+ SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'`
+ if [ -f "$SRCFILE" ]; then
+ cp "$SRCFILE" lex.yy.c
+ fi
+ ;;
+ esac
+ fi
+ if [ ! -f lex.yy.c ]; then
+ echo 'main() { return 0; }' >lex.yy.c
+ fi
+ ;;
+
+ makeinfo)
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified a \`.texi' or \`.texinfo' file, or any other file
+ indirectly affecting the aspect of the manual. The spurious
+ call might also be the consequence of using a buggy \`make' (AIX,
+ DU, IRIX). You might want to install the \`Texinfo' package or
+ the \`GNU make' package. Grab either from any GNU archive site."
+ file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'`
+ if test -z "$file"; then
+ file=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'`
+ file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $file`
+ fi
+ touch $file
+ ;;
+
+ *)
+ echo 1>&2 "\
+WARNING: \`$1' is needed, and you do not seem to have it handy on your
+ system. You might have modified some files without having the
+ proper tools for further handling them. Check the \`README' file,
+ it often tells you about the needed prerequirements for installing
+ this package. You may also peek at any GNU archive site, in case
+ some other package would contain this missing \`$1' program."
+ exit 1
+ ;;
+esac
+
+exit 0
diff --git a/mkinstalldirs b/mkinstalldirs
new file mode 100755
index 0000000..4f58503
--- /dev/null
+++ b/mkinstalldirs
@@ -0,0 +1,40 @@
+#! /bin/sh
+# mkinstalldirs --- make directory hierarchy
+# Author: Noah Friedman <friedman@prep.ai.mit.edu>
+# Created: 1993-05-16
+# Public domain
+
+# $Id: mkinstalldirs,v 1.13 1999/01/05 03:18:55 bje Exp $
+
+errstatus=0
+
+for file
+do
+ set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'`
+ shift
+
+ pathcomp=
+ for d
+ do
+ pathcomp="$pathcomp$d"
+ case "$pathcomp" in
+ -* ) pathcomp=./$pathcomp ;;
+ esac
+
+ if test ! -d "$pathcomp"; then
+ echo "mkdir $pathcomp"
+
+ mkdir "$pathcomp" || lasterr=$?
+
+ if test ! -d "$pathcomp"; then
+ errstatus=$lasterr
+ fi
+ fi
+
+ pathcomp="$pathcomp/"
+ done
+done
+
+exit $errstatus
+
+# mkinstalldirs ends here
diff --git a/nullmailer-1.00RC5.spec b/nullmailer-1.00RC5.spec
new file mode 100644
index 0000000..aec3504
--- /dev/null
+++ b/nullmailer-1.00RC5.spec
@@ -0,0 +1,85 @@
+Name: nullmailer
+Summary: Simple relay-only mail transport agent
+Version: 1.00RC5
+Release: 1
+Copyright: GPL
+Group: Networking/Daemons
+Source: http://em.ca/~bruceg/nullmailer/archive/%{version}/nullmailer-%{version}.tar.gz
+BuildRoot: /tmp/nullmailer-root
+URL: http://em.ca/~bruceg/nullmailer/
+Packager: Bruce Guenter <bruceg@em.ca>
+Provides: smtpdaemon
+Conflicts: sendmail
+Conflicts: qmail
+Requires: supervise-scripts >= 3.2
+PreReq: shadow-utils
+
+%description
+Nullmailer is a mail transport agent designed to only relay all its
+messages through a fixed set of "upstream" hosts. It is also designed
+to be secure.
+
+%prep
+%setup
+
+%build
+CFLAGS="$RPM_OPT_FLAGS" CXXFLAGS="$RPM_OPT_FLAGS" \
+./configure --prefix=/usr --sysconfdir=/etc --localstatedir=/var
+
+make
+
+%install
+rm -fr $RPM_BUILD_ROOT
+mkdir -p $RPM_BUILD_ROOT/{usr/lib,etc/rc.d/init.d}
+mkdir -p $RPM_BUILD_ROOT/var/nullmailer/service/log
+mkdir -p $RPM_BUILD_ROOT/var/log/nullmailer
+
+make DESTDIR=$RPM_BUILD_ROOT install-strip
+ln -s ../sbin/sendmail $RPM_BUILD_ROOT/usr/lib/sendmail
+install scripts/nullmailer.run $RPM_BUILD_ROOT/var/nullmailer/service/run
+install scripts/nullmailer-log.run $RPM_BUILD_ROOT/var/nullmailer/service/log/run
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%pre
+PATH="/sbin:/usr/sbin:$PATH" export PATH
+if [ "$1" = 1 ]; then
+ # pre-install instructions
+ grep ^nullmail: /etc/group >/dev/null || groupadd -r nullmail
+ grep ^nullmail: /etc/passwd >/dev/null || useradd -d /var/lock/svc/nullmailer -g nullmail -M -r -s /bin/true nullmail
+fi
+
+%post
+if ! [ -L /service/nullmailer ]; then
+ svc-add /var/nullmailer/service nullmailer
+fi
+
+%preun
+if [ "$1" = 0 ]; then
+ svc-remove nullmailer
+fi
+
+%postun
+if [ "$1" = 0 ]; then
+ # post-erase instructions
+ /usr/sbin/userdel nullmail
+ /usr/sbin/groupdel nullmail
+fi
+
+%files
+%defattr(-,nullmail,nullmail)
+%doc AUTHORS BUGS ChangeLog COPYING INSTALL NEWS README TODO YEAR2000
+%dir /etc/nullmailer
+%attr(04711,nullmail,nullmail) /usr/bin/mailq
+/usr/bin/nullmailer-inject
+/usr/lib/sendmail
+%dir /usr/libexec/nullmailer
+/usr/libexec/nullmailer/*
+/usr/man/man1/*
+/usr/man/man8/*
+%attr(04711,nullmail,nullmail) /usr/sbin/nullmailer-queue
+/usr/sbin/nullmailer-send
+/usr/sbin/sendmail
+%dir /var/log/nullmailer
+/var/nullmailer
diff --git a/protocols/Makefile.am b/protocols/Makefile.am
new file mode 100644
index 0000000..46d5dc1
--- /dev/null
+++ b/protocols/Makefile.am
@@ -0,0 +1,11 @@
+libexecdir = @libexecdir@/nullmailer
+
+libexec_PROGRAMS = smtp qmqp
+CXXLINK = $(CC) $(CXXFLAGS) $(LDFLAGS) -o $@
+INCLUDES = -I../lib -I../lib/cli
+
+smtp_SOURCES = smtp.cc protocol.cc protocol.h
+smtp_LDADD = ../lib/cli/libcli.a ../lib/libnullmailer.a
+
+qmqp_SOURCES = qmqp.cc protocol.cc protocol.h
+qmqp_LDADD = ../lib/cli/libcli.a ../lib/libnullmailer.a
diff --git a/protocols/Makefile.in b/protocols/Makefile.in
new file mode 100644
index 0000000..c9f8a94
--- /dev/null
+++ b/protocols/Makefile.in
@@ -0,0 +1,312 @@
+# Makefile.in generated automatically by automake 1.4a from Makefile.am
+
+# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DESTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_FLAG =
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+CC = @CC@
+CXX = @CXX@
+MAKEINFO = @MAKEINFO@
+MKDIR = @MKDIR@
+PACKAGE = @PACKAGE@
+RANLIB = @RANLIB@
+RM = @RM@
+STRIP = @STRIP@
+VERSION = @VERSION@
+
+libexecdir = @libexecdir@/nullmailer
+
+libexec_PROGRAMS = smtp qmqp
+CXXLINK = $(CC) $(CXXFLAGS) $(LDFLAGS) -o $@
+INCLUDES = -I../lib -I../lib/cli
+
+smtp_SOURCES = smtp.cc protocol.cc protocol.h
+smtp_LDADD = ../lib/cli/libcli.a ../lib/libnullmailer.a
+
+qmqp_SOURCES = qmqp.cc protocol.cc protocol.h
+qmqp_LDADD = ../lib/cli/libcli.a ../lib/libnullmailer.a
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = ../config.h
+CONFIG_CLEAN_FILES =
+PROGRAMS = $(libexec_PROGRAMS)
+
+
+DEFS = @DEFS@ -I. -I$(srcdir) -I..
+CPPFLAGS = @CPPFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+smtp_OBJECTS = smtp.o protocol.o
+smtp_DEPENDENCIES = ../lib/cli/libcli.a ../lib/libnullmailer.a
+smtp_LDFLAGS =
+qmqp_OBJECTS = qmqp.o protocol.o
+qmqp_DEPENDENCIES = ../lib/cli/libcli.a ../lib/libnullmailer.a
+qmqp_LDFLAGS =
+CXXFLAGS = @CXXFLAGS@
+CXXCOMPILE = $(CXX) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+CXXLD = $(CXX)
+CFLAGS = @CFLAGS@
+COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@
+DIST_COMMON = Makefile.am Makefile.in
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = gtar
+GZIP_ENV = --best
+SOURCES = $(smtp_SOURCES) $(qmqp_SOURCES)
+OBJECTS = $(smtp_OBJECTS) $(qmqp_OBJECTS)
+
+all: all-redirect
+.SUFFIXES:
+.SUFFIXES: .S .c .cc .o .s
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
+ cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps protocols/Makefile
+
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ cd $(top_builddir) \
+ && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+
+mostlyclean-libexecPROGRAMS:
+
+clean-libexecPROGRAMS:
+ -test -z "$(libexec_PROGRAMS)" || rm -f $(libexec_PROGRAMS)
+
+distclean-libexecPROGRAMS:
+
+maintainer-clean-libexecPROGRAMS:
+
+install-libexecPROGRAMS: $(libexec_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ $(mkinstalldirs) $(DESTDIR)$(libexecdir)
+ @list='$(libexec_PROGRAMS)'; for p in $$list; do \
+ if test -f $$p; then \
+ echo " $(INSTALL_PROGRAM) $(INSTALL_STRIP_FLAG) $$p $(DESTDIR)$(libexecdir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`"; \
+ $(INSTALL_PROGRAM) $(INSTALL_STRIP_FLAG) $$p $(DESTDIR)$(libexecdir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \
+ else :; fi; \
+ done
+
+uninstall-libexecPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ list='$(libexec_PROGRAMS)'; for p in $$list; do \
+ rm -f $(DESTDIR)$(libexecdir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \
+ done
+
+.c.o:
+ $(COMPILE) -c $<
+
+.s.o:
+ $(COMPILE) -c $<
+
+.S.o:
+ $(COMPILE) -c $<
+
+mostlyclean-compile:
+ -rm -f *.o core *.core
+
+clean-compile:
+
+distclean-compile:
+ -rm -f *.tab.c
+
+maintainer-clean-compile:
+
+smtp: $(smtp_OBJECTS) $(smtp_DEPENDENCIES)
+ @rm -f smtp
+ $(CXXLINK) $(smtp_LDFLAGS) $(smtp_OBJECTS) $(smtp_LDADD) $(LIBS)
+
+qmqp: $(qmqp_OBJECTS) $(qmqp_DEPENDENCIES)
+ @rm -f qmqp
+ $(CXXLINK) $(qmqp_LDFLAGS) $(qmqp_OBJECTS) $(qmqp_LDADD) $(LIBS)
+.cc.o:
+ $(CXXCOMPILE) -c $<
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP)
+ list='$(SOURCES) $(HEADERS)'; \
+ unique=`for i in $$list; do echo $$i; done | \
+ awk ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ here=`pwd` && cd $(srcdir) \
+ && mkid -f$$here/ID $$unique $(LISP)
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS)'; \
+ unique=`for i in $$list; do echo $$i; done | \
+ awk ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
+ || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS)
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+ -rm -f TAGS ID
+
+maintainer-clean-tags:
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = protocols
+
+distdir: $(DISTFILES)
+ @for file in $(DISTFILES); do \
+ d=$(srcdir); \
+ if test -d $$d/$$file; then \
+ cp -pr $$d/$$file $(distdir)/$$file; \
+ else \
+ test -f $(distdir)/$$file \
+ || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+ || cp -p $$d/$$file $(distdir)/$$file || :; \
+ fi; \
+ done
+protocol.o: protocol.cc ../config.h ../lib/connect.h \
+ ../lib/mystring/mystring.h ../lib/mystring/rep.h \
+ ../lib/mystring/iter.h ../lib/mystring/join.h ../lib/errcodes.h \
+ protocol.h ../lib/fdbuf/fdbuf.h ../lib/fdbuf/fdibuf.h \
+ ../lib/fdbuf/fdobuf.h ../lib/cli/cli.h
+qmqp.o: qmqp.cc ../config.h ../lib/errcodes.h ../lib/fdbuf/fdbuf.h \
+ ../lib/fdbuf/fdibuf.h ../lib/fdbuf/fdobuf.h ../lib/hostname.h \
+ ../lib/itoa.h ../lib/mystring/mystring.h ../lib/mystring/rep.h \
+ ../lib/mystring/iter.h ../lib/mystring/join.h \
+ ../lib/netstring.h protocol.h
+smtp.o: smtp.cc ../config.h ../lib/connect.h ../lib/mystring/mystring.h \
+ ../lib/mystring/rep.h ../lib/mystring/iter.h \
+ ../lib/mystring/join.h ../lib/errcodes.h ../lib/fdbuf/fdbuf.h \
+ ../lib/fdbuf/fdibuf.h ../lib/fdbuf/fdobuf.h ../lib/hostname.h \
+ ../lib/itoa.h protocol.h
+
+info-am:
+info: info-am
+dvi-am:
+dvi: dvi-am
+check-am: all-am
+check: check-am
+installcheck-am:
+installcheck: installcheck-am
+install-exec-am: install-libexecPROGRAMS
+install-exec: install-exec-am
+
+install-data-am:
+install-data: install-data-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-am
+uninstall-am: uninstall-libexecPROGRAMS
+uninstall: uninstall-am
+all-am: Makefile $(PROGRAMS)
+all-redirect: all-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_STRIP_FLAG=-s install
+installdirs:
+ $(mkinstalldirs) $(DESTDIR)$(libexecdir)
+
+
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -rm -f Makefile $(CONFIG_CLEAN_FILES)
+ -rm -f config.cache config.log stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+mostlyclean-am: mostlyclean-libexecPROGRAMS mostlyclean-compile \
+ mostlyclean-tags mostlyclean-generic
+
+mostlyclean: mostlyclean-am
+
+clean-am: clean-libexecPROGRAMS clean-compile clean-tags clean-generic \
+ mostlyclean-am
+
+clean: clean-am
+
+distclean-am: distclean-libexecPROGRAMS distclean-compile \
+ distclean-tags distclean-generic clean-am
+
+distclean: distclean-am
+
+maintainer-clean-am: maintainer-clean-libexecPROGRAMS \
+ maintainer-clean-compile maintainer-clean-tags \
+ maintainer-clean-generic distclean-am
+ @echo "This command is intended for maintainers to use;"
+ @echo "it deletes files that may require special tools to rebuild."
+
+maintainer-clean: maintainer-clean-am
+
+.PHONY: mostlyclean-libexecPROGRAMS distclean-libexecPROGRAMS \
+clean-libexecPROGRAMS maintainer-clean-libexecPROGRAMS \
+uninstall-libexecPROGRAMS install-libexecPROGRAMS mostlyclean-compile \
+distclean-compile clean-compile maintainer-clean-compile tags \
+mostlyclean-tags distclean-tags clean-tags maintainer-clean-tags \
+distdir info-am info dvi-am dvi check check-am installcheck-am \
+installcheck install-exec-am install-exec install-data-am install-data \
+install-am install uninstall-am uninstall all-redirect all-am all \
+installdirs mostlyclean-generic distclean-generic clean-generic \
+maintainer-clean-generic clean mostlyclean distclean maintainer-clean
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/protocols/protocol.cc b/protocols/protocol.cc
new file mode 100644
index 0000000..e32d0a5
--- /dev/null
+++ b/protocols/protocol.cc
@@ -0,0 +1,52 @@
+// nullmailer -- a simple relay-only MTA
+// Copyright (C) 1999,2000 Bruce Guenter <bruceg@em.ca>
+//
+// 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
+//
+// You can contact me at <bruceg@em.ca>. There is also a mailing list
+// available to discuss this package. To subscribe, send an email to
+// <nullmailer-subscribe@lists.em.ca>.
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "connect.h"
+#include "errcodes.h"
+#include "protocol.h"
+#include "cli.h"
+
+const char* cli_help_suffix = "";
+const char* cli_args_usage = "remote-address < mail-file";
+const int cli_args_min = 1;
+const int cli_args_max = 1;
+cli_option cli_options[] = {
+ { 'p', "port", cli_option::integer, 0, &port,
+ "Set the port number on the remote host to connect to", 0 },
+ {0}
+};
+
+int cli_main(int, char* argv[])
+{
+ const char* remote = argv[0];
+ fdibuf in(0, true);
+ int tmp = protocol_prep(&in);
+ if(tmp)
+ return tmp;
+ int fd = tcpconnect(remote, port);
+ if(fd < 0)
+ return -fd;
+ return protocol_send(&in, fd);
+}
+
diff --git a/protocols/protocol.h b/protocols/protocol.h
new file mode 100644
index 0000000..0d0f369
--- /dev/null
+++ b/protocols/protocol.h
@@ -0,0 +1,12 @@
+#ifndef NULLMAILER__PROTOCOL__H__
+#define NULLMAILER__PROTOCOL__H__
+
+#include "fdbuf/fdbuf.h"
+
+// This must be provided by the protocol, but will be set by the lib.
+extern int port;
+
+extern int protocol_prep(fdibuf* in);
+extern int protocol_send(fdibuf* in, int fd);
+
+#endif
diff --git a/protocols/qmqp.cc b/protocols/qmqp.cc
new file mode 100644
index 0000000..d71d70b
--- /dev/null
+++ b/protocols/qmqp.cc
@@ -0,0 +1,134 @@
+// nullmailer -- a simple relay-only MTA
+// Copyright (C) 1999,2000 Bruce Guenter <bruceg@em.ca>
+//
+// 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
+//
+// You can contact me at <bruceg@em.ca>. There is also a mailing list
+// available to discuss this package. To subscribe, send an email to
+// <nullmailer-subscribe@lists.em.ca>.
+
+#include "config.h"
+#include <stdlib.h>
+#include <unistd.h>
+#include "errcodes.h"
+#include "fdbuf/fdbuf.h"
+#include "hostname.h"
+#include "itoa.h"
+#include "mystring/mystring.h"
+#include "netstring.h"
+#include "protocol.h"
+
+int port = 628;
+const char* cli_program = "qmqp";
+const char* cli_help_prefix = "Send an emal message via QMQP\n";
+
+class qmqp
+{
+ fdibuf in;
+ fdobuf out;
+public:
+ qmqp(int fd);
+ ~qmqp();
+ int send(fdibuf* msg, unsigned long size, const mystring& env);
+};
+
+qmqp::qmqp(int fd)
+ : in(fd), out(fd)
+{
+}
+
+qmqp::~qmqp()
+{
+}
+
+bool skip_envelope(fdibuf* msg)
+{
+ if(!msg->rewind())
+ return false;
+ mystring tmp;
+ while(msg->getline(tmp))
+ if(!tmp)
+ break;
+ return msg;
+}
+
+int qmqp::send(fdibuf* msg, unsigned long size, const mystring& env)
+{
+ if(!skip_envelope(msg))
+ return -ERR_MSG_READ;
+ unsigned long fullsize = strlen(itoa(size)) + 1 + size + 1 + env.length();
+ out << itoa(fullsize) << ":" // Start the "outer" netstring
+ << itoa(size) << ":"; // Start the message netstring
+ fdbuf_copy(*msg, out, true); // Send out the message
+ out << "," // End the message netstring
+ << env // The envelope is already encoded
+ << ","; // End the "outer" netstring
+ if(!out.flush())
+ return -ERR_MSG_WRITE;
+ mystring response;
+ if(!in.getnetstring(response))
+ return -ERR_PROTO;
+ switch(response[0]) {
+ case 'K': return 0;
+ case 'Z': return -ERR_MSG_TEMPFAIL;
+ case 'D': return -ERR_MSG_PERMFAIL;
+ default: return -ERR_PROTO;
+ }
+}
+
+bool compute_size(fdibuf* msg, unsigned long& size)
+{
+ char buf[4096];
+ size = 0;
+ while(msg->read(buf, 4096))
+ size += msg->last_count();
+ if(msg->eof())
+ size += msg->last_count();
+ return size > 0;
+}
+
+bool make_envelope(fdibuf* msg, mystring& env)
+{
+ mystring tmp;
+ while(msg->getline(tmp)) {
+ if(!tmp)
+ return true;
+ env += str2net(tmp);
+ }
+ return false;
+}
+
+bool preload_data(fdibuf* msg, unsigned long& size, mystring& env)
+{
+ return make_envelope(msg, env) &&
+ compute_size(msg, size);
+}
+
+static unsigned long msg_size;
+static mystring msg_envelope;
+
+int protocol_prep(fdibuf* in)
+{
+ if(!preload_data(in, msg_size, msg_envelope))
+ return ERR_MSG_READ;
+ return 0;
+}
+
+int protocol_send(fdibuf* in, int fd)
+{
+ alarm(60*60); // Connection must close after an hour
+ qmqp conn(fd);
+ return -conn.send(in, msg_size, msg_envelope);
+}
diff --git a/protocols/smtp.cc b/protocols/smtp.cc
new file mode 100644
index 0000000..9ec690c
--- /dev/null
+++ b/protocols/smtp.cc
@@ -0,0 +1,149 @@
+// nullmailer -- a simple relay-only MTA
+// Copyright (C) 1999,2000 Bruce Guenter <bruceg@em.ca>
+//
+// 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
+//
+// You can contact me at <bruceg@em.ca>. There is also a mailing list
+// available to discuss this package. To subscribe, send an email to
+// <nullmailer-subscribe@lists.em.ca>.
+
+#include "config.h"
+#include <stdlib.h>
+#include <unistd.h>
+#include "connect.h"
+#include "errcodes.h"
+#include "fdbuf/fdbuf.h"
+#include "hostname.h"
+#include "itoa.h"
+#include "mystring/mystring.h"
+#include "protocol.h"
+
+int port = 25;
+const char* cli_program = "smtp";
+const char* cli_help_prefix = "Send an email message via SMTP\n";
+
+class smtp
+{
+ fdibuf in;
+ fdobuf out;
+public:
+ smtp(int fd);
+ ~smtp();
+ int get(mystring& str);
+ int put(mystring cmd, mystring& result);
+ void docmd(mystring cmd, int range, bool nofail=false);
+ void send_data(fdibuf* msg);
+ void send_envelope(fdibuf* msg);
+ void send(fdibuf* msg);
+};
+
+smtp::smtp(int fd)
+ : in(fd), out(fd)
+{
+}
+
+smtp::~smtp()
+{
+}
+
+int smtp::get(mystring& str)
+{
+ mystring tmp;
+ str = "";
+ int code = -1;
+ while(in.getline(tmp)) {
+ if(tmp[tmp.length()-1] == '\r')
+ tmp = tmp.left(tmp.length()-1);
+ code = atoi(tmp.c_str());
+ if(!!str)
+ str += "/";
+ str += tmp.right(4);
+ if(tmp[3] != '-')
+ break;
+ }
+ return code;
+}
+
+int smtp::put(mystring cmd, mystring& result)
+{
+ out << cmd << "\r\n";
+ if(!out.flush())
+ return -1;
+ return get(result);
+}
+
+void smtp::docmd(mystring cmd, int range, bool nofail)
+{
+ mystring msg;
+ int code;
+ if(!cmd)
+ code = get(msg);
+ else
+ code = put(cmd, msg);
+ if(!nofail) {
+ if(code < range || code >= (range+100)) {
+ int e;
+ if(code >= 500)
+ e = ERR_MSG_PERMFAIL;
+ else if(code >= 400)
+ e = ERR_MSG_TEMPFAIL;
+ else
+ e = ERR_PROTO;
+ exit(e);
+ }
+ }
+}
+
+void smtp::send_envelope(fdibuf* msg)
+{
+ mystring tmp;
+ msg->getline(tmp);
+ docmd("MAIL FROM: <" + tmp + ">", 200);
+ while(msg->getline(tmp) && !!tmp)
+ docmd("RCPT TO: <" + tmp + ">", 200);
+}
+
+void smtp::send_data(fdibuf* msg)
+{
+ docmd("DATA", 300);
+ mystring tmp;
+ while(msg->getline(tmp)) {
+ if((tmp[0] == '.' && tmp[1] == 0 && !(out << ".")) ||
+ !(out << tmp << "\r\n"))
+ exit(ERR_MSG_WRITE);
+ }
+ docmd(".", 200);
+}
+
+void smtp::send(fdibuf* msg)
+{
+ send_envelope(msg);
+ send_data(msg);
+}
+
+int protocol_prep(fdibuf*)
+{
+ return 0;
+}
+
+int protocol_send(fdibuf* in, int fd)
+{
+ smtp conn(fd);
+ conn.docmd("", 200);
+ conn.docmd("HELO " + hostname(), 200);
+ conn.send(in);
+ conn.docmd("QUIT", 200, true);
+ return 0;
+}
diff --git a/scripts/CVS/Entries b/scripts/CVS/Entries
new file mode 100644
index 0000000..549ceaa
--- /dev/null
+++ b/scripts/CVS/Entries
@@ -0,0 +1,3 @@
+/nullmailer-log.run/1.1/Wed Feb 16 18:24:30 2000//
+/nullmailer.run/1.1/Wed Feb 16 18:24:30 2000//
+D
diff --git a/scripts/CVS/Repository b/scripts/CVS/Repository
new file mode 100644
index 0000000..851a70c
--- /dev/null
+++ b/scripts/CVS/Repository
@@ -0,0 +1 @@
+nullmailer/scripts
diff --git a/scripts/CVS/Root b/scripts/CVS/Root
new file mode 100644
index 0000000..a644f54
--- /dev/null
+++ b/scripts/CVS/Root
@@ -0,0 +1 @@
+/CVS
diff --git a/scripts/nullmailer-log.run b/scripts/nullmailer-log.run
new file mode 100755
index 0000000..3e69ddb
--- /dev/null
+++ b/scripts/nullmailer-log.run
@@ -0,0 +1,2 @@
+#! /bin/sh
+exec setuidgid nullmail multilog t /var/log/nullmailer
diff --git a/scripts/nullmailer.run b/scripts/nullmailer.run
new file mode 100755
index 0000000..640e5cf
--- /dev/null
+++ b/scripts/nullmailer.run
@@ -0,0 +1,2 @@
+#! /bin/sh
+exec setuidgid nullmail /usr/sbin/nullmailer-send
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..31f59c7
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,28 @@
+bin_PROGRAMS = \
+ mailq \
+ nullmailer-inject
+sbin_PROGRAMS = \
+ nullmailer-queue \
+ nullmailer-send \
+ sendmail
+
+#noinst_PROGRAMS = address
+
+CXXLINK = $(CC) $(CXXFLAGS) $(LDFLAGS) -o $@
+INCLUDES = -I../lib -I../lib/cli
+
+mailq_SOURCES = mailq.cc
+mailq_LDADD = ../lib/libnullmailer.a
+
+nullmailer_inject_SOURCES = inject.cc
+nullmailer_inject_LDADD = ../lib/cli/libcli.a ../lib/libnullmailer.a
+
+nullmailer_queue_SOURCES = queue.cc
+nullmailer_queue_LDADD = ../lib/libnullmailer.a
+
+nullmailer_send_SOURCES = send.cc
+nullmailer_send_LDADD = ../lib/libnullmailer.a
+
+sendmail_SOURCES = sendmail.cc
+sendmail_LDADD = ../lib/cli/libcli.a ../lib/libnullmailer.a
+
diff --git a/src/Makefile.in b/src/Makefile.in
new file mode 100644
index 0000000..03712ad
--- /dev/null
+++ b/src/Makefile.in
@@ -0,0 +1,381 @@
+# Makefile.in generated automatically by automake 1.4a from Makefile.am
+
+# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DESTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_FLAG =
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+CC = @CC@
+CXX = @CXX@
+MAKEINFO = @MAKEINFO@
+MKDIR = @MKDIR@
+PACKAGE = @PACKAGE@
+RANLIB = @RANLIB@
+RM = @RM@
+STRIP = @STRIP@
+VERSION = @VERSION@
+
+bin_PROGRAMS = mailq nullmailer-inject
+
+sbin_PROGRAMS = nullmailer-queue nullmailer-send sendmail
+
+
+#noinst_PROGRAMS = address
+
+CXXLINK = $(CC) $(CXXFLAGS) $(LDFLAGS) -o $@
+INCLUDES = -I../lib -I../lib/cli
+
+mailq_SOURCES = mailq.cc
+mailq_LDADD = ../lib/libnullmailer.a
+
+nullmailer_inject_SOURCES = inject.cc
+nullmailer_inject_LDADD = ../lib/cli/libcli.a ../lib/libnullmailer.a
+
+nullmailer_queue_SOURCES = queue.cc
+nullmailer_queue_LDADD = ../lib/libnullmailer.a
+
+nullmailer_send_SOURCES = send.cc
+nullmailer_send_LDADD = ../lib/libnullmailer.a
+
+sendmail_SOURCES = sendmail.cc
+sendmail_LDADD = ../lib/cli/libcli.a ../lib/libnullmailer.a
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = ../config.h
+CONFIG_CLEAN_FILES =
+PROGRAMS = $(bin_PROGRAMS) $(sbin_PROGRAMS)
+
+
+DEFS = @DEFS@ -I. -I$(srcdir) -I..
+CPPFLAGS = @CPPFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+mailq_OBJECTS = mailq.o
+mailq_DEPENDENCIES = ../lib/libnullmailer.a
+mailq_LDFLAGS =
+nullmailer_inject_OBJECTS = inject.o
+nullmailer_inject_DEPENDENCIES = ../lib/cli/libcli.a \
+../lib/libnullmailer.a
+nullmailer_inject_LDFLAGS =
+nullmailer_queue_OBJECTS = queue.o
+nullmailer_queue_DEPENDENCIES = ../lib/libnullmailer.a
+nullmailer_queue_LDFLAGS =
+nullmailer_send_OBJECTS = send.o
+nullmailer_send_DEPENDENCIES = ../lib/libnullmailer.a
+nullmailer_send_LDFLAGS =
+sendmail_OBJECTS = sendmail.o
+sendmail_DEPENDENCIES = ../lib/cli/libcli.a ../lib/libnullmailer.a
+sendmail_LDFLAGS =
+CXXFLAGS = @CXXFLAGS@
+CXXCOMPILE = $(CXX) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+CXXLD = $(CXX)
+DIST_COMMON = Makefile.am Makefile.in
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = gtar
+GZIP_ENV = --best
+SOURCES = $(mailq_SOURCES) $(nullmailer_inject_SOURCES) $(nullmailer_queue_SOURCES) $(nullmailer_send_SOURCES) $(sendmail_SOURCES)
+OBJECTS = $(mailq_OBJECTS) $(nullmailer_inject_OBJECTS) $(nullmailer_queue_OBJECTS) $(nullmailer_send_OBJECTS) $(sendmail_OBJECTS)
+
+all: all-redirect
+.SUFFIXES:
+.SUFFIXES: .S .c .cc .o .s
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
+ cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps src/Makefile
+
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ cd $(top_builddir) \
+ && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+
+mostlyclean-binPROGRAMS:
+
+clean-binPROGRAMS:
+ -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS)
+
+distclean-binPROGRAMS:
+
+maintainer-clean-binPROGRAMS:
+
+install-binPROGRAMS: $(bin_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ $(mkinstalldirs) $(DESTDIR)$(bindir)
+ @list='$(bin_PROGRAMS)'; for p in $$list; do \
+ if test -f $$p; then \
+ echo " $(INSTALL_PROGRAM) $(INSTALL_STRIP_FLAG) $$p $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`"; \
+ $(INSTALL_PROGRAM) $(INSTALL_STRIP_FLAG) $$p $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \
+ else :; fi; \
+ done
+
+uninstall-binPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ list='$(bin_PROGRAMS)'; for p in $$list; do \
+ rm -f $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \
+ done
+
+mostlyclean-sbinPROGRAMS:
+
+clean-sbinPROGRAMS:
+ -test -z "$(sbin_PROGRAMS)" || rm -f $(sbin_PROGRAMS)
+
+distclean-sbinPROGRAMS:
+
+maintainer-clean-sbinPROGRAMS:
+
+install-sbinPROGRAMS: $(sbin_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ $(mkinstalldirs) $(DESTDIR)$(sbindir)
+ @list='$(sbin_PROGRAMS)'; for p in $$list; do \
+ if test -f $$p; then \
+ echo " $(INSTALL_PROGRAM) $(INSTALL_STRIP_FLAG) $$p $(DESTDIR)$(sbindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`"; \
+ $(INSTALL_PROGRAM) $(INSTALL_STRIP_FLAG) $$p $(DESTDIR)$(sbindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \
+ else :; fi; \
+ done
+
+uninstall-sbinPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ list='$(sbin_PROGRAMS)'; for p in $$list; do \
+ rm -f $(DESTDIR)$(sbindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \
+ done
+
+.c.o:
+ $(COMPILE) -c $<
+
+.s.o:
+ $(COMPILE) -c $<
+
+.S.o:
+ $(COMPILE) -c $<
+
+mostlyclean-compile:
+ -rm -f *.o core *.core
+
+clean-compile:
+
+distclean-compile:
+ -rm -f *.tab.c
+
+maintainer-clean-compile:
+
+mailq: $(mailq_OBJECTS) $(mailq_DEPENDENCIES)
+ @rm -f mailq
+ $(CXXLINK) $(mailq_LDFLAGS) $(mailq_OBJECTS) $(mailq_LDADD) $(LIBS)
+
+nullmailer-inject: $(nullmailer_inject_OBJECTS) $(nullmailer_inject_DEPENDENCIES)
+ @rm -f nullmailer-inject
+ $(CXXLINK) $(nullmailer_inject_LDFLAGS) $(nullmailer_inject_OBJECTS) $(nullmailer_inject_LDADD) $(LIBS)
+
+nullmailer-queue: $(nullmailer_queue_OBJECTS) $(nullmailer_queue_DEPENDENCIES)
+ @rm -f nullmailer-queue
+ $(CXXLINK) $(nullmailer_queue_LDFLAGS) $(nullmailer_queue_OBJECTS) $(nullmailer_queue_LDADD) $(LIBS)
+
+nullmailer-send: $(nullmailer_send_OBJECTS) $(nullmailer_send_DEPENDENCIES)
+ @rm -f nullmailer-send
+ $(CXXLINK) $(nullmailer_send_LDFLAGS) $(nullmailer_send_OBJECTS) $(nullmailer_send_LDADD) $(LIBS)
+
+sendmail: $(sendmail_OBJECTS) $(sendmail_DEPENDENCIES)
+ @rm -f sendmail
+ $(CXXLINK) $(sendmail_LDFLAGS) $(sendmail_OBJECTS) $(sendmail_LDADD) $(LIBS)
+.cc.o:
+ $(CXXCOMPILE) -c $<
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP)
+ list='$(SOURCES) $(HEADERS)'; \
+ unique=`for i in $$list; do echo $$i; done | \
+ awk ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ here=`pwd` && cd $(srcdir) \
+ && mkid -f$$here/ID $$unique $(LISP)
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS)'; \
+ unique=`for i in $$list; do echo $$i; done | \
+ awk ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
+ || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS)
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+ -rm -f TAGS ID
+
+maintainer-clean-tags:
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = src
+
+distdir: $(DISTFILES)
+ @for file in $(DISTFILES); do \
+ d=$(srcdir); \
+ if test -d $$d/$$file; then \
+ cp -pr $$d/$$file $(distdir)/$$file; \
+ else \
+ test -f $(distdir)/$$file \
+ || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+ || cp -p $$d/$$file $(distdir)/$$file || :; \
+ fi; \
+ done
+inject.o: inject.cc ../config.h ../lib/defines.h \
+ ../lib/mystring/mystring.h ../lib/mystring/rep.h \
+ ../lib/mystring/iter.h ../lib/mystring/join.h ../lib/list.h \
+ ../lib/hostname.h ../lib/fdbuf/fdbuf.h ../lib/fdbuf/fdibuf.h \
+ ../lib/fdbuf/fdobuf.h ../lib/itoa.h ../lib/address.h \
+ ../lib/canonicalize.h ../lib/configio.h ../lib/cli/cli.h
+mailq.o: mailq.cc ../config.h ../lib/defines.h ../lib/fdbuf/fdbuf.h \
+ ../lib/fdbuf/fdibuf.h ../lib/fdbuf/fdobuf.h ../lib/itoa.h
+queue.o: queue.cc ../config.h ../lib/itoa.h ../lib/defines.h \
+ ../lib/mystring/mystring.h ../lib/mystring/rep.h \
+ ../lib/mystring/iter.h ../lib/mystring/join.h \
+ ../lib/fdbuf/fdbuf.h ../lib/fdbuf/fdibuf.h \
+ ../lib/fdbuf/fdobuf.h ../lib/configio.h ../lib/list.h \
+ ../lib/canonicalize.h ../lib/hostname.h
+send.o: send.cc ../config.h ../lib/configio.h ../lib/mystring/mystring.h \
+ ../lib/mystring/rep.h ../lib/mystring/iter.h \
+ ../lib/mystring/join.h ../lib/list.h ../lib/defines.h \
+ ../lib/errcodes.h ../lib/fdbuf/fdbuf.h ../lib/fdbuf/fdibuf.h \
+ ../lib/fdbuf/fdobuf.h ../lib/itoa.h
+sendmail.o: sendmail.cc ../config.h ../lib/fdbuf/fdbuf.h \
+ ../lib/fdbuf/fdibuf.h ../lib/fdbuf/fdobuf.h ../lib/defines.h \
+ ../lib/cli/cli.h
+
+info-am:
+info: info-am
+dvi-am:
+dvi: dvi-am
+check-am: all-am
+check: check-am
+installcheck-am:
+installcheck: installcheck-am
+install-exec-am: install-binPROGRAMS install-sbinPROGRAMS
+install-exec: install-exec-am
+
+install-data-am:
+install-data: install-data-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-am
+uninstall-am: uninstall-binPROGRAMS uninstall-sbinPROGRAMS
+uninstall: uninstall-am
+all-am: Makefile $(PROGRAMS)
+all-redirect: all-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_STRIP_FLAG=-s install
+installdirs:
+ $(mkinstalldirs) $(DESTDIR)$(bindir) $(DESTDIR)$(sbindir)
+
+
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -rm -f Makefile $(CONFIG_CLEAN_FILES)
+ -rm -f config.cache config.log stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+mostlyclean-am: mostlyclean-binPROGRAMS mostlyclean-sbinPROGRAMS \
+ mostlyclean-compile mostlyclean-tags \
+ mostlyclean-generic
+
+mostlyclean: mostlyclean-am
+
+clean-am: clean-binPROGRAMS clean-sbinPROGRAMS clean-compile clean-tags \
+ clean-generic mostlyclean-am
+
+clean: clean-am
+
+distclean-am: distclean-binPROGRAMS distclean-sbinPROGRAMS \
+ distclean-compile distclean-tags distclean-generic \
+ clean-am
+
+distclean: distclean-am
+
+maintainer-clean-am: maintainer-clean-binPROGRAMS \
+ maintainer-clean-sbinPROGRAMS maintainer-clean-compile \
+ maintainer-clean-tags maintainer-clean-generic \
+ distclean-am
+ @echo "This command is intended for maintainers to use;"
+ @echo "it deletes files that may require special tools to rebuild."
+
+maintainer-clean: maintainer-clean-am
+
+.PHONY: mostlyclean-binPROGRAMS distclean-binPROGRAMS clean-binPROGRAMS \
+maintainer-clean-binPROGRAMS uninstall-binPROGRAMS install-binPROGRAMS \
+mostlyclean-sbinPROGRAMS distclean-sbinPROGRAMS clean-sbinPROGRAMS \
+maintainer-clean-sbinPROGRAMS uninstall-sbinPROGRAMS \
+install-sbinPROGRAMS mostlyclean-compile distclean-compile \
+clean-compile maintainer-clean-compile tags mostlyclean-tags \
+distclean-tags clean-tags maintainer-clean-tags distdir info-am info \
+dvi-am dvi check check-am installcheck-am installcheck install-exec-am \
+install-exec install-data-am install-data install-am install \
+uninstall-am uninstall all-redirect all-am all installdirs \
+mostlyclean-generic distclean-generic clean-generic \
+maintainer-clean-generic clean mostlyclean distclean maintainer-clean
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/inject.cc b/src/inject.cc
new file mode 100644
index 0000000..ac6f241
--- /dev/null
+++ b/src/inject.cc
@@ -0,0 +1,581 @@
+// nullmailer -- a simple relay-only MTA
+// Copyright (C) 1999,2000 Bruce Guenter <bruceg@em.ca>
+//
+// 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
+//
+// You can contact me at <bruceg@em.ca>. There is also a mailing list
+// available to discuss this package. To subscribe, send an email to
+// <nullmailer-subscribe@lists.em.ca>.
+
+#include "config.h"
+#include "defines.h"
+#include <ctype.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include "mystring/mystring.h"
+#include "list.h"
+#include "hostname.h"
+#include "fdbuf/fdbuf.h"
+#include "itoa.h"
+#include "address.h"
+#include "canonicalize.h"
+#include "configio.h"
+#include "cli/cli.h"
+
+enum {
+ use_args, use_both, use_either, use_header
+};
+static int use_recips = use_either;
+static int show_message = false;
+static int show_envelope = false;
+static const char* o_from = 0;
+
+const char* cli_program = "nullmailer-inject";
+const char* cli_help_prefix = "Reformat and inject a message into the nullmailer queue\n";
+const char* cli_help_suffix = "";
+const char* cli_args_usage = "[recipients] <message";
+const int cli_args_min = 0;
+const int cli_args_max = -1;
+cli_option cli_options[] = {
+ { 'a', "use-args", cli_option::flag, use_args, &use_recips,
+ "Use only command-line arguments for recipients", 0 },
+ { 'b', "use-both", cli_option::flag, use_both, &use_recips,
+ "Use both command-line and message header for recipients", 0 },
+ { 'e', "use-either", cli_option::flag, use_either, &use_recips,
+ "Use either command-line and message header for recipients", 0 },
+ { 'h', "use-header", cli_option::flag, use_header, &use_recips,
+ "Use only message header for recipients", 0 },
+ { 'f', "from", cli_option::string, 0, &o_from,
+ "Set the sender address", 0 },
+ { 'n', "no-queue", cli_option::flag, 1, &show_message,
+ "Send the formatted message to standard output", 0 },
+ { 'v', "show-envelope", cli_option::flag, 1, &show_envelope,
+ "Show the envelope with the message", 0 },
+ {0},
+};
+
+#define fail(MSG) do{ fout << "nullmailer-inject: " << MSG << endl; return false; }while(0)
+#define fail_sys(MSG) do{ fout << "nullmailer-inject: " << MSG << ": " << strerror(errno) << endl; return false; }while(0)
+#define bad_hdr(LINE,MSG) do{ header_has_errors = true; fout << "nullmailer-inject: Invalid header line:\n " << LINE << "\n " MSG << endl; }while(0)
+
+typedef list<mystring> slist;
+// static bool do_debug = false;
+
+static mystring cur_line;
+
+///////////////////////////////////////////////////////////////////////////////
+// Configuration
+///////////////////////////////////////////////////////////////////////////////
+mystring defaultdomain;
+mystring defaulthost;
+mystring idhost;
+
+extern void canonicalize(mystring& domain);
+
+void read_config()
+{
+ mystring tmp;
+ if(!config_read("defaultdomain", defaultdomain))
+ defaultdomain = domainname();
+ if(!config_read("defaulthost", defaulthost))
+ defaulthost = hostname();
+ if(!config_read("idhost", idhost))
+ idhost = defaulthost;
+ canonicalize(defaulthost);
+ canonicalize(idhost);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Envelope processing
+///////////////////////////////////////////////////////////////////////////////
+static slist recipients;
+static mystring sender;
+static bool use_header_recips = true;
+
+void parse_recips(const mystring& list)
+{
+ if(!!list) {
+ int start = 0;
+ int end;
+ while((end = list.find_first('\n', start)) >= 0) {
+ recipients.append(list.sub(start, end-start));
+ start = end+1;
+ }
+ }
+}
+
+bool parse_recip_arg(mystring str)
+{
+ mystring list;
+ if(!parse_addresses(str, list))
+ return false;
+ parse_recips(list);
+ return true;
+}
+
+bool parse_sender(const mystring& list)
+{
+ int end = list.find_first('\n');
+ if(end > 0 && list.find_first('\n', end+1) < 0) {
+ sender = list.sub(0, end);
+ return true;
+ }
+ return false;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Header processing
+///////////////////////////////////////////////////////////////////////////////
+static slist headers;
+
+static bool header_is_resent = false;
+static bool header_has_errors = false;
+static bool header_add_to = false;
+
+struct header_field
+{
+ // member information
+ const char* name;
+ unsigned length;
+ bool is_address;
+ bool is_recipient;
+ bool is_sender;
+ bool is_resent;
+ bool remove; // remove means strip after parsing
+ bool ignore; // ignore means do not parse
+
+ bool present;
+
+ bool parse(mystring& line)
+ {
+ if(strncasecmp(line.c_str(), name, length))
+ return false;
+ if(ignore)
+ return true;
+ if(is_resent) {
+ if(!header_is_resent) {
+ sender = "";
+ if(use_header_recips)
+ recipients.empty();
+ }
+ header_is_resent = true;
+ }
+ mystring tmp = line.right(length);
+ if(is_address) {
+ mystring list;
+ if(!parse_addresses(tmp, list))
+ bad_hdr(line, "Unable to parse the addresses.");
+ else {
+ line = mystringjoin(name) + " " + tmp;
+ if(is_recipient) {
+ if(is_resent == header_is_resent && use_header_recips)
+ parse_recips(list);
+ }
+ else if(is_sender) {
+ if(is_resent == header_is_resent && !sender)
+ parse_sender(list);
+ }
+ }
+ }
+ present = true;
+ return true;
+ }
+};
+
+#define F false
+#define T true
+#define X(N,IA,IR,IS,IRS,R) { #N ":",strlen(#N ":"),\
+ IA,IR,IS,IRS,R,false, false }
+static header_field header_fields[] = {
+ // Sender address fields, in order of priority
+ X(Sender, T,F,F,F,F), // 0
+ X(From, T,F,F,F,F), // 1
+ X(Reply-To, T,F,F,F,F), // 2
+ X(Return-Path, T,F,T,F,T), // 3
+ X(Return-Receipt-To, T,F,F,F,F), // 4
+ X(Errors-To, T,F,F,F,F), // 5
+ X(Resent-Sender, T,F,F,T,F), // 6
+ X(Resent-From, T,F,F,T,F), // 7
+ X(Resent-Reply-To, T,F,F,T,F), // 8
+ // Destination address fields
+ X(To, T,T,F,F,F), // 9
+ X(Cc, T,T,F,F,F), // 10
+ X(Bcc, T,T,F,F,T), // 11
+ X(Apparently-To, T,T,F,F,F), // 12
+ X(Resent-To, T,T,F,T,F), // 13
+ X(Resent-Cc, T,T,F,T,F), // 14
+ X(Resent-Bcc, T,T,F,T,T), // 15
+ // Other fields of interest
+ X(Date, F,F,F,F,F), // 16
+ X(Message-Id, F,F,F,F,F), // 17
+ X(Resent-Date, F,F,F,T,F), // 18
+ X(Resent-Message-Id, F,F,F,T,F), // 19
+ X(Content-Length, F,F,F,F,T), // 20
+};
+#undef X
+#undef F
+#undef T
+#define header_field_count (sizeof header_fields/sizeof(header_field))
+static bool& header_has_from = header_fields[1].present;
+static bool& header_has_rfrom = header_fields[7].present;
+static bool& header_has_to = header_fields[9].present;
+static bool& header_has_cc = header_fields[10].present;
+static bool& header_has_rto = header_fields[13].present;
+static bool& header_has_rcc = header_fields[14].present;
+static bool& header_has_date = header_fields[16].present;
+static bool& header_has_mid = header_fields[17].present;
+static bool& header_has_rdate = header_fields[18].present;
+static bool& header_has_rmid = header_fields[19].present;
+static header_field& header_field_from = header_fields[1];
+static header_field& header_field_mid = header_fields[17];
+static header_field& header_field_rpath = header_fields[3];
+
+static bool use_name_address_style = true;
+static mystring from;
+
+void setup_from()
+{
+ mystring user = getenv("NULLMAILER_USER");
+ if(!user) user = getenv("MAILUSER");
+ if(!user) user = getenv("USER");
+ if(!user) user = getenv("LOGNAME");
+ if(!user) user = "unknown";
+
+ mystring host = getenv("NULLMAILER_HOST");
+ if(!host) host = getenv("MAILHOST");
+ if(!host) host = getenv("HOSTNAME");
+ if(!host) host = defaulthost;
+ canonicalize(host);
+
+ mystring name = getenv("NULLMAILER_NAME");
+ if(!name) name = getenv("MAILNAME");
+ if(!name) name = getenv("NAME");
+
+ if(use_name_address_style) {
+ if(!name) from = "<" + user + "@" + host + ">";
+ else from = name + " <" + user + "@" + host + ">";
+ }
+ else {
+ if(!name) from = user + "@" + host;
+ else from = user + "@" + host + " (" + name + ")";
+ }
+
+ mystring suser = getenv("NULLMAILER_SUSER");
+ if(!suser) suser = user;
+
+ mystring shost = getenv("NULLMAILER_SHOST");
+ if(!shost) shost = host;
+ canonicalize(shost);
+
+ if(!sender)
+ sender = suser + "@" + shost;
+}
+
+bool parse_line(mystring& line)
+{
+ bool valid = false;
+ for(unsigned i = 0; i < line.length(); i++) {
+ char ch = line[i];
+ if(isspace(ch))
+ break;
+ if(ch == ':') {
+ valid = (i > 0);
+ break;
+ }
+ }
+ if(!valid)
+ //bad_hdr(line, "Missing field name.");
+ return false;
+ bool remove = false;
+ for(unsigned i = 0; i < header_field_count; i++) {
+ header_field& h = header_fields[i];
+ if(h.parse(line)) {
+ remove = h.remove;
+ break;
+ }
+ }
+ if(!remove)
+ headers.append(line);
+ return true;
+}
+
+bool is_header(const mystring& line)
+{
+ for(unsigned i = 0; i < line.length(); i++) {
+ char ch = line[i];
+ if(isspace(ch))
+ return false;
+ if(ch == ':')
+ return true;
+ }
+ return false;
+}
+
+bool is_continuation(const mystring& line)
+{
+ return isspace(line[0]);
+}
+
+bool read_header()
+{
+ mystring whole;
+ while(fin.getline(cur_line)) {
+ if(!cur_line)
+ break;
+ if(!!whole && is_continuation(cur_line)) {
+ //if(!whole)
+ //bad_hdr(cur_line, "First line cannot be a continuation line.");
+ //else
+ whole += "\n" + cur_line;
+ }
+ else if(!is_header(cur_line)) {
+ cur_line += '\n';
+ break;
+ }
+ else {
+ if(!!whole)
+ parse_line(whole);
+ whole = cur_line;
+ }
+ }
+ if(!!whole)
+ parse_line(whole);
+ return !header_has_errors;
+}
+
+extern mystring make_messageid();
+extern mystring make_date();
+
+mystring make_recipient_list()
+{
+ mystring result;
+ bool first = true;
+ for(slist::iter iter(recipients); iter; iter++) {
+ if(!first)
+ result = result + ", " + *iter;
+ else
+ result = *iter;
+ first = false;
+ }
+ return result;
+}
+
+bool fix_header()
+{
+ setup_from();
+ if(!header_is_resent) {
+ if(!header_has_date)
+ headers.append("Date: " + make_date());
+ if(!header_has_mid)
+ headers.append("Message-Id: " + make_messageid());
+ if(!header_has_from)
+ headers.append("From: " + from);
+ if(!header_has_to && !header_has_cc && header_add_to &&
+ recipients.count() > 0) {
+ header_has_to = true;
+ headers.append("To: " + make_recipient_list());
+ }
+ }
+ else {
+ if(!header_has_rdate)
+ headers.append("Resent-Date: " + make_date());
+ if(!header_has_rmid)
+ headers.append("Resent-Message-Id: " + make_messageid());
+ if(!header_has_rfrom)
+ headers.append("Resent-From: " + from);
+ if(!header_has_rto && !header_has_rcc && header_add_to &&
+ recipients.count() > 0) {
+ header_has_rto = true;
+ headers.append("Resent-To: " + make_recipient_list());
+ }
+ }
+ if(!header_has_to && !header_has_cc)
+ headers.append("Cc: recipient list not shown: ;");
+ return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Message sending
+///////////////////////////////////////////////////////////////////////////////
+static fdobuf* nqpipe = 0;
+static pid_t pid = 0;
+
+void exec_queue()
+{
+ if(chdir(SBIN_DIR) == -1) {
+ fout << "nullmailer-inject: Could not change directory to " << SBIN_DIR
+ << ": " << strerror(errno) << endl;
+ exit(1);
+ }
+ else
+ execl("nullmailer-queue", "nullmailer-queue", 0);
+ fout << "nullmailer-inject: Could not exec nullmailer-queue: "
+ << strerror(errno) << endl;
+ exit(1);
+}
+
+bool start_queue()
+{
+ int pipe1[2];
+ if(pipe(pipe1) == -1)
+ fail_sys("Could not create pipe to nullmailer-queue");
+ fout.flush();
+ pid = fork();
+ if(pid == -1)
+ fail_sys("Could not fork");
+ if(pid == 0) {
+ close(pipe1[1]);
+ close(0);
+ dup2(pipe1[0], 0);
+ exec_queue();
+ }
+ else {
+ close(pipe1[0]);
+ nqpipe = new fdobuf(pipe1[1], true);
+ }
+ return true;
+}
+
+bool send_env()
+{
+ if(!(*nqpipe << sender << "\n"))
+ fail("Error sending sender to nullmailer-queue.");
+ for(slist::iter iter(recipients); iter; iter++)
+ if(!(*nqpipe << *iter << "\n"))
+ fail("Error sending recipients to nullmailer-queue.");
+ if(!(*nqpipe << endl))
+ fail("Error sending recipients to nullmailer-queue.");
+ return true;
+}
+
+bool send_header()
+{
+ for(slist::iter iter(headers); iter; iter++)
+ if(!(*nqpipe << *iter << "\n"))
+ fail("Error sending header to nullmailer-queue.");
+ if(!(*nqpipe << endl))
+ fail("Error sending header to nullmailer-queue.");
+ return true;
+}
+
+bool send_body()
+{
+ if(!(*nqpipe << cur_line) ||
+ !fdbuf_copy(fin, *nqpipe))
+ fail("Error sending message body to nullmailer-queue.");
+ return true;
+}
+
+bool wait_queue()
+{
+ if(!nqpipe->close())
+ fail("Error closing pipe to nullmailer-queue.");
+ int status;
+ if(waitpid(pid, &status, 0) == -1)
+ fail("Error catching the return value from nullmailer-queue.");
+ if(WIFEXITED(status)) {
+ status = WEXITSTATUS(status);
+ if(status)
+ fail("nullmailer-queue failed.");
+ else
+ return true;
+ }
+ else
+ fail("nullmailer-queue crashed or was killed.");
+}
+
+bool send_message()
+{
+ if(show_message) {
+ nqpipe = &fout;
+ if(show_envelope)
+ send_env();
+ send_header();
+ send_body();
+ return true;
+ }
+ else
+ return start_queue() &&
+ send_env() && send_header() && send_body() &&
+ wait_queue();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Main
+///////////////////////////////////////////////////////////////////////////////
+bool parse_flags()
+{
+ for(const char* flagstr = getenv("NULLMAILER_FLAGS");
+ flagstr && *flagstr; flagstr++) {
+ switch(*flagstr) {
+ case 'c': use_name_address_style=false; break;
+ case 'f': header_field_from.ignore=header_field_from.remove=true; break;
+ case 'i': header_field_mid.ignore=header_field_mid.remove=true; break;
+ case 's': header_field_rpath.ignore=header_field_rpath.remove=true; break;
+ case 't': header_add_to = true; break;
+ default:
+ // Just ignore any flags we can't handle
+ break;
+ }
+ }
+ return true;
+}
+
+bool parse_args(int argc, char* argv[])
+{
+ if(!parse_flags())
+ return false;
+ if(o_from) {
+ mystring list;
+ mystring tmp(o_from);
+ if(!parse_addresses(tmp, list) ||
+ !parse_sender(list)) {
+ fout << "nullmailer-inject: Invalid sender address: " << o_from << endl;
+ return false;
+ }
+ }
+ use_header_recips = (use_recips != use_args);
+ if(use_recips == use_header)
+ return true;
+ if(use_recips == use_either && argc > 0)
+ use_header_recips = false;
+ bool result = true;
+ for(int i = 0; i < argc; i++) {
+ if(!parse_recip_arg(argv[i])) {
+ fout << "Invalid recipient: " << argv[i] << endl;
+ result = false;
+ }
+ }
+ return result;
+}
+
+int cli_main(int argc, char* argv[])
+{
+ read_config();
+ if(!parse_args(argc, argv) ||
+ !read_header() ||
+ !fix_header())
+ return 1;
+ if(recipients.count() == 0) {
+ fout << "No recipients were listed." << endl;
+ return 1;
+ }
+ if(!send_message())
+ return 1;
+ return 0;
+}
diff --git a/src/mailq.cc b/src/mailq.cc
new file mode 100644
index 0000000..505b141
--- /dev/null
+++ b/src/mailq.cc
@@ -0,0 +1,59 @@
+// nullmailer -- a simple relay-only MTA
+// Copyright (C) 1999,2000 Bruce Guenter <bruceg@em.ca>
+//
+// 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
+//
+// You can contact me at <bruceg@em.ca>. There is also a mailing list
+// available to discuss this package. To subscribe, send an email to
+// <nullmailer-subscribe@lists.em.ca>.
+
+#include "config.h"
+#include "defines.h"
+#include "fdbuf/fdbuf.h"
+#include "itoa.h"
+#include <dirent.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <unistd.h>
+
+#define fail(X) do{ fout << X << endl; return 1; }while(0)
+
+int main(int, char*[])
+{
+ if(chdir(QUEUE_MSG_DIR))
+ fail("Cannot change directory to queue.");
+ DIR* dir = opendir(QUEUE_MSG_DIR);
+ if(!dir)
+ fail("Cannot open queue directory.");
+ struct dirent* entry;
+ while((entry = readdir(dir)) != 0) {
+ const char* name = entry->d_name;
+ if(name[0] == '.')
+ continue;
+ time_t time = atoi(name);
+ char timebuf[100];
+ strftime(timebuf, 100, "%Y-%m-%d %H:%M:%S ", localtime(&time));
+ fout << timebuf;
+ struct stat statbuf;
+ if(stat(name, &statbuf) == -1)
+ fout << "?????";
+ else
+ fout << itoa(statbuf.st_size);
+ fout << " bytes" << endl;
+ }
+ closedir(dir);
+ return 0;
+}
diff --git a/src/queue.cc b/src/queue.cc
new file mode 100644
index 0000000..457e498
--- /dev/null
+++ b/src/queue.cc
@@ -0,0 +1,200 @@
+// nullmailer -- a simple relay-only MTA
+// Copyright (C) 1999,2000 Bruce Guenter <bruceg@em.ca>
+//
+// 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
+//
+// You can contact me at <bruceg@em.ca>. There is also a mailing list
+// available to discuss this package. To subscribe, send an email to
+// <nullmailer-subscribe@lists.em.ca>.
+
+#include "config.h"
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <unistd.h>
+#include "itoa.h"
+#include "defines.h"
+#include "mystring/mystring.h"
+#include "fdbuf/fdbuf.h"
+#include "configio.h"
+#include "canonicalize.h"
+#include "hostname.h"
+
+#define fail(MSG) do{ fout << "nullmailer-queue: " << MSG << endl; return false; }while(0)
+
+pid_t pid = getpid();
+uid_t uid = getuid();
+time_t timesecs = time(0);
+mystring adminaddr;
+mystring localhost;
+bool remapadmin = false;
+
+bool is_dir(const char* path)
+{
+ struct stat buf;
+ return !stat(path, &buf) && S_ISDIR(buf.st_mode);
+}
+
+bool is_exist(const char* path)
+{
+ struct stat buf;
+ return !stat(path, &buf);
+}
+
+int fsyncdir(const char* path)
+{
+ int fd = open(path, O_RDONLY);
+ if(fd == -1)
+ return 0;
+ int result = fsync(fd);
+ if(result == -1 && errno != EIO)
+ result = 0;
+ close(fd);
+ return result;
+}
+
+void trigger()
+{
+ int fd = open(QUEUE_TRIGGER, O_WRONLY|O_NONBLOCK, 0666);
+ if(fd == -1)
+ return;
+ char x = 0;
+ write(fd, &x, 1);
+ close(fd);
+}
+
+bool validate_addr(mystring& addr, bool doremap)
+{
+ int i = addr.find_last('@');
+ if(i < 0)
+ return false;
+ mystring hostname = addr.right(i+1);
+ if(doremap && remapadmin) {
+ if(hostname == localhost || hostname == "localhost")
+ addr = adminaddr;
+ }
+ else if(hostname.find_first('.') < 0)
+ return false;
+ return true;
+}
+
+bool copyenv(fdobuf& out)
+{
+ mystring str;
+ if(!fin.getline(str) || !str)
+ fail("Could not read envelope sender.");
+ if(!validate_addr(str, false))
+ fail("Envelope sender address is invalid.");
+ if(!(out << str << endl))
+ fail("Could not write envelope sender.");
+ unsigned count=0;
+ while(fin.getline(str) && !!str) {
+ if(!validate_addr(str, true))
+ fail("Envelope recipient address is invalid.");
+ if(!(out << str << endl))
+ fail("Could not write envelope recipient.");
+ ++count;
+ }
+ if(count == 0)
+ fail("No envelope recipients read.");
+ if(!(out << "\n"))
+ fail("Could not write extra blank line to destination.");
+ return true;
+}
+
+bool makereceived(fdobuf& out)
+{
+ mystring line("Received: (nullmailer pid ");
+ line += itoa(pid);
+ line += " invoked by uid ";
+ line += itoa(uid);
+ line += ");\n\t";
+ char buf[100];
+ if(!strftime(buf, 100, "%a, %d %b %Y %H:%M:%S -0000\n", gmtime(&timesecs)))
+ fail("Error generating a date string.");
+ line += buf;
+ if(!(out << line))
+ fail("Could not write received line to message.");
+ return true;
+}
+
+bool dump(int fd)
+{
+ fdobuf out(fd);
+ if(!copyenv(out))
+ return false;
+ if(!makereceived(out))
+ return false;
+ if(!fdbuf_copy(fin, out))
+ fail("Error copying the message to the queue file.");
+ if(!out.flush())
+ fail("Error flushing the output file.");
+ if(!out.close())
+ fail("Error closing the output file.");
+ return true;
+}
+
+bool deliver()
+{
+ if(!is_dir(QUEUE_MSG_DIR) || !is_dir(QUEUE_TMP_DIR))
+ fail("Installation error: queue directory is invalid.");
+
+ // Notes:
+ // - temporary file name is unique to the currently running
+ // nullmailer-queue program
+ // - destination file name is unique to the system
+ // - if the temporary file previously existed, it did so because
+ // the previous nullmailer-queue process crashed, and it can be
+ // safely overwritten
+ const mystring pidstr = itoa(pid);
+ const mystring timestr = itoa(timesecs);
+ const mystring tmpfile = QUEUE_TMP_DIR + pidstr;
+ const mystring newfile = QUEUE_MSG_DIR + timestr + "." + pidstr;
+
+ int out = open(tmpfile.c_str(), O_CREAT|O_WRONLY|O_TRUNC, 0666);
+ if(out < 0)
+ fail("Could not open temporary file for writing");
+ if(!dump(out)) {
+ unlink(tmpfile.c_str());
+ return false;
+ }
+ if(link(tmpfile.c_str(), newfile.c_str()))
+ fail("Error linking the temp file to the new file.");
+ if(fsyncdir(QUEUE_MSG_DIR))
+ fail("Error syncing the new directory.");
+ if(unlink(tmpfile.c_str()))
+ fail("Error unlinking the temp file.");
+ return true;
+}
+
+mystring defaulthost;
+mystring defaultdomain;
+
+int main(int, char*[])
+{
+ if(config_read("adminaddr", adminaddr) && !!adminaddr) {
+ remapadmin = true;
+ defaulthost = hostname();
+ defaultdomain = domainname();
+ canonicalize(localhost);
+ }
+
+ if(!deliver())
+ return 1;
+ trigger();
+ return 0;
+}
diff --git a/src/send.cc b/src/send.cc
new file mode 100644
index 0000000..9191a67
--- /dev/null
+++ b/src/send.cc
@@ -0,0 +1,316 @@
+// nullmailer -- a simple relay-only MTA
+// Copyright (C) 1999,2000 Bruce Guenter <bruceg@em.ca>
+//
+// 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
+//
+// You can contact me at <bruceg@em.ca>. There is also a mailing list
+// available to discuss this package. To subscribe, send an email to
+// <nullmailer-subscribe@lists.em.ca>.
+
+#include "config.h"
+#include <ctype.h>
+#include <dirent.h>
+#include <errno.h>
+#include <signal.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include "configio.h"
+#include "defines.h"
+#include "errcodes.h"
+#include "fdbuf/fdbuf.h"
+#include "itoa.h"
+#include "list.h"
+
+typedef list<mystring> slist;
+
+#define fail(MSG) do { ferr << MSG << endl; return false; } while(0)
+#define fail_sys(MSG) do{ ferr << MSG << strerror(errno) << endl; return false; }while(0)
+
+struct remote
+{
+ static const mystring default_proto;
+
+ mystring host;
+ mystring proto;
+ slist options;
+ remote(const slist& list);
+ ~remote();
+};
+
+const mystring remote::default_proto = "smtp";
+
+remote::remote(const slist& lst)
+{
+ slist::const_iter iter = lst;
+ host = *iter;
+ ++iter;
+ if(!iter)
+ proto = default_proto;
+ else {
+ proto = *iter;
+ for(++iter; iter; ++iter)
+ options.append(*iter);
+ }
+}
+
+remote::~remote() { }
+
+typedef list<remote> rlist;
+
+unsigned ws_split(const mystring& str, slist& lst)
+{
+ lst.empty();
+ const char* ptr = str.c_str();
+ const char* end = ptr + str.length();
+ unsigned count = 0;
+ for(;;) {
+ while(ptr < end && isspace(*ptr))
+ ++ptr;
+ const char* start = ptr;
+ while(ptr < end && !isspace(*ptr))
+ ++ptr;
+ if(ptr == start)
+ break;
+ lst.append(mystring(start, ptr-start));
+ ++count;
+ }
+ return count;
+}
+
+static rlist remotes;
+static int pausetime = 60;
+
+bool load_remotes()
+{
+ slist rtmp;
+ if(!config_readlist("remotes", rtmp) ||
+ rtmp.count() == 0)
+ return false;
+ remotes.empty();
+ for(slist::const_iter r(rtmp); r; r++) {
+ if((*r)[0] == '#')
+ continue;
+ slist parts;
+ if(!ws_split(*r, parts))
+ continue;
+ remotes.append(remote(parts));
+ }
+ return remotes.count() > 0;
+}
+
+bool load_config()
+{
+ bool result = true;
+
+ if(!load_remotes())
+ result = false;
+
+ if(!config_readint("pausetime", pausetime))
+ pausetime = 60;
+
+ return result;
+}
+
+static slist files;
+static bool reload_files = false;
+
+void catch_alrm(int)
+{
+ signal(SIGALRM, catch_alrm);
+ reload_files = true;
+}
+
+bool load_files()
+{
+ fout << "Rescanning queue." << endl;
+ DIR* dir = opendir(".");
+ if(!dir)
+ fail_sys("Cannot open queue directory: ");
+ files.empty();
+ struct dirent* entry;
+ while((entry = readdir(dir)) != 0) {
+ const char* name = entry->d_name;
+ if(name[0] == '.')
+ continue;
+ files.append(name);
+ }
+ closedir(dir);
+ return true;
+}
+
+void exec_protocol(int fd, remote& remote)
+{
+ if(close(0) == -1 || dup2(fd, 0) == -1 || close(fd) == -1 ||
+ close(1) == -1 || close(2) == -1)
+ return;
+ mystring program = PROTOCOL_DIR + remote.proto;
+ const char* args[3+remote.options.count()];
+ unsigned i = 0;
+ args[i++] = program.c_str();
+ for(slist::const_iter opt(remote.options); opt; opt++)
+ args[i++] = (*opt).c_str();
+ args[i++] = remote.host.c_str();
+ args[i++] = 0;
+ execv(args[0], (char**)args);
+}
+
+#undef fail
+#define fail(MSG) do { fout << MSG << endl; return false; } while(0)
+#define fail2(MSG1,MSG2) do{ fout << MSG1 << MSG2 << endl; return false; }while(0)
+
+bool catchsender(pid_t pid)
+{
+ int status;
+ if(waitpid(pid, &status, 0) == -1)
+ fail("Error catching the child process return value.");
+ else {
+ if(WIFEXITED(status)) {
+ status = WEXITSTATUS(status);
+ if(status)
+ fail2("Sending failed: ", errorstr[status]);
+ else {
+ fout << "Sent file." << endl;
+ return true;
+ }
+ }
+ else
+ fail("Sending process crashed or was killed.");
+ }
+}
+
+bool send_one(mystring filename, remote& remote)
+{
+ int fd = open(filename.c_str(), O_RDONLY);
+ if(fd == -1) {
+ fout << "Can't open file '" << filename << "'" << endl;
+ return false;
+ }
+ fout << "Starting delivery: protocol: " << remote.proto
+ << " host: " << remote.host
+ << " file: " << filename << endl;
+ pid_t pid = fork();
+ switch(pid) {
+ case -1:
+ fail("Fork failed.");
+ case 0:
+ exec_protocol(fd, remote);
+ exit(ERR_EXEC_FAILED);
+ default:
+ close(fd);
+ if(!catchsender(pid))
+ return false;
+ if(unlink(filename.c_str()) == -1)
+ fail("Can't unlink file.");
+ }
+ return true;
+}
+
+bool send_all()
+{
+ if(!load_config())
+ fail("Could not load the config");
+ if(remotes.count() <= 0)
+ fail("No remote hosts listed for delivery");
+ if(files.count() == 0)
+ return true;
+ fout << "Starting delivery, "
+ << itoa(files.count()) << " message(s) in queue." << endl;
+ for(rlist::iter remote(remotes); remote; remote++) {
+ for(slist::iter file(files); file; files.remove(file)) {
+ if(!send_one(*file, *remote))
+ break;
+ }
+ }
+ fout << "Delivery complete, "
+ << itoa(files.count()) << " message(s) remain." << endl;
+ return true;
+}
+
+static int trigger;
+#ifdef NAMEDPIPEBUG
+static int trigger2;
+#endif
+
+bool open_trigger()
+{
+ trigger = open(QUEUE_TRIGGER, O_RDONLY|O_NONBLOCK);
+#ifdef NAMEDPIPEBUG
+ trigger2 = open(QUEUE_TRIGGER, O_WRONLY|O_NONBLOCK);
+#endif
+ if(trigger == -1)
+ fail("Could not open trigger file.");
+ return true;
+}
+
+bool read_trigger()
+{
+ if(trigger != -1) {
+ char buf[1024];
+ read(trigger, buf, sizeof buf);
+#ifdef NAMEDPIPEBUG
+ close(trigger2);
+#endif
+ close(trigger);
+ }
+ return open_trigger();
+}
+
+bool do_select()
+{
+ fd_set readfds;
+ FD_ZERO(&readfds);
+ FD_SET(trigger, &readfds);
+ struct timeval timeout;
+ timeout.tv_sec = pausetime;
+ timeout.tv_usec = 0;
+ int s = select(trigger+1, &readfds, 0, 0,
+ (files.count() == 0) ? 0 : &timeout);
+ if(s == 1) {
+ fout << "Trigger pulled." << endl;
+ read_trigger();
+ reload_files = 1;
+ }
+ else if(s == -1 && errno != EINTR)
+ fail("Internal error in select.");
+ else if(s == 0)
+ reload_files = true;
+ if(reload_files)
+ load_files();
+ return true;
+}
+
+int main(int, char*[])
+{
+ if(!open_trigger())
+ return 1;
+ if(chdir(QUEUE_MSG_DIR) == -1) {
+ fout << "Could not chdir to queue message directory." << endl;
+ return 1;
+ }
+
+ signal(SIGALRM, catch_alrm);
+ signal(SIGHUP, SIG_IGN);
+ load_config();
+ load_files();
+ for(;;) {
+ send_all();
+ do_select();
+ }
+ return 0;
+}
diff --git a/src/sendmail.cc b/src/sendmail.cc
new file mode 100644
index 0000000..9b649bb
--- /dev/null
+++ b/src/sendmail.cc
@@ -0,0 +1,136 @@
+// nullmailer -- a simple relay-only MTA
+// Copyright (C) 1999,2000 Bruce Guenter <bruceg@em.ca>
+//
+// 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
+//
+// You can contact me at <bruceg@em.ca>. There is also a mailing list
+// available to discuss this package. To subscribe, send an email to
+// <nullmailer-subscribe@lists.em.ca>.
+
+#include <config.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "fdbuf/fdbuf.h"
+#include "defines.h"
+#include "cli/cli.h"
+
+const char* cli_program = "sendmail";
+const char* cli_help_prefix = "Nullmailer sendmail emulator\n";
+const char* cli_help_suffix = 0;
+const char* cli_args_usage = "[recipients] <message";
+const int cli_args_min = 0;
+const int cli_args_max = -1;
+
+static int o_dummyi;
+static const char* o_dummys;
+static const char* o_sender = 0;
+static char* o_from;
+static int use_header = false;
+
+cli_option cli_options[] = {
+ { 'B', 0, cli_option::string, 0, &o_dummys, "Ignored", 0 },
+ { 'b', 0, cli_option::string, 0, &o_dummys, "Ignored", 0 },
+ { 'C', 0, cli_option::string, 0, &o_dummys, "Ignored", 0 },
+ { 'd', 0, cli_option::string, 0, &o_dummys, "Ignored", 0 },
+ { 'F', 0, cli_option::string, 0, &o_sender,
+ "Set the full name of the sender", 0 },
+ { 'f', 0, cli_option::string, 0, &o_from,
+ "Set the envelope sender address", 0 },
+ { 'h', 0, cli_option::string, 0, &o_dummys, "Ignored", 0 },
+ { 'i', 0, cli_option::flag, 0, &o_dummyi, "Ignored", 0 },
+ { 'L', 0, cli_option::string, 0, &o_dummys, "Ignored", 0 },
+ { 'N', 0, cli_option::string, 0, &o_dummys, "Ignored", 0 },
+ { 'n', 0, cli_option::flag, 0, &o_dummyi, "Ignored", 0 },
+ { 'O', 0, cli_option::string, 0, &o_dummys, "Ignored", 0 },
+ { 'o', 0, cli_option::string, 0, &o_dummys, "Ignored", 0 },
+ { 'p', 0, cli_option::string, 0, &o_dummys, "Ignored", 0 },
+ { 'q', 0, cli_option::string, 0, &o_dummys, "Ignored", 0 },
+ { 'R', 0, cli_option::string, 0, &o_dummys, "Ignored", 0 },
+ { 'r', 0, cli_option::string, 0, &o_from,
+ "An alternate and obsolete form of the -f flag", 0 },
+ { 't', 0, cli_option::flag, 1, &use_header,
+ "Read message for recipients", 0 },
+ { 'U', 0, cli_option::flag, 0, &o_dummyi, "Ignored", 0 },
+ { 'V', 0, cli_option::string, 0, &o_dummys, "Ignored", 0 },
+ { 'v', 0, cli_option::flag, 0, &o_dummyi, "Ignored", 0 },
+ { 'X', 0, cli_option::string, 0, &o_dummys, "Ignored", 0 },
+ {0}
+};
+
+#ifdef HAVE_SETENV
+// Sometimes we need an explicit declaration.
+extern "C" int setenv(const char*, const char*, int);
+#else
+// This is not really a full emulation of setenv, but close enough
+int setenv(const char* var, const char* val, int overwrite)
+{
+ size_t varlen = strlen(var);
+ size_t vallen = strlen(val);
+ char str[varlen+vallen+2];
+ memcpy(str, var, varlen);
+ str[varlen] = '=';
+ memcpy(str+varlen+1, val, vallen);
+ str[varlen+vallen+1] = 0;
+ return putenv(str);
+}
+#endif
+
+bool setenvelope(char* str)
+{
+ char* at = strchr(str, '@');
+ if(at) {
+ *at = 0;
+ setenv("NULLMAILER_HOST", at+1, 1);
+ }
+ setenv("NULLMAILER_USER", str, 1);
+ return true;
+}
+
+int parseargs()
+{
+ if(o_sender)
+ setenv("NULLMAILER_NAME", o_sender, 1);
+ if(o_from)
+ if(!setenvelope(o_from))
+ return -1;
+ return 0;
+}
+
+int cli_main(int argc, char* argv[])
+{
+ if(chdir(BIN_DIR) == -1) {
+ ferr << "sendmail: Could not change directory to " << BIN_DIR << endl;
+ return 1;
+ }
+
+ if(parseargs() < 0)
+ return 1;
+
+ char* newargv[argc+3];
+ newargv[0] = "nullmailer-inject";
+ int j = 1;
+ if(use_header)
+ newargv[j++] = "-b";
+ else
+ newargv[j++] = "-e";
+ for(int i = 0; i < argc; i++)
+ newargv[j++] = argv[i];
+ newargv[j] = 0;
+
+ execv(newargv[0], newargv);
+ ferr << "sendmail: Could not exec nullmailer-inject." << endl;
+ return 1;
+}
diff --git a/stamp-h.in b/stamp-h.in
new file mode 100644
index 0000000..9788f70
--- /dev/null
+++ b/stamp-h.in
@@ -0,0 +1 @@
+timestamp
diff --git a/test/Makefile.am b/test/Makefile.am
new file mode 100644
index 0000000..6899f8a
--- /dev/null
+++ b/test/Makefile.am
@@ -0,0 +1,24 @@
+noinst_PROGRAMS = address-test
+EXTRA_DIST = address-trace.cc
+
+CXXLINK = $(CC) $(CXXFLAGS) $(LDFLAGS) -o $@
+INCLUDES = -I../lib
+
+address_test_SOURCES = address-test.cc # address-trace.cc
+address_test_LDADD = ../lib/libnullmailer.a
+
+# The following makes sure that we can't produce a package without the
+# tests executing properly
+dist-hook: test
+ cp -r tests $(distdir)
+
+test: all
+ ./address-test
+ @failed=0; \
+ for test in `find tests -type f | fgrep -v CVS`; do \
+ echo Running test $$test...; \
+ if env - SYSCONFDIR=$(sysconfdir)/nullmailer bash $$test; \
+ then echo 'Done.'; \
+ else echo '******************************Failed!******************************'; failed=1; \
+ fi; \
+ done 2>&1; exit $$failed
diff --git a/test/Makefile.in b/test/Makefile.in
new file mode 100644
index 0000000..5dac8f7
--- /dev/null
+++ b/test/Makefile.in
@@ -0,0 +1,294 @@
+# Makefile.in generated automatically by automake 1.4a from Makefile.am
+
+# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DESTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_FLAG =
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+CC = @CC@
+CXX = @CXX@
+MAKEINFO = @MAKEINFO@
+MKDIR = @MKDIR@
+PACKAGE = @PACKAGE@
+RANLIB = @RANLIB@
+RM = @RM@
+STRIP = @STRIP@
+VERSION = @VERSION@
+
+noinst_PROGRAMS = address-test
+EXTRA_DIST = address-trace.cc
+
+CXXLINK = $(CC) $(CXXFLAGS) $(LDFLAGS) -o $@
+INCLUDES = -I../lib
+
+address_test_SOURCES = address-test.cc # address-trace.cc
+address_test_LDADD = ../lib/libnullmailer.a
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = ../config.h
+CONFIG_CLEAN_FILES =
+PROGRAMS = $(noinst_PROGRAMS)
+
+
+DEFS = @DEFS@ -I. -I$(srcdir) -I..
+CPPFLAGS = @CPPFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+address_test_OBJECTS = address-test.o
+address_test_DEPENDENCIES = ../lib/libnullmailer.a
+address_test_LDFLAGS =
+CXXFLAGS = @CXXFLAGS@
+CXXCOMPILE = $(CXX) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+CXXLD = $(CXX)
+DIST_COMMON = Makefile.am Makefile.in
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = gtar
+GZIP_ENV = --best
+SOURCES = $(address_test_SOURCES)
+OBJECTS = $(address_test_OBJECTS)
+
+all: all-redirect
+.SUFFIXES:
+.SUFFIXES: .S .c .cc .o .s
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
+ cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps test/Makefile
+
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ cd $(top_builddir) \
+ && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+
+mostlyclean-noinstPROGRAMS:
+
+clean-noinstPROGRAMS:
+ -test -z "$(noinst_PROGRAMS)" || rm -f $(noinst_PROGRAMS)
+
+distclean-noinstPROGRAMS:
+
+maintainer-clean-noinstPROGRAMS:
+
+.c.o:
+ $(COMPILE) -c $<
+
+.s.o:
+ $(COMPILE) -c $<
+
+.S.o:
+ $(COMPILE) -c $<
+
+mostlyclean-compile:
+ -rm -f *.o core *.core
+
+clean-compile:
+
+distclean-compile:
+ -rm -f *.tab.c
+
+maintainer-clean-compile:
+
+address-test: $(address_test_OBJECTS) $(address_test_DEPENDENCIES)
+ @rm -f address-test
+ $(CXXLINK) $(address_test_LDFLAGS) $(address_test_OBJECTS) $(address_test_LDADD) $(LIBS)
+.cc.o:
+ $(CXXCOMPILE) -c $<
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP)
+ list='$(SOURCES) $(HEADERS)'; \
+ unique=`for i in $$list; do echo $$i; done | \
+ awk ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ here=`pwd` && cd $(srcdir) \
+ && mkid -f$$here/ID $$unique $(LISP)
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS)'; \
+ unique=`for i in $$list; do echo $$i; done | \
+ awk ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
+ || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS)
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+ -rm -f TAGS ID
+
+maintainer-clean-tags:
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = test
+
+distdir: $(DISTFILES)
+ @for file in $(DISTFILES); do \
+ d=$(srcdir); \
+ if test -d $$d/$$file; then \
+ cp -pr $$d/$$file $(distdir)/$$file; \
+ else \
+ test -f $(distdir)/$$file \
+ || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+ || cp -p $$d/$$file $(distdir)/$$file || :; \
+ fi; \
+ done
+ $(MAKE) $(AM_MAKEFLAGS) top_distdir="$(top_distdir)" distdir="$(distdir)" dist-hook
+address-test.o: address-test.cc ../config.h ../lib/canonicalize.h \
+ ../lib/mystring/mystring.h ../lib/mystring/rep.h \
+ ../lib/mystring/iter.h ../lib/mystring/join.h ../lib/address.h \
+ ../lib/fdbuf/fdbuf.h ../lib/fdbuf/fdibuf.h \
+ ../lib/fdbuf/fdobuf.h ../lib/itoa.h
+address-trace.o: address-trace.cc ../lib/address.cc ../config.h \
+ ../lib/canonicalize.h ../lib/mystring/mystring.h \
+ ../lib/mystring/rep.h ../lib/mystring/iter.h \
+ ../lib/mystring/join.h ../lib/list.h ../lib/fdbuf/fdbuf.h \
+ ../lib/fdbuf/fdibuf.h ../lib/fdbuf/fdobuf.h
+
+info-am:
+info: info-am
+dvi-am:
+dvi: dvi-am
+check-am: all-am
+check: check-am
+installcheck-am:
+installcheck: installcheck-am
+install-exec-am:
+install-exec: install-exec-am
+
+install-data-am:
+install-data: install-data-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-am
+uninstall-am:
+uninstall: uninstall-am
+all-am: Makefile $(PROGRAMS)
+all-redirect: all-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_STRIP_FLAG=-s install
+installdirs:
+
+
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -rm -f Makefile $(CONFIG_CLEAN_FILES)
+ -rm -f config.cache config.log stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+mostlyclean-am: mostlyclean-noinstPROGRAMS mostlyclean-compile \
+ mostlyclean-tags mostlyclean-generic
+
+mostlyclean: mostlyclean-am
+
+clean-am: clean-noinstPROGRAMS clean-compile clean-tags clean-generic \
+ mostlyclean-am
+
+clean: clean-am
+
+distclean-am: distclean-noinstPROGRAMS distclean-compile distclean-tags \
+ distclean-generic clean-am
+
+distclean: distclean-am
+
+maintainer-clean-am: maintainer-clean-noinstPROGRAMS \
+ maintainer-clean-compile maintainer-clean-tags \
+ maintainer-clean-generic distclean-am
+ @echo "This command is intended for maintainers to use;"
+ @echo "it deletes files that may require special tools to rebuild."
+
+maintainer-clean: maintainer-clean-am
+
+.PHONY: mostlyclean-noinstPROGRAMS distclean-noinstPROGRAMS \
+clean-noinstPROGRAMS maintainer-clean-noinstPROGRAMS \
+mostlyclean-compile distclean-compile clean-compile \
+maintainer-clean-compile tags mostlyclean-tags distclean-tags \
+clean-tags maintainer-clean-tags distdir info-am info dvi-am dvi check \
+check-am installcheck-am installcheck install-exec-am install-exec \
+install-data-am install-data install-am install uninstall-am uninstall \
+all-redirect all-am all installdirs mostlyclean-generic \
+distclean-generic clean-generic maintainer-clean-generic clean \
+mostlyclean distclean maintainer-clean
+
+
+# The following makes sure that we can't produce a package without the
+# tests executing properly
+dist-hook: test
+ cp -r tests $(distdir)
+
+test: all
+ ./address-test
+ @failed=0; \
+ for test in `find tests -type f | fgrep -v CVS`; do \
+ echo Running test $$test...; \
+ if env - SYSCONFDIR=$(sysconfdir)/nullmailer bash $$test; \
+ then echo 'Done.'; \
+ else echo '******************************Failed!******************************'; failed=1; \
+ fi; \
+ done 2>&1; exit $$failed
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/test/address-test.cc b/test/address-test.cc
new file mode 100644
index 0000000..3760817
--- /dev/null
+++ b/test/address-test.cc
@@ -0,0 +1,182 @@
+#include "config.h"
+#include <ctype.h>
+#include "canonicalize.h"
+#include "mystring/mystring.h"
+#include "address.h"
+
+#include "fdbuf/fdbuf.h"
+#include "itoa.h"
+
+static bool test(const mystring& in,
+ const mystring& out,
+ const mystring& list)
+{
+ mystring line = in;
+ mystring tmplist;
+ if(!parse_addresses(line, tmplist)) {
+ fout << "Parsing of '" << in << "' failed." << endl;
+ return false;
+ }
+ bool status = true;
+ if(!!list && tmplist != list) {
+ fout << "Parsing of '" << in << "' failed: bad result list, was:\n"
+ << tmplist
+ << "should be:\n"
+ << list;
+ status = false;
+ }
+ if(!!out && line != out) {
+ fout << "Parsing of '" << in << "' failed: bad result string, was:\n"
+ << line
+ << "should be:\n"
+ << out;
+ status = false;
+ }
+ return status;
+}
+
+#define TEST(X,Y,Z) do{ ++count; if(!test(X,Y,Z)) ++failed; }while(0)
+
+mystring defaulthost = "a";
+mystring defaultdomain = "b.c";
+
+int main()
+{
+ int count = 0;
+ int failed = 0;
+ // periods in local
+ TEST("a.b@c.d",
+ "a.b@c.d",
+ "a.b@c.d\n");
+ // quoted local
+ TEST("\"e\"@c.d",
+ "e@c.d",
+ "e@c.d\n");
+ // missing host and domain
+ TEST("e",
+ "e@a.b.c",
+ "e@a.b.c\n");
+ // missing domain
+ TEST("e@x",
+ "e@x.b.c",
+ "e@x.b.c\n");
+ // trailing period
+ TEST("e@c.d.",
+ "e@c.d",
+ "e@c.d\n");
+ // comment <address> style
+ TEST("x<y@a.b>",
+ "x <y@a.b>",
+ "y@a.b\n");
+ TEST("<y@a.b>",
+ "<y@a.b>",
+ "y@a.b\n");
+ // address (comment) style
+ TEST("y@a.b(x)",
+ "y@a.b (x)",
+ "y@a.b\n");
+ // internal comments before local
+ TEST("(j)y@a.b",
+ "y@a.b (j)",
+ "y@a.b\n");
+ // internal comments after local
+ TEST("y(j)@a.b",
+ "y@a.b (j)",
+ "y@a.b\n");
+ // internal comments before domain
+ TEST("y@(j)a.b",
+ "y@a.b (j)",
+ "y@a.b\n");
+ // internal comments before period
+ TEST("y@a(j).b",
+ "y@a.b (j)",
+ "y@a.b\n");
+ // internal comments after period
+ TEST("y@a.(j)b",
+ "y@a.b (j)",
+ "y@a.b\n");
+ // normal list
+ TEST("a@b.c,d@e.f",
+ "a@b.c, d@e.f",
+ "a@b.c\nd@e.f\n");
+ // list with comments
+ TEST("a@b.c(j),d@e.f(k)",
+ "a@b.c (j), d@e.f (k)",
+ "a@b.c\nd@e.f\n");
+ // list without commas
+ TEST("a@b.c d@e.f",
+ "a@b.c, d@e.f",
+ "a@b.c\nd@e.f\n");
+ // list without commas with comments
+ TEST("a@b.c(j) d@e.f(k)",
+ "a@b.c (j), d@e.f (k)",
+ "a@b.c\nd@e.f\n");
+ // simple group
+ TEST("g: a@b.c, d@e.f;",
+ "g: a@b.c, d@e.f;",
+ "a@b.c\nd@e.f\n");
+ // group with spaces in name
+ TEST("g h: a@b.c, d@e.f;",
+ "g h: a@b.c, d@e.f;",
+ "a@b.c\nd@e.f\n");
+ // empty group
+ TEST("g: ;",
+ "g: ;",
+ "");
+ // group with a comment
+ TEST("g: a@b.c(j);",
+ "g: a@b.c (j);",
+ "a@b.c\n");
+ // group with comments
+ TEST("g:a@b.c(j),d@e.f(k);",
+ "g: a@b.c (j), d@e.f (k);",
+ "a@b.c\nd@e.f\n");
+ // group with no commas
+ TEST("g:a@b.c d@e.f;",
+ "g: a@b.c, d@e.f;",
+ "a@b.c\nd@e.f\n");
+ // group with route addresses
+ TEST("g:foo<a@b.c>;",
+ "g: foo <a@b.c>;",
+ "a@b.c\n");
+ // route-path syntax (stripped)
+ TEST("f<@g.h:a@b.c>",
+ "f <a@b.c>",
+ "a@b.c\n");
+ // multiple route-path syntax
+ TEST("f<@g.h@i.j:a@b.c>",
+ "f <a@b.c>",
+ "a@b.c\n");
+ // comments with quoted brackets
+ TEST("(f\\)\\()a@b.c",
+ "a@b.c (f\\)\\()",
+ "a@b.c\n");
+ // nested comments
+ TEST("(f(g)h)a@b.c",
+ "a@b.c (f(g)h)",
+ "a@b.c\n");
+ // simple quoted addresses
+ TEST("\"a\"@b.c",
+ "a@b.c",
+ "a@b.c\n");
+ // quoted parts of address
+ TEST("a.\"b\".c@d.e",
+ "a.b.c@d.e",
+ "a.b.c@d.e\n");
+ // escaped characters within quotes
+ TEST("\"s\\'b\"@d.e",
+ "s'b@d.e",
+ "s'b@d.e\n");
+ // escaped specials
+ TEST("\"s\\\"a\\\"b\"@d.e",
+ "\"s\\\"a\\\"b\"@d.e",
+ "s\"a\"b@d.e\n");
+ // twisted syntax
+ //TEST("\"\\\"d\\\" <\"<@_._:e@f.g>",
+ // "who knows",
+ // "e@f.g\n");
+
+ fout << itoa(count) << " tests run, ";
+ fout << itoa(failed) << " failed." << endl;
+ return failed;
+}
diff --git a/test/address-trace.cc b/test/address-trace.cc
new file mode 100644
index 0000000..f9957db
--- /dev/null
+++ b/test/address-trace.cc
@@ -0,0 +1,2 @@
+#define TRACE
+#include "address.cc"
diff --git a/test/tests/CVS/Entries b/test/tests/CVS/Entries
new file mode 100644
index 0000000..bd5c58c
--- /dev/null
+++ b/test/tests/CVS/Entries
@@ -0,0 +1,3 @@
+/protocols/1.1/Wed Feb 16 18:24:38 2000//
+D/inject////
+D/queue////
diff --git a/test/tests/CVS/Repository b/test/tests/CVS/Repository
new file mode 100644
index 0000000..c57efaa
--- /dev/null
+++ b/test/tests/CVS/Repository
@@ -0,0 +1 @@
+nullmailer/test/tests
diff --git a/test/tests/CVS/Root b/test/tests/CVS/Root
new file mode 100644
index 0000000..a644f54
--- /dev/null
+++ b/test/tests/CVS/Root
@@ -0,0 +1 @@
+/CVS
diff --git a/test/tests/inject/CVS/Entries b/test/tests/inject/CVS/Entries
new file mode 100644
index 0000000..435fbdb
--- /dev/null
+++ b/test/tests/inject/CVS/Entries
@@ -0,0 +1,8 @@
+/bad-headers/1.1/Wed Feb 16 18:24:41 2000//
+/date/1.1/Wed Feb 16 18:24:41 2000//
+/from/1.1/Wed Feb 16 18:24:41 2000//
+/message-id/1.1/Wed Feb 16 18:24:41 2000//
+/recips/1.1/Wed Feb 16 18:24:41 2000//
+/return-path/1.1/Wed Feb 16 18:24:41 2000//
+/sender/1.1/Wed Feb 16 18:24:41 2000//
+D
diff --git a/test/tests/inject/CVS/Repository b/test/tests/inject/CVS/Repository
new file mode 100644
index 0000000..fcad062
--- /dev/null
+++ b/test/tests/inject/CVS/Repository
@@ -0,0 +1 @@
+nullmailer/test/tests/inject
diff --git a/test/tests/inject/CVS/Root b/test/tests/inject/CVS/Root
new file mode 100644
index 0000000..a644f54
--- /dev/null
+++ b/test/tests/inject/CVS/Root
@@ -0,0 +1 @@
+/CVS
diff --git a/test/tests/inject/bad-headers b/test/tests/inject/bad-headers
new file mode 100644
index 0000000..c65d5a7
--- /dev/null
+++ b/test/tests/inject/bad-headers
@@ -0,0 +1,15 @@
+. functions
+
+injtest() { echo "$@" | not inject >/dev/null }
+
+echo "Checking that inject rejects leading continuation lines."
+injtest " foo..."
+
+echo "Checking that inject rejects malformed RFC headers."
+injtest "foo : bar"
+injtest ":foo bar"
+injtest "foo"
+
+echo "Checking that inject rejects bad addresses."
+injtest "from: foo<bar"
+
diff --git a/test/tests/inject/copy b/test/tests/inject/copy
new file mode 100644
index 0000000..9e99c85
--- /dev/null
+++ b/test/tests/inject/copy
@@ -0,0 +1,19 @@
+. functions
+
+tst() {
+ {
+ echo "To: bruceg@em.ca"
+ echo
+ dd if=/dev/urandom bs=1k count=$1 2>/dev/null | uuencode data
+ } >testmessage.in
+ inject -n <testmessage.in | \
+ sed -e '/^Message-Id:/d' -e '/^Date:/d' -e '/^From:/d' >testmessage.out
+ cmp testmessage.in testmessage.out
+}
+
+for k in 1 2 4 8 10 20 40 80 100; do
+ echo "Testing inject with ${k}KB of uuencoded data"
+ tst $k
+done
+
+rm -f testmessage.{in,out}
diff --git a/test/tests/inject/date b/test/tests/inject/date
new file mode 100644
index 0000000..5925ab4
--- /dev/null
+++ b/test/tests/inject/date
@@ -0,0 +1,12 @@
+. functions
+
+inj() { injectfield date 'to: nobody' "$@" }
+
+echo "Checking that inject inserts a date line."
+test -n "`inj`"
+
+echo "Checking that inject preserves an existing date line."
+inj "date: foo" | grep '^ foo$' >/dev/null
+
+echo "Checking that inject does not add more date lines."
+test 1 -eq `inj "date: foo" | wc -l`
diff --git a/test/tests/inject/from b/test/tests/inject/from
new file mode 100644
index 0000000..92dfdd2
--- /dev/null
+++ b/test/tests/inject/from
@@ -0,0 +1,66 @@
+. functions
+
+inj() { injectfield from 'to: nobody' "$@" }
+testvar() {
+ set -e
+ echo "Checking that inject obeys $1."
+ export $1="$2"
+ inj | grep -q "$3"
+}
+
+echo "Checking that inject inserts a from line."
+test -n "`inj`"
+
+echo "Checking that inject preserves an existing from line."
+inj "from: a@b.c" | grep -q '^ a@b\.c$'
+
+echo "Checking that inject does not add more from lines."
+test 1 -eq `inj "from: a@b.c" | wc -l`
+
+echo "Checking that inject will strip from lines."
+export NULLMAILER_FLAGS=f
+inj "from: a@b.c" | not grep -q '^ a@b\.c$'
+unset NULLMAILER_FLAGS
+
+echo "Checking that inject obeys hostname()"
+hostname=`hostname`
+inj | grep -q "@$hostname>$"
+
+echo "Checking that inject obeys config/defaulthost"
+echo test.org >$SYSCONFDIR/defaulthost
+inj | grep -q '@test.org>$'
+
+echo "Checking that inject obeys config/defaultdomain"
+echo test >$SYSCONFDIR/defaulthost
+echo domain.org >$SYSCONFDIR/defaultdomain
+inj | grep -q '@test.domain.org>$'
+
+testvar HOSTNAME test1.org '@test1.org>$'
+
+testvar MAILHOST test2.org '@test2.org>$'
+
+testvar NULLMAILER_HOST test3.org '@test3.org>$'
+
+echo "Checking that inject uses 'unknown'"
+inj | grep -q ' <unknown@'
+
+testvar LOGNAME name1 ' <name1@'
+
+testvar USER name2 ' <name2@'
+
+testvar MAILUSER name3 ' <name3@'
+
+testvar NULLMAILER_USER name4 ' <name4@'
+
+echo "Checking that inject uses a blank name."
+inj | grep -q '^ <'
+
+testvar NAME full1 '^ full1 <'
+
+testvar MAILNAME full2 '^ full2 <'
+
+testvar NULLMAILER_NAME full3 '^ full3 <'
+
+echo "Checking that inject will use address-comment form."
+export NULLMAILER_FLAGS=c
+inj | grep -q '^ name4@test3.org (full3)$'
diff --git a/test/tests/inject/headers b/test/tests/inject/headers
new file mode 100644
index 0000000..7c052b8
--- /dev/null
+++ b/test/tests/inject/headers
@@ -0,0 +1,22 @@
+. functions
+
+tst() {
+ injectlines "$@" | \
+ sed -e '/^Message-Id:/d' -e '/^Date:/d' -e '/^From:/d' >testmessage.out
+ cmp testmessage.in testmessage.out
+}
+
+cat <<EOF >testmessage.in
+To: bruceg@em.ca
+
+data
+done
+EOF
+
+echo Testing header seperation with a blank line
+tst 'To: bruceg@em.ca' '' 'data' 'done'
+
+echo Testing header seperation without a blank line
+tst 'To: bruceg@em.ca' 'data' 'done'
+
+rm -f testmessage.{in,out}
diff --git a/test/tests/inject/message-id b/test/tests/inject/message-id
new file mode 100644
index 0000000..d0f6d62
--- /dev/null
+++ b/test/tests/inject/message-id
@@ -0,0 +1,24 @@
+. functions
+
+inj() { injectfield message-id 'to: n' "$@" }
+
+echo "Checking that inject inserts a message-id."
+test -n "`inj`"
+
+echo "Checking that inject preserves an existing message-id."
+inj "Message-Id: <mid@mid>" | grep -q '^ <mid@mid>$'
+
+echo "Checking that inject does not add more message-ids."
+test 1 -eq `inj "Message-Id: <mid@mid>" | wc -l`
+
+echo "Checking that inject will ignore an existing message-id."
+export NULLMAILER_FLAGS=i
+inj "Message-Id: <mid@mid>" | not grep -q '^ <mid@mid>$'
+
+echo "Checking that inject obeys hostname()"
+hostname=`hostname`
+inj | grep -q "@$hostname>$"
+
+echo "Checking that inject obeys config/idhost"
+echo test1.org >$SYSCONFDIR/idhost
+inj | grep -q '@test1.org>$'
diff --git a/test/tests/inject/recips b/test/tests/inject/recips
new file mode 100644
index 0000000..c0d3f11
--- /dev/null
+++ b/test/tests/inject/recips
@@ -0,0 +1,50 @@
+. functions
+
+inj() { inject -n -v "$@" | tail +2 | sed '/^$/,$d' }
+inj-find() { echo to: a@b.c | inj "$1" d@e.f | grep -q "$2" }
+inj-notfind() { echo to: a@b.c | inj "$1" d@e.f | not grep -q "$2" }
+
+hdrline='^a@b.c$'
+cmdline='^d@e.f$'
+
+echo "Checking that inject uses command line with -a."
+inj-find -a $cmdline
+
+echo "Checking that inject ignores header lines with -a."
+inj-notfind -a $hdrline
+
+echo "Checking that inject uses command line with -b."
+inj-find -b $cmdline
+
+echo "Checking that inject uses header lines with -b."
+inj-find -b $hdrline
+
+echo "Checking that inject ignores command line with -h."
+inj-notfind -h $cmdline
+
+echo "Checking that inject uses header lines with -h."
+inj-find -h $hdrline
+
+echo "Checking that inject uses command line with -e and no header."
+echo | inj -e d@e.f | grep -q $cmdline
+
+echo "Checking that inject uses command line with -e and header."
+inj-find -e $cmdline
+
+echo "Checking that inject uses header with -e and no command line."
+echo to: a@b.c | inj -e | grep -q $hdrline
+
+echo "Checking that inject ignores header with -e and command line."
+inj-notfind -e $hdrline
+
+echo "Checking that inject uses command line with no header by default."
+echo | inj -e d@e.f | grep -q $cmdline
+
+echo "Checking that inject uses command line with header by default."
+inj-find -e $cmdline
+
+echo "Checking that inject uses header with no command line by default."
+echo to: a@b.c | inj -e | grep -q $hdrline
+
+echo "Checking that inject ignores header with command line by default."
+inj-notfind -e $hdrline
diff --git a/test/tests/inject/return-path b/test/tests/inject/return-path
new file mode 100644
index 0000000..280838a
--- /dev/null
+++ b/test/tests/inject/return-path
@@ -0,0 +1,9 @@
+. functions
+
+inj() { injectfield return-path 'to: n' "$@" }
+
+echo "Checking that inject does not inserts a return-path."
+test -z "`inj`"
+
+echo "Checking that inject strips return-paths."
+test -z "`inj return-path: blah`"
diff --git a/test/tests/inject/sender b/test/tests/inject/sender
new file mode 100644
index 0000000..e624e27
--- /dev/null
+++ b/test/tests/inject/sender
@@ -0,0 +1,76 @@
+. functions
+
+inj() { inject -n -v a </dev/null | head -1 }
+testvar() {
+ set -e
+ echo "Checking that inject obeys $1."
+ export $1="$2"
+ inj | grep -q "$3"
+}
+testcanon() {
+ set -e
+ echo "Checking that inject canonicalizes $1."
+ export $1="$2"
+ inj | grep -q "$3"
+}
+testhdr() {
+ set -e
+ echo "Checking that inject $1 $2:"
+ echo $2: $3 | inject -n -v a | head -1 | grep -q "$4"
+}
+testign() { testhdr ignores "$@" }
+testset() { testhdr uses "$@" }
+
+echo "Checking that inject obeys hostname()"
+hostname=`hostname`
+domainname=`hostname -d`
+inj | grep -q "@$hostname$"
+
+echo "Checking that inject obeys config/defaulthost"
+echo test.org >$SYSCONFDIR/defaulthost
+inj | grep -q '@test.org$'
+
+echo "Checking that inject obeys domainname()"
+echo test >$SYSCONFDIR/defaulthost
+rm -f $SYSCONFDIR/defaultdomain
+inj | grep -q "@test.$domainname$"
+
+echo "Checking that inject obeys config/defaultdomain"
+echo test >$SYSCONFDIR/defaulthost
+echo domain.org >$SYSCONFDIR/defaultdomain
+inj | grep -q '@test.domain.org$'
+
+testvar HOSTNAME test1.org '@test1.org$'
+
+testcanon HOSTNAME test1 '@test1.domain.org$'
+
+testvar MAILHOST test2.org '@test2.org$'
+
+testcanon MAILHOST test2 '@test2.domain.org$'
+
+testvar NULLMAILER_HOST test3.org '@test3.org$'
+
+testcanon NULLMAILER_HOST test3 '@test3.domain.org$'
+
+echo "Checking that inject uses 'unknown'"
+inj | grep -q '^unknown@'
+
+testvar LOGNAME name1 '^name1@'
+
+testvar USER name2 '^name2@'
+
+testvar MAILUSER name3 '^name3@'
+
+testvar NULLMAILER_USER name4 '^name4@'
+
+testign Errors-To a@b.c '^name4@test3'
+testign From a@b.c '^name4@test3'
+testign Reply-To a@b.c '^name4@test3'
+testign Resent-From a@b.c '^name4@test3'
+testign Resent-Reply-To a@b.c '^name4@test3'
+testign Resent-Sender a@b.c '^name4@test3'
+testign Return-Receipt-To a@b.c '^name4@test3'
+testign Sender a@b.c '^name4@test3'
+testset Return-Path name0@host0.org '^name0@host0.org$'
+export NULLMAILER_FLAGS=s
+testign Return-Path name0@host0.org '^name4@test3'
diff --git a/test/tests/protocols b/test/tests/protocols
new file mode 100644
index 0000000..f9d00e7
--- /dev/null
+++ b/test/tests/protocols
@@ -0,0 +1,44 @@
+. functions
+
+rm -f testmail
+cat >testmail <<EOF
+bruceg@em.ca
+bruceg@em.ca
+
+From: <bruceg@em.ca>
+To: <bruceg@em.ca>
+Subject: Nullmailer automated test message
+
+Just testing, please ignore
+EOF
+
+for p in smtp qmqp
+do
+ echo "Testing host not found error with $p."
+ error 2 protocol $p this.host.can.not.exist <testmail
+
+ echo "Testing connection refused error with $p."
+ error 7 protocol $p -p 24680 localhost <testmail
+
+ echo "Testing usage error with $p (zero args)."
+ error 1 protocol $p <testmail
+
+ echo "Testing usage error with $p (two args)."
+ error 1 protocol $p localhost foobar <testmail
+
+ echo "Testing usage error with $p (unknown option)."
+ error 1 protocol $p -x localhost <testmail
+
+ echo "Testing usage error with $p (invalid integer)."
+ error 1 protocol $p -p foo localhost <testmail
+
+ tcpserver 0 24680 date & job=$!
+ sleep 1
+ trap "kill $job" EXIT
+ echo "Testing protocol failure with $p."
+ error 11 protocol $p -p 24680 localhost <testmail
+ kill $job
+ trap - EXIT
+done
+
+rm -f testmail
diff --git a/test/tests/queue/CVS/Entries b/test/tests/queue/CVS/Entries
new file mode 100644
index 0000000..0ade2cc
--- /dev/null
+++ b/test/tests/queue/CVS/Entries
@@ -0,0 +1,2 @@
+/rewrite/1.1/Wed Feb 16 18:24:45 2000//
+D
diff --git a/test/tests/queue/CVS/Repository b/test/tests/queue/CVS/Repository
new file mode 100644
index 0000000..a6ff493
--- /dev/null
+++ b/test/tests/queue/CVS/Repository
@@ -0,0 +1 @@
+nullmailer/test/tests/queue
diff --git a/test/tests/queue/CVS/Root b/test/tests/queue/CVS/Root
new file mode 100644
index 0000000..a644f54
--- /dev/null
+++ b/test/tests/queue/CVS/Root
@@ -0,0 +1 @@
+/CVS
diff --git a/test/tests/queue/rewrite b/test/tests/queue/rewrite
new file mode 100644
index 0000000..a7a0575
--- /dev/null
+++ b/test/tests/queue/rewrite
@@ -0,0 +1,45 @@
+. functions
+
+que() {
+ set -e
+ ../src/nullmailer-queue && \
+ cat /tmp/nm/var/nullmailer/queue/* && \
+ rm -f /tmp/nm/var/nullmailer/queue/*
+}
+que-recip() {
+ set -e
+ que | sed -e '2,2!d' | grep -q "$@"
+}
+
+echo admin@remote >/tmp/nm/etc/nullmailer/adminaddr
+
+echo "Checking that queue rewrites user@localhost to adminaddr."
+que-recip -q '^admin@remote$' <<EOF
+bruceg@qcc.sk.ca
+user@localhost
+
+header
+
+data
+EOF
+
+echo "Checking that queue rewrites user@hostname to adminaddr."
+hostname=`hostname -f`
+que-recip -q '^admin@remote$' <<EOF
+bruceg@qcc.sk.ca
+user@$hostname
+
+header
+
+data
+EOF
+
+echo "Checking that queue does not rewrite non-local users."
+que-recip -q '^user@nowhere.org$' <<EOF
+bruceg@qcc.sk.ca
+user@nowhere.org
+
+header
+
+data
+EOF