diff options
153 files changed, 15585 insertions, 0 deletions
@@ -0,0 +1 @@ +Bruce Guenter <bruceg@em.ca> @@ -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! @@ -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. + @@ -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/ @@ -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: @@ -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 +------------------------------------------------------------------------------- @@ -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. @@ -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; +} @@ -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(×ecs))) + 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 |